/*
 * The Presence app, live. JOB-14, 26 September 2026.
 *
 * Muse's stylesheet (muse.css) is the design and is never edited by hand: it
 * is re-imported from Drive whenever Muse changes the mockup. This file holds
 * only what a live product needs that a mockup did not: the sign in card,
 * a locked mode, the voice pill in Mentor and Leader, a thinking state, and
 * the orb following a real voice.
 *
 * It writes no colour of its own. Every colour is one of Muse's variables,
 * so a mode change or a re-import restyles this file with the rest.
 */

/* The stage must not scroll. Muse gave it overflow:hidden, which still makes
   it a scroll container, and the chat panel waits off canvas to the right, so
   focusing a control (a tap, or Tab on a keyboard) could scroll the whole
   stage sideways by 42px and show the panel's edge. Seen at 375px wide on 26
   September 2026. clip hides the same overflow without being scrollable. */
.stage { overflow: clip; }

/* Presence: ONLY THE AURORA MOVES. Sheldon, 26 September 2026: "everything
   is moving, almost like a water effect". Two layers did it. The water layer
   ran the lake through an SVG turbulence ripple, and the sky layer slid a
   second copy of the photograph up to 2% under a soft edged mask, which
   ghosts the treeline and mountains wherever the mask's blur reaches them.
   The handoff's own ripple rule says drop the water if it moves anything
   outside the aurora, so it is gone. The aurora now glows in place: the copy
   stays exactly over the photograph and only its light and colour pulse,
   inside the mask. Nothing can shift position, so nothing but the aurora
   can appear to move. */
/* Strict masks: Muse's aurora shapes, cut to zero below a skyline drawn
   above each photo's trees and peaks (scripts/presence-skylines.mjs). Zero
   means the animated layer adds nothing there, so terrain is pixel still. */
/* (Superseded 27 September 2026 by the traced masks in THE AURORA, v2 below.) */

.scene .water-motion,
.scene.has-water .water-motion { display: none !important; animation: none !important; filter: none !important; }
/* Smoothness, the second brief the same evening: "all animations on the
   desktop look very choppy". Every animation below touches only opacity and
   transform, which the compositor runs without repainting. The colour lift
   is a STATIC filter, painted once when the layer is built; the pulse is the
   layer's opacity alone. Muse's version animated background-position and
   filter on a 1280 by 1920 masked copy of the photograph, a full repaint of
   the largest thing on screen every frame. */
/* THE AURORA, v2. 27 September 2026, the presence definitive brief v2,
   which supersedes v1's generated light: "A separate layer of generated
   light will always read as a separate layer. Kill it." It slid in front of
   Strategist's trees, the straight cut sliced Mentor's cabin, and Leader
   showed artifacts.

   A cinemagraph instead: the photograph's OWN sky moves.

   Layer 1 is the photograph, untouched: Muse's plain <img>, no filter, no
   transform, no animation.

   Layer 2 is the same photograph's sky, clipped by a mask traced from that
   photo's own silhouette (scripts/presence-skymask.mjs: every tree tip,
   ridge, the cabin's hills; feathered 2px, pulled 3px into the sky), and
   drifted a few pixels sideways, slowly, back and forth. No blur, no glow,
   no scale, no blend mode: the moving pixels are the photo's aurora, so it
   reads as the aurora moving. The mask stays put on the layer; only the
   picture inside it moves, by transform, which the compositor runs without
   repainting. Below the mask edge nothing is drawn, so trees, mountains,
   the cabin, snow and water are the original pixels on every frame. */
/* Coach and Strategist trade scenes, Sheldon 1 October 2026: each traced mask
   follows its photograph. scripts/presence-scenes.mjs. */
.scene.coach { --sky-mask: url('/presence/img/sky-strategist-traced.png') !important; }
.scene.strategist { --sky-mask: url('/presence/img/sky-coach-traced.png') !important; }
.scene.mentor { --sky-mask: url('/presence/img/sky-mentor-traced.png') !important; }
.scene.leader { --sky-mask: url('/presence/img/sky-leader-traced.png') !important; }
.scene .sky-motion {
  background-image: none !important;
  animation: none !important;
  filter: none !important;
  mix-blend-mode: normal;
  overflow: hidden;
}
.scene .sky-motion::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--scene-photo);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  will-change: transform;
  pointer-events: none;
  animation: sky-drift 26s ease-in-out infinite alternate;
}
.scene .sky-motion::after { content: none; }
@keyframes sky-drift {
  from { transform: translate3d(-6px, 0, 0); }
  to { transform: translate3d(6px, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .scene .sky-motion::before { animation: none; transform: none; }
}

/* Nothing animates off screen. Four scenes each carried a running aurora
   layer and the hidden view kept its orb spinning, all composited every
   frame for nobody. */
.scene:not(.is-active) .sky-motion::before,
.scene:not(.is-active) .sky-motion::after,
.presence-view:not(.is-active) .sky-motion::before,
.presence-view:not(.is-active) .sky-motion::after,
.orb-view:not(.is-active),
.orb-view:not(.is-active)::before,
.orb-view:not(.is-active) *,
.orb-view:not(.is-active) *::before,
.orb-view:not(.is-active) *::after { animation-play-state: paused !important; }

/* The Orb view's own motion, the same rule. Muse's keyframes animated a 45px
   blur on a layer larger than the screen, a brightness filter on the orb,
   and a border colour on the ring: three repaints a frame. Redefined here by
   name, so her selectors and timings stand and only the properties change.
   A later @keyframes of the same name replaces the earlier one. */
.orb-view::before { filter: blur(40px); will-change: transform; }
@keyframes aurora-drift { to { transform: translate3d(3%, -2%, 0) scale(1.06); } }
@keyframes orb-breathe { 50% { transform: scale(1.035); } }
@keyframes orb-speak { to { transform: scale(1.065); } }
@keyframes ring-listen { 50% { transform: scale(1.11); opacity: 0.65; } }
.orb-core, .orb-ring, .orb-halo { will-change: transform; }

/* The orb breathes with whoever is speaking. main.ts sets the orb's own
   `scale` from the real microphone or playback level, and only when it
   changes: a variable on the stage restyled the whole page every frame. */
.orb-core { transition: scale 90ms linear; }

/* Thinking: the ring turns slowly while the answer is being written. */
.orb-view.is-thinking .orb-ring {
  animation: ring-listen 2.6s ease-in-out infinite;
  opacity: 0.8;
}

/* A mode this plan does not open stays visible, and reads as closed. */
.mode-btn.is-locked { opacity: 0.46; }
.mode-btn.is-locked::after {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-left: 6px;
  vertical-align: middle;
  border: 1px solid currentColor;
  border-radius: 1px;
}

/* Mentor and Leader: the model pill and the voice pill are a pair, the same
   size, side by side, mirrored around the point where Muse placed the model
   pill at every breakpoint. Sheldon, 26 September 2026: the voice pill sat
   stacked underneath at a different size. */
.stage.has-voice-pill > .model-picker {
  box-sizing: border-box;
  width: 15em;
  min-width: 0;
  white-space: nowrap;
  justify-content: center;
}
.stage.has-voice-pill > .model-picker:not(.voice-picker) { transform: translateX(calc(-100% - 5px)); }
.stage.has-voice-pill > .voice-picker { transform: translateX(5px); }
.voice-picker::before { background: var(--mode-2); box-shadow: 0 0 9px var(--mode-2); }

/* A pending answer in the chat panel. */
.bubble.is-pending { opacity: 0.6; }

/* Sign in. A card on the stage, in the chat panel's own material. */
.signin {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 16px;
  background: var(--shadow);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.signin-card {
  width: min(380px, 100%);
  padding: 28px 24px 22px;
  border: 1px solid var(--line);
  border-radius: 24px;
  background: var(--panel-strong);
  color: var(--ink);
  text-align: center;
  font-family: "Poppins", sans-serif;
}
.signin-card h2 {
  margin: 0 0 10px;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.signin-card p {
  margin: 0 0 18px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}
#googleButton { display: flex; justify-content: center; min-height: 44px; margin-bottom: 12px; }
.signin-card .signin-note { min-height: 1.5em; margin: 0 0 8px; }
.signin-close {
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .orb-view.is-listening .orb-core,
  .orb-view.is-speaking .orb-core { scale: 1; transition: none; }
  .orb-view.is-thinking .orb-ring { animation: none; }
}

/* Conversation history, 26 September 2026. The same panel material as
   Muse's chat, sliding in from the same side; the button mirrors hers on
   the left of the top bar. Colours are her variables only. */
.history-open { left: 18px; right: auto; }
.stage.intro-active .history-open { display: none; }
.stage.chat-on .history-panel { transform: translateX(104%); }
.stage.history-on .history-panel { transform: translateX(0); }
.stage.history-on .chat-shade { opacity: 1; pointer-events: auto; }
.history-actions { display: flex; align-items: center; gap: 8px; }
.history-new {
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.history-search {
  width: 100%;
  box-sizing: border-box;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}
.history-note { margin: 10px 2px 12px; color: var(--muted); font-size: 12px; line-height: 1.45; }
.history-list { flex: 1; overflow: auto; display: flex; flex-direction: column; gap: 8px; padding-bottom: 12px; }
.history-empty { color: var(--muted); font-size: 13px; margin: 18px 2px; }
.history-item {
  display: flex;
  align-items: stretch;
  gap: 6px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
}
.history-item.is-current { border-color: var(--mode-2); }
.history-open-item {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 14px;
  border: 0;
  background: none;
  color: var(--ink);
  text-align: left;
  font: inherit;
  cursor: pointer;
}
.history-title { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.history-meta { font-size: 11px; color: var(--muted); letter-spacing: 0.04em; }
.history-snippet { font-size: 12px; color: var(--muted); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.history-drive {
  align-self: center;
  margin-right: 10px;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 11px;
  white-space: nowrap;
  cursor: pointer;
}
@media (max-width: 420px) { .history-open { left: 12px; width: 38px; height: 38px; } }

/* The voice chooser and the voice notice. 26 September 2026, the voice
   selector brief: which voice is speaking must be unmistakable, each voice
   can be previewed, and a voice that did not speak as chosen is announced. */
.voice-menu {
  position: absolute;
  z-index: 26;
  left: 50%;
  bottom: calc(max(18px, env(safe-area-inset-bottom)) + 170px);
  transform: translateX(-50%);
  width: min(360px, calc(100% - 32px));
  box-sizing: border-box;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 22px;
  background: var(--panel-strong);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  color: var(--ink);
  font-family: "Poppins", sans-serif;
  box-shadow: 0 18px 48px var(--shadow);
}
.voice-now {
  margin: 2px 4px 12px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mode-1);
}
.voice-option {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 6px 8px 6px 6px;
  border: 1px solid var(--line);
  border-radius: 16px;
}
.voice-option.is-selected { border-color: var(--mode-2); background: var(--panel); }
/* Five voices, 29 September 2026. A voice that cannot be chosen yet (the
   Sheldon clone until it is trained) is greyed and says why; it is never
   removed. The list scrolls rather than running off a short screen. */
.voice-option.is-unavailable { opacity: 0.45; border-style: dashed; }
.voice-option.is-unavailable .voice-pick,
.voice-option.is-unavailable .voice-preview { cursor: not-allowed; }
.voice-menu { max-height: calc(100svh - 230px); overflow-y: auto; overscroll-behavior: contain; }
.voice-pick {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.voice-dot {
  flex: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--muted);
  box-sizing: border-box;
}
.voice-option.is-selected .voice-dot { border-color: var(--mode-1); background: var(--mode-1); box-shadow: 0 0 10px var(--mode-glow); }
.voice-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.voice-text strong { font-size: 14px; }
.voice-text small { font-size: 11px; color: var(--muted); }
.voice-preview {
  flex: none;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.voice-preview:disabled { opacity: 0.6; cursor: default; }
.voice-notice {
  position: absolute;
  z-index: 27;
  left: 50%;
  top: calc(max(18px, env(safe-area-inset-top)) + 64px);
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 32px);
  box-sizing: border-box;
  padding: 10px 16px;
  border: 1px solid var(--mode-2);
  border-radius: 999px;
  background: var(--panel-strong);
  color: var(--ink);
  font-family: "Poppins", sans-serif;
  font-size: 13px;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.voice-notice.is-on { opacity: 1; }
.stage.has-voice-pill > .voice-picker svg { width: 12px; height: 12px; opacity: 0.78; }

/* Listening mode and the plus button. 26 September 2026, the listening mode
   and plus button briefs, with the council's conditions: the same two
   circles as before, no badges or recording lights, the talk button keeps
   its gradient and reads Done, and the transcript takes the mode tabs'
   place in the same glass. Only existing tokens. */
.talk-btn { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
.talk-btn .talk-done { display: none; }
.talk-btn.is-dictating .talk-done { display: inline-flex; }
.talk-btn.is-dictating .talk-mic { display: none; }
#earBtn > span { display: grid; place-items: center; }
#earBtn .ear-off { display: none; }
#earBtn[aria-pressed="true"] .ear-on { display: none; }
#earBtn[aria-pressed="true"] .ear-off { display: grid; }
.dictation { display: none; }
.stage.is-dictating .modes { display: none; }
.stage.is-dictating > .model-picker { opacity: 0; pointer-events: none; }
.stage.is-dictating .dictation {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 2px;
  box-sizing: border-box;
  height: calc(3 * 1.45em + 20px);
  margin: 0 0 12px;
  padding: 10px 14px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--panel);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: var(--ink);
  font-family: "Poppins", sans-serif;
  font-size: 13px;
  line-height: 1.45;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, currentColor 45%);
  mask-image: linear-gradient(180deg, transparent 0, currentColor 45%);
}
/* A transcript is read, not a label: sentence case, never the bar's capitals. */
.dictation p { margin: 0; text-transform: none; letter-spacing: normal; }
.dictation p.is-unclear { color: var(--muted); font-style: italic; }
.dict-timer { margin-left: 0.45em; font-variant-numeric: tabular-nums; }
.orb-view.is-dictating .orb-ring { animation-duration: 2.4s; }
@media (prefers-reduced-motion: reduce) {
  .orb-view.is-dictating .orb-ring { animation: none; }
}

.plus-sheet .voice-option:not(:has(button)) .voice-pick { cursor: default; }
.plus-search {
  width: 100%;
  box-sizing: border-box;
  margin: 0 0 4px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}
/* The sheet caps itself and scrolls, so rows can never run off a phone's top.
   Council review, 28 September 2026: measured at -374px on 375x812 before. */
.plus-sheet { max-height: calc(100% - (max(18px, env(safe-area-inset-bottom)) + 170px) - max(18px, env(safe-area-inset-top)) - 8px); overflow-y: auto; }
.plus-list { max-height: 40vh; overflow-y: auto; }
.plus-list .voice-now { margin-top: 12px; color: var(--muted); }
.plus-list .voice-text strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plus-back { margin-top: 12px; }
.attach-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 14px 8px; }
.attach-chips[hidden] { display: none; }
.attach-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 4px 4px 4px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--ink);
  font-family: "Poppins", sans-serif;
  font-size: 12px;
}
.attach-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.attach-remove {
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 16px;
  cursor: pointer;
}

/* The hero in normal flow. 27 September 2026, the hero overlap brief: on
   desktop the Leader header sat on the greeting, two absolutely positioned
   layers in one spot. Each view's text now flows top to bottom in one
   column: eyebrow, greeting (beside the orb), mode name, tagline,
   description. Nothing in the column is positioned, so nothing in it can
   overlap. On a phone the wrappers disappear (display: contents) and the
   added eyebrow and greeting are not shown: the phone layout is unchanged. */
.view-hero,
.hero-row,
.hero-text { display: contents; }
.hero-eyebrow,
.hero-greeting { display: none; }

@media (min-width: 900px) and (min-height: 561px) {
  .stage { --hero-gap: clamp(14px, 2.4vh, 26px); }

  /* One band between the top bar and the mode tabs (tabs top: 260px from
     the bottom, measured at 1440 by 900). The band is the only positioned
     thing; every block inside it is in flow. */
  .view-hero {
    position: absolute;
    z-index: 6;
    top: 66px;
    bottom: 276px;
    left: max(34px, calc((100% - 1220px) / 2));
    right: max(34px, calc((100% - 1220px) / 2));
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--hero-gap);
    pointer-events: none;
  }

  /* The eyebrow moves into the column; the stage's own line stays for
     screen readers only, and so does the old intro overlay. */
  .stage > .identity,
  .stage > .welcome {
    position: absolute;
    width: 1px;
    height: 1px;
    inset: auto;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .view-hero .hero-eyebrow {
    display: block;
    position: static;
    inset: auto;
    flex: none;
    width: 100%;
    margin: 0;
  }

  /* Orb and text side by side, vertically centred (Muse's desktop law). */
  .hero-row {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    align-items: center;
    justify-content: center;
    gap: clamp(40px, 6vw, 110px);
  }
  .hero-text {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: min(560px, 42vw);
    pointer-events: auto;
  }
  .view-hero .orb-wrap,
  .stage.intro-active .view-hero .orb-wrap {
    position: relative;
    left: auto;
    top: auto;
    flex: none;
    transform: none;
    pointer-events: auto;
  }
  .view-hero .orb-wrap.is-pressed { transform: scale(0.92); }
  .stage.intro-active .view-hero .orb-wrap { pointer-events: none; }

  .view-hero .orb-copy,
  .view-hero .presence-copy {
    position: static;
    inset: auto;
    transform: none;
    width: 100%;
    max-width: none;
    margin: 0;
    padding: 0;
    pointer-events: auto;
  }
  .view-hero .presence-copy { width: min(620px, 100%); }
  /* The header is part of the greeting's composition now, not hidden under it. */
  .stage.intro-active .view-hero .orb-copy { opacity: 1; }

  /* Presence: eyebrow at the top, greeting and header centred below it. */
  .presence-view .view-hero .hero-greeting { margin-top: auto; }
  .presence-view .view-hero .presence-copy { margin-bottom: auto; }

  /* The greeting is the intro: in the column while it plays, then it folds
     away and the header settles into the middle. Its height animates, so
     nothing jumps and nothing ever stacks. */
  .view-hero .hero-greeting {
    display: grid;
    grid-template-rows: 1fr;
    width: 100%;
    opacity: 1;
    transition: grid-template-rows 1.4s cubic-bezier(0.45, 0, 0.55, 1), opacity 1s ease, margin-bottom 1.4s cubic-bezier(0.45, 0, 0.55, 1);
  }
  .hero-text .hero-greeting { margin-bottom: var(--hero-gap); }
  .view-hero .hero-greeting > .identity-intro { min-height: 0; overflow: hidden; margin: 0; }
  .stage:not(.intro-active) .view-hero .hero-greeting { grid-template-rows: 0fr; opacity: 0; }
  .stage:not(.intro-active) .hero-text .hero-greeting { margin-bottom: 0; }
  .stage:not(.intro-active) .presence-view .view-hero .hero-greeting { margin-bottom: calc(-1 * var(--hero-gap)); }
  .view-hero .closing-lead { font-size: clamp(28px, min(3vw, 5vh), 44px); }
  .view-hero .closing-outline { font-size: clamp(26px, min(2.8vw, 4.6vh), 40px); }
  .view-hero .closing-sub { max-width: 520px; font-size: clamp(13px, 1.1vw, 16px); }

  /* The model pill follows what it belongs under: the orb, or the Presence
     header. main.ts measures and sets the two variables. */
  .stage.has-hero-pill > .model-picker { left: var(--pill-x); top: var(--pill-y); }
}
@media (min-width: 900px) and (min-height: 561px) and (prefers-reduced-motion: reduce) {
  .view-hero .hero-greeting { transition-duration: 0.01ms; }
}

/* The greeting, centred on phones. 27 September 2026, Sheldon's screenshot:
   the intro text sat 20px right of centre and ran off the right edge. Muse's
   stylesheet gives .welcome-copy width: 100% and later left and right insets
   of 20px; with a width set, the right inset is ignored, so the box was the
   shell's full width, shifted 20px. Width auto lets the insets define it. */
.welcome-copy { width: auto; }

/* Chat messages are text, selectable on every device, and each Atlas reply
   carries a Copy button that writes plain text only. 29 September 2026.
   Only the conversation can be selected. Before this, a drag that ran past
   the edge of a reply, or Ctrl+A, took the whole page with it: the hero
   lines and the six aurora photographs behind the chat, which is what a
   paste then carried. The button label is generated content, never text. */
.stage { -webkit-user-select: none; user-select: none; }
.stage .messages, .stage .messages *, .stage .history-list, .stage .history-list * { -webkit-user-select: text; user-select: text; }
.stage input, .stage textarea { -webkit-user-select: text; user-select: text; }
.bubble { -webkit-touch-callout: default; }
.bubble .copy-btn::before { content: attr(data-label); }
.bubble .bubble-text { white-space: pre-wrap; }
.bubble .copy-btn {
  display: block;
  margin: 8px 0 0 auto;
  padding: 5px 11px;
  min-height: 30px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 250, 240, 0.78);
  font: 700 10px/1 "Poppins", sans-serif;
  letter-spacing: 0.09em;
  cursor: pointer;
}
.stage .messages .copy-btn { -webkit-user-select: none; user-select: none; }
.bubble .copy-btn:hover, .bubble .copy-btn:focus-visible { border-color: rgba(74, 224, 199, 0.6); color: #fff; }
.bubble .copy-btn.is-done { border-color: rgba(74, 224, 199, 0.8); color: #4ae0c7; }
.bubble.is-pending .copy-btn { display: none; }
.turn-timing {
  align-self: flex-start;
  margin: -6px 0 0 4px;
  color: rgba(255, 250, 240, 0.55);
  font: 500 11px/1.3 "Poppins", sans-serif;
  letter-spacing: 0.02em;
}

/* The intro plays alone on phones and small screens. 29 September 2026,
   Sheldon: on a phone "Hi, I'm Atlas" showed at the same time as "Coach,
   Renew your mind" in Presence, and under the model pill in Orb, "too much
   text". The first thing anyone reads is the introduction; the mode title,
   its line, the duplicate eyebrow and the pills wait until it has played,
   then fade in as it fades out. Every screen size: the desktop layout had
   composed the greeting and the header together (27 September), and his
   rule is that the introduction is the first thing read, full stop.
   Measured, not eyeballed: test/intro-first.test.ts and the walk. */
@media all {
  .stage .orb-copy,
  .stage .presence-copy,
  .stage .hero-eyebrow,
  .stage > .identity,
  .stage > .model-picker {
    transition: opacity 1.4s ease 0.4s;
  }
  .stage.intro-active .orb-copy,
  .stage.intro-active .presence-copy,
  .stage.intro-active .hero-eyebrow,
  .stage.intro-active > .identity,
  .stage.intro-active > .model-picker {
    opacity: 0 !important;
    visibility: hidden !important;
    pointer-events: none !important;
  }
}

/*
 * The intro words carry a soft drop shadow. Sheldon, 2 October 2026: "Hi,
 * I'm Atlas, your AI counterpart" had none and could not be read against
 * bright sky; then, the same day, "a soft, subtle drop shadow behind it,
 * readable, not harsh (the harsh-glow removal from the tagline work stays)."
 * Two layers: a close one that gives each letter an edge, and a wide faint
 * one that lifts the line off the sky. No glow, no colour, nothing wider.
 *
 * The lead and the sub are solid, so they take text-shadow (Muse sets
 * `filter:none!important` on the lead at one breakpoint, so a filter would
 * vanish there). The outline line has a transparent fill, where a
 * text-shadow would show through the hollow letters; it takes the same two
 * layers as drop-shadow filters, which follow the stroke instead.
 */
.closing-stack .closing-lead,
.closing-stack .closing-sub {
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5), 0 4px 18px rgba(0, 0, 0, 0.38);
}
.closing-stack .closing-outline {
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.5)) drop-shadow(0 4px 18px rgba(0, 0, 0, 0.38));
}

/*
 * The stepped-down banner. Sheldon, 2 October 2026: a developer switcher
 * state sat silent for four weeks and broke Mentor and Leader in a demo.
 * It stays put (no fade, no timer) because the state it names stays put.
 * Muse's variables only. The six second notice moves down beneath it rather
 * than covering it.
 */
.preview-banner {
  position: absolute;
  z-index: 28;
  left: 50%;
  top: calc(max(18px, env(safe-area-inset-top)) + 64px);
  transform: translateX(-50%);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px 12px;
  width: max-content;
  max-width: calc(100% - 32px);
  box-sizing: border-box;
  padding: 10px 14px;
  border: 1px solid var(--trybe-orange);
  border-radius: 18px;
  background: var(--panel-strong);
  color: var(--ink);
  font-family: "Poppins", sans-serif;
  font-size: 13px;
  line-height: 1.35;
  text-align: center;
}
.preview-back {
  border: 1px solid var(--trybe-orange);
  border-radius: 999px;
  padding: 6px 12px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.preview-back:disabled { opacity: 0.6; cursor: default; }
.stage.is-previewing .voice-notice { top: calc(max(18px, env(safe-area-inset-top)) + 132px); }

/*
 * Desktop framing for Mentor and Leader. Sheldon, 2 October 2026: "On mobile
 * they look great; on desktop they don't." Both photographs are tall
 * portrait frames with the subject in the lower third (Leader's mountains and
 * lake at 70 to 95 percent down, Mentor's cabin at 62 to 82). A wide window
 * shows about a third of a portrait photo's height, and `cover` centred that
 * third, so Leader lost its horizon entirely and Mentor's cabin fell behind
 * the buttons. Coach and Strategist frame well centred, so they are untouched.
 *
 * One focus value moves all three layers together: the photograph, the
 * traced sky mask and the drifting copy of the sky inside it. They share one
 * box and one `cover`, so the same position keeps the mask on the photo's own
 * horizon: the land never moves. Landscape windows only; phones keep the
 * centred crop that already looks right.
 */
@media (min-width: 641px) and (orientation: landscape) {
  .scene.mentor { --focus-y: 64%; }
  .scene.leader { --focus-y: 85%; }
  .scene.mentor img.base,
  .scene.leader img.base { object-position: 50% var(--focus-y); }
  .scene.mentor .sky-motion,
  .scene.leader .sky-motion { -webkit-mask-position: 50% var(--focus-y); mask-position: 50% var(--focus-y); }
  .scene.mentor .sky-motion::before,
  .scene.leader .sky-motion::before { background-position: 50% var(--focus-y); }
}

/*
 * The waveform ribbon. Sheldon, 2 October 2026: a thin glass line above the
 * mode tabs that rises and falls with Atlas's voice and breathes when she is
 * quiet. Presence only; the orb belongs to the Orb view.
 *
 * Placement: absolute, inside the tab bar and just above it, so nothing
 * reflows: the headline, pills, tabs and the Talk button stay exactly where
 * they were. Muse places the bar absolutely on desktop (900 wide and 561
 * tall, and up) and in flow below that; in flow it is given position:
 * relative, which moves nothing and makes it the ribbon's anchor too. The
 * smallest gap above the tabs, measured at 1280 by 800, is 44px; the ribbon
 * takes 24px of it with 10px clear below and at least 10 above.
 *
 * Motion: transform only. At rest a CSS animation breathes the bars (the
 * compositor runs it, the main thread does nothing); while someone speaks,
 * .is-live hands the bars to ribbon.ts. Glass without backdrop-filter: a blur
 * over the drifting aurora would repaint every frame. Colour is Muse's aqua,
 * the aurora's own green-teal.
 */
@media not all and (min-width: 900px) and (min-height: 561px) {
  .controls .modes { position: relative; }
}
.voice-ribbon {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 10px);
  width: min(56%, 340px);
  height: 24px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-radius: 999px;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.6s ease;
}
.voice-ribbon::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--panel);
  opacity: 0.22;
}
.voice-ribbon i {
  position: relative;
  display: block;
  width: 2px;
  height: 16px;
  border-radius: 2px;
  background: var(--aqua);
  opacity: 0.82;
  transform: scaleY(0.1);
  transform-origin: 50% 50%;
  will-change: transform;
  animation: ribbon-breathe 5.2s ease-in-out infinite alternate;
}
.voice-ribbon.is-live i { animation: none; }
@keyframes ribbon-breathe {
  from { transform: scaleY(0.08); }
  to { transform: scaleY(0.2); }
}
.stage:not(.presence-active) .voice-ribbon,
.stage.intro-active .voice-ribbon { opacity: 0; }
.stage:not(.presence-active) .voice-ribbon i,
.stage.intro-active .voice-ribbon i { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .voice-ribbon i { animation: none; }
}

/*
 * The Talk flow, 2 October 2026. Push to talk on the big button: Listening
 * and Thinking carry a pulsing live dot after the words, swapped in place in
 * the status line (fixed height, so nothing moves). The side button is
 * continuous conversation: a waveform icon, lit while the open back and
 * forth runs, unavailable while a push to talk turn is open.
 */
.status .live-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: 8px;
  vertical-align: 1px;
  border-radius: 50%;
  background: var(--aqua);
  box-shadow: 0 0 8px var(--aqua);
  animation: live-dot 1.2s ease-in-out infinite;
}
@keyframes live-dot {
  0%, 100% { opacity: 0.35; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.1); }
}
.mini-control.is-continuous svg { width: 20px; height: 20px; }
.mini-control.is-continuous.is-active {
  border-color: var(--aqua);
  color: var(--ink);
  box-shadow: 0 0 0 1px var(--aqua), 0 0 18px var(--mode-glow);
}
.mini-control.is-continuous.is-active svg path { animation: live-dot 1.2s ease-in-out infinite; }
.mini-control.is-continuous.is-active svg path:nth-child(2) { animation-delay: -0.2s; }
.mini-control.is-continuous.is-active svg path:nth-child(3) { animation-delay: -0.4s; }
.mini-control.is-continuous.is-active svg path:nth-child(4) { animation-delay: -0.6s; }
.mini-control.is-continuous.is-active svg path:nth-child(5) { animation-delay: -0.8s; }
.mini-control.is-continuous:disabled { opacity: 0.45; cursor: default; }
@media (prefers-reduced-motion: reduce) {
  .status .live-dot,
  .mini-control.is-continuous.is-active svg path { animation: none; }
}

/* The Settings window behind the plus button. 3 October 2026, Sheldon:
   "the same kind of setup and box that you see when you click on
   Connectors in Claude." Nav on the left, the page on the right, cards
   with a tick when connected and a plus when not. It sits on the body,
   above the shell (80), so it covers the sidebar the way Claude's does. */
.settings-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 32px 24px;
  background: rgba(4, 6, 18, 0.5);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: "Poppins", sans-serif;
  color: var(--ink);
}
.settings-window {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  width: min(1040px, 100%);
  height: min(800px, 100%);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: #121130;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
}
.settings-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 0;
  padding: 14px 10px;
  overflow-y: auto;
  border-right: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.025);
}
.settings-search,
.conn-search {
  box-sizing: border-box;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}
.settings-search { width: 100%; margin-bottom: 6px; }
.settings-search::placeholder,
.conn-search::placeholder { color: var(--muted); }
.settings-nav-list { display: flex; flex-direction: column; gap: 2px; }
.settings-nav-group {
  margin: 16px 10px 6px;
  font-size: 12px;
  color: var(--muted);
}
.settings-nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.settings-nav-item:hover { background: rgba(255, 255, 255, 0.05); }
.settings-nav-item[aria-current="page"] { background: rgba(255, 255, 255, 0.1); }
.settings-nav-icon { display: grid; place-items: center; width: 18px; height: 18px; color: var(--muted); }
.settings-nav-item[aria-current="page"] .settings-nav-icon { color: var(--ink); }
.settings-nav-icon svg { width: 18px; height: 18px; }
.settings-main { position: relative; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.settings-close {
  position: absolute;
  z-index: 2;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--ink);
  cursor: pointer;
}
.settings-close:hover { background: rgba(255, 255, 255, 0.08); }
.settings-close svg { width: 20px; height: 20px; }
.settings-pane { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 40px 32px 32px; }
.settings-head { margin: 0 44px 22px 0; }
.settings-head h2,
.conn-head h2 { margin: 0; font-size: 24px; font-weight: 600; letter-spacing: -0.01em; }
.settings-sub { margin: 6px 0 0; font-size: 13px; color: var(--muted); }
.settings-empty { margin: 8px 0; font-size: 14px; color: var(--muted); }
.settings-rows { display: grid; grid-template-columns: minmax(120px, 220px) 1fr; margin: 0; }
.settings-rows dt,
.settings-rows dd { margin: 0; padding: 16px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.settings-rows dt { color: var(--ink); font-weight: 500; }
.settings-rows dd { color: var(--muted); text-align: right; }
.settings-panel-host { max-width: 560px; }

.conn-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 44px 26px 0;
}
.conn-head-left,
.conn-head-right { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.conn-tabs { display: inline-flex; padding: 3px; border-radius: 10px; background: rgba(255, 255, 255, 0.06); }
.conn-tab {
  padding: 5px 12px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.conn-tab[aria-selected="true"] { background: rgba(255, 255, 255, 0.14); color: var(--ink); }
.conn-search { width: 240px; }
.conn-add-wrap { position: relative; }
.conn-add {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border: 0;
  border-radius: 10px;
  background: #fff;
  color: #121130;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.conn-add svg { width: 16px; height: 16px; }
.conn-add .conn-caret { width: 14px; height: 14px; opacity: 0.7; }
.conn-add-menu {
  position: absolute;
  z-index: 3;
  top: calc(100% + 6px);
  right: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 260px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #1b1a40;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
}
.conn-add-menu button {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 10px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.conn-add-menu button:hover,
.conn-add-menu button:focus-visible { background: rgba(255, 255, 255, 0.08); }
.conn-add-menu strong { font-size: 14px; font-weight: 500; }
.conn-add-menu small { font-size: 12px; color: var(--muted); }
.conn-title { display: flex; align-items: center; gap: 8px; margin: 0 0 14px; font-size: 16px; font-weight: 600; }
.conn-count { padding: 1px 8px; border-radius: 999px; background: rgba(255, 255, 255, 0.08); font-size: 12px; font-weight: 500; color: var(--muted); }
.deleg-switch { margin: 0 0 10px; }
.deleg-waiting-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.conn-tab.deleg-waiting { border: 1px dashed var(--line); opacity: 0.6; cursor: not-allowed; }
.deleg-list { display: flex; flex-direction: column; }
.deleg-row { display: flex; flex-direction: column; gap: 3px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.deleg-row strong { font-size: 14px; font-weight: 500; }
.deleg-row small { font-size: 12px; color: var(--muted); }
.conn-status { display: flex; align-items: center; gap: 10px; margin: -4px 0 14px; font-size: 13px; color: var(--muted); }
.conn-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.conn-card {
  position: relative;
  display: flex;
  gap: 14px;
  min-height: 96px;
  padding: 16px 52px 16px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.03);
}
.conn-card.is-actionable { cursor: pointer; }
.conn-card.is-actionable:hover { background: rgba(255, 255, 255, 0.06); }
.conn-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
}
.conn-mark svg { width: 32px; height: 32px; }
.conn-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.conn-text strong { font-size: 15px; font-weight: 600; }
.conn-blurb { margin: 0; font-size: 13px; line-height: 1.4; color: rgba(241, 247, 255, 0.82); }
.conn-note { font-size: 12px; color: #8cf7e2; }
.conn-by { font-size: 12px; color: var(--muted); }
.conn-corner {
  position: absolute;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink);
  cursor: pointer;
}
.conn-corner svg { width: 18px; height: 18px; }
.conn-corner.is-plus:hover { background: rgba(255, 255, 255, 0.12); }
.conn-corner.is-tick { border-color: rgba(74, 222, 128, 0.45); background: rgba(74, 222, 128, 0.14); color: #4ade80; }
.conn-corner.is-tick:disabled { cursor: default; opacity: 1; }

/* Phones: the window is the screen, the nav is a row that scrolls. */
@media (max-width: 720px) {
  .settings-overlay { padding: 0; }
  .settings-window {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    width: 100%;
    height: 100dvh;
    border: 0;
    border-radius: 0;
  }
  /* The nav scrolls in its own lane, which ends before the close button,
     so an item never slides under it. The fade says there is more. */
  .settings-nav {
    flex-direction: row;
    margin-right: 52px;
    padding: max(10px, env(safe-area-inset-top)) 12px 10px;
    overflow-x: auto;
    overflow-y: hidden;
    border-right: 0;
    background: none;
    -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent);
    mask-image: linear-gradient(90deg, #000 88%, transparent);
  }
  .settings-main { border-top: 1px solid var(--line); }
  .settings-search,
  .settings-nav-group { display: none; }
  .settings-nav-list { flex-direction: row; gap: 4px; }
  .settings-nav-item { width: auto; padding: 8px 12px; white-space: nowrap; font-size: 13px; }
  .settings-main { position: static; }
  .settings-close { top: max(11px, env(safe-area-inset-top)); right: 10px; }
  .settings-pane { padding: 22px 16px max(24px, env(safe-area-inset-bottom)); }
  .settings-head,
  .conn-head { margin-right: 0; }
  .conn-head-right { width: 100%; }
  .conn-search { flex: 1; width: auto; min-width: 0; }
  .conn-grid { grid-template-columns: minmax(0, 1fr); }
  .settings-rows { grid-template-columns: minmax(0, 1fr) auto; }
}

/* Content Studio's door, in the Strategist section only (owner). 4 October 2026. */
.studio-link { display: inline-block; align-self: center; margin: 6px auto 0; padding: 7px 16px; border-radius: 999px;
  border: 1px solid rgba(110, 41, 140, .7); background: linear-gradient(120deg, rgba(110, 41, 140, .45), rgba(0, 93, 92, .45));
  backdrop-filter: blur(14px); color: #ece7df; font-size: 12px; font-weight: 600; letter-spacing: .02em; text-decoration: none; }
.studio-link[hidden] { display: none; }
.studio-link:hover { border-color: #2dd4bf; }
