/* ============================================================================
   THE CONNECTION COACH — "the quiet room", in pearl and aurora
   A calm space you step into to say something hard. It holds you, and it
   slows you down on purpose.
   ========================================================================== */

:root {
  /* Two rooms now, the same quiet in each.

     LIGHT — pearl. Silver light with lavender, pink and sky moving through it,
     the inside of a shell. DARK — aurora. Deep teal water with green, violet
     and blue light above it.

     The token names are the old ones on purpose — every rule in this file
     already speaks them. Read --ink as "the room" and --mist as "what you
     read"; in light mode the ink is pale and the mist is dark. Iridescence is
     only ever a background or an accent: text sits on solid surfaces, so
     contrast never depends on where the shimmer happens to be. */
  --ink:        #F5F4F9;  /* pearl */
  --ink-raised: #FFFFFF;
  --ink-lift:   #EFECF6;
  --ink-edge:   #E2DEEC;
  --ink-hover:  #ECE8F5;
  --ink-field:  #FFFFFF;
  --ink-deep:   #ECE9F3;

  --mist:       #1E1B2E;
  --mist-soft:  #47425C;
  --mist-faint: #5D5873;

  --clay:       #7048BE;  /* the accent — amethyst */
  --clay-deep:  #CDBDEB;
  --clay-glow:  rgba(112, 72, 190, 0.14);
  --slate:      #2E6FAE;  /* the cool counterweight — sky */
  --slate-deep: #A9C3E3;
  --slate-glow: rgba(46, 111, 174, 0.12);
  --pink:       #C2578F;

  --warn:       #946510;
  --warn-ink:   #5E420B;
  --bad-ink:    #6A2A55;
  --accent-ink: #4B2A8C;  /* text on an accent-tinted surface */
  --on-accent:  #FFFFFF;  /* text on the solid accent gradient */

  --track:        #8C87A2;
  --edge-control: #8C87A2;
  --veil:         rgba(40, 32, 66, 0.32);

  --iris: radial-gradient(90% 60% at 10% -10%, rgba(196, 176, 240, 0.55), transparent 60%),
          radial-gradient(80% 55% at 100% 0%, rgba(244, 196, 222, 0.50), transparent 62%),
          radial-gradient(90% 60% at 50% 110%, rgba(176, 208, 242, 0.55), transparent 64%),
          linear-gradient(180deg, #F7F6FA, #EFEFF4);
  --grad-primary: linear-gradient(120deg, #6A44B3 0%, #94478D 55%, #3D6CAE 100%);
  --grad-edge: linear-gradient(120deg, #B9A3E8, #EAA9CC, #9EC3EC, #C9CBD6);
  --shadow: 0 1px 2px rgba(40, 32, 66, 0.06), 0 8px 24px rgba(40, 32, 66, 0.07);

  /* ---- the scales.

     Measured before they existed: seventeen distinct font-sizes, twelve
     border-radii and eleven gap values. 0.78 / 0.80 / 0.82 / 0.85rem all appear
     and are, at reading distance, the same size — that is drift, not design,
     and it is the difference between something that was designed and something
     that was assembled. Everything below now comes off these steps. */
  --t-1: 0.72rem;   /* eyebrows, the smallest true thing        */
  --t-2: 0.82rem;   /* asides, captions, links                  */
  --t-3: 0.92rem;   /* quiet prose                              */
  --t-4: 1rem;      /* body, buttons, what you type             */
  --t-5: 1.16rem;   /* the lede, and names                      */
  --t-6: 1.5rem;    /* a section that owns its screen           */
  --t-7: clamp(1.4rem, 5vw, 1.8rem);     /* the title           */
  --t-8: clamp(2rem, 7.5vw, 2.9rem);     /* the one display     */

  --s-1: 0.25rem; --s-2: 0.5rem; --s-3: 0.75rem; --s-4: 1rem;
  --s-5: 1.25rem; --s-6: 1.5rem; --s-7: 2rem;    --s-8: 2.5rem;

  --r-sm:  8px;    /* the small mechanical parts                */
  --r-md:  11px;   /* anything you press                        */
  --r-lg:  14px;   /* anything that holds something             */
  --r-pill: 999px;

  --serif: "Newsreader", ui-serif, Georgia, "Iowan Old Style", serif;
  --sans:  "Instrument Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Breath. Nothing here snaps. */
  /* Slowness is a choice this app makes on purpose — but it belongs in the
     things that are ALIVE (the koi, the orb's pulse), not in the things you
     are waiting for. Every screen change used to fade in over 900ms, which is
     long enough to read as the app being slow rather than the room being calm;
     screenshots caught it mid-fade often enough to prove the point. Arrival is
     now 380ms. The breath stayed where breathing belongs. */
  --arrive: 380ms cubic-bezier(0.22, 0.61, 0.36, 1);
  --breath: 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
  --settle: 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
  --touch:  180ms cubic-bezier(0.22, 0.61, 0.36, 1);

  --gutter: clamp(1.25rem, 5vw, 2rem);
  --measure: 34rem;
  --radius: var(--r-lg);
}

/* Aurora. Applied by data-theme, which app.js resolves from the phone's
   setting or the person's own choice on Account. */
:root[data-theme="dark"] {
  --ink:        #0A1416;
  --ink-raised: #0F1D20;
  --ink-lift:   #15272A;
  --ink-edge:   #1E3437;
  --ink-hover:  #1A2E31;
  --ink-field:  #0D1A1C;
  --ink-deep:   #071012;

  --mist:       #E2EFEB;
  --mist-soft:  #A9C0BA;
  --mist-faint: #87A19C;

  --clay:       #A88DEB;  /* violet */
  --clay-deep:  #4B3C80;
  --clay-glow:  rgba(168, 141, 235, 0.16);
  --slate:      #5CD3A5;  /* aurora green */
  --slate-deep: #23594A;
  --slate-glow: rgba(92, 211, 165, 0.14);
  --pink:       #7FB2EE;  /* in the dark room the third light is blue */

  --warn:       #D6B072;
  --warn-ink:   #EEDDB9;
  --bad-ink:    #E8D6F4;
  --accent-ink: #E6DCFF;
  --on-accent:  #071012;

  --track:        #557274;
  --edge-control: #5F7E80;
  --veil:         rgba(2, 8, 9, 0.72);

  --iris: radial-gradient(90% 55% at 0% -10%, rgba(92, 211, 165, 0.13), transparent 60%),
          radial-gradient(80% 50% at 100% 0%, rgba(168, 141, 235, 0.14), transparent 62%),
          radial-gradient(90% 60% at 50% 112%, rgba(111, 168, 236, 0.12), transparent 64%),
          linear-gradient(180deg, #0B1618, #081113);
  --grad-primary: linear-gradient(120deg, #5CD3A5 0%, #9C8BEA 55%, #73AAEE 100%);
  --grad-edge: linear-gradient(120deg, #5CD3A5, #A88DEB, #73AAEE);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 10px 30px rgba(0, 0, 0, 0.25);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ink);
  color: var(--mist);
  font-family: var(--sans);
  /* 17px, expressed as a percentage of whatever the reader has told their
     browser they can see. Hard-coding the pixel value silently overrode that
     preference — on a phone set to large text, this app alone stayed small. */
  font-size: 106.25%;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
}

body {
  min-height: 100svh;
  background: var(--ink);
  background-image: var(--iris);
  background-attachment: fixed;
}

/* ------------------------------------------------------------------ layout */

#app {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: max(1.25rem, env(safe-area-inset-top)) var(--gutter)
           calc(2.5rem + env(safe-area-inset-bottom));
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}

.screen {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--s-6);
  animation: arrive var(--arrive) both;
}

@keyframes arrive {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

.stack   { display: flex; flex-direction: column; gap: var(--s-4); }
.stack-s { display: flex; flex-direction: column; gap: var(--s-2); }
.row     { display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: center; }
/* A .btn inside a .row is one of several side by side, so it sizes to its
   label rather than to the line. Without this they stacked, which turned two
   small choices into two full-width decisions. */
.row > .btn { width: auto; flex: 0 1 auto; }
.grow    { flex: 1; }
.spacer  { flex: 1; min-height: 1rem; }

/* -------------------------------------------------------------- typography */

h1, h2, h3 { margin: 0; font-weight: 400; }

.display {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--t-8);
  line-height: 1.14;
  letter-spacing: -0.018em;
  color: var(--mist);
}

.title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: var(--t-7);
  line-height: 1.24;
  letter-spacing: -0.012em;
}

.lede {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--t-5);
  line-height: 1.5;
  color: var(--mist-soft);
}

.body  { font-size: var(--t-4); color: var(--mist-soft); }
/* The app's voice, quietly.

   DESIGN.md draws one line and the whole typographic system hangs off it: the
   serif is what the app and the coach say; the sans is machinery — labels,
   buttons, metadata, your own typing. `.small` is sans, and `.small` had
   quietly become where the app's most tender sentences lived, so screens ended
   up with two consecutive paragraphs of the same voice in two different
   typefaces. This is `.small`'s size and weight in the serif, so quiet prose
   can stay quiet without changing who is speaking. */
.aside {
  font-family: var(--serif);
  font-size: var(--t-3);
  line-height: 1.55;
  color: var(--mist-soft);
}

.small { font-size: var(--t-3); color: var(--mist-soft); }

.meta {
  font-size: var(--t-1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mist-faint);
  font-weight: 500;
}

.warm { color: var(--clay); }
.cool { color: var(--slate); }
em.q { font-family: var(--serif); font-style: italic; color: var(--mist); }

/* ---------------------------------------------------------------- surfaces */

.card {
  background: var(--ink-raised);
  border: 1px solid var(--ink-edge);
  border-radius: var(--radius);
  padding: 1.125rem 1.25rem;
}

.card.warm-edge { border-color: color-mix(in srgb, var(--clay) 28%, transparent); background: linear-gradient(180deg, color-mix(in srgb, var(--clay) 5%, transparent), transparent 70%), var(--ink-raised); }
.card.cool-edge { border-color: color-mix(in srgb, var(--slate) 26%, transparent); background: linear-gradient(180deg, color-mix(in srgb, var(--slate) 5%, transparent), transparent 70%), var(--ink-raised); }

hr.rule { border: 0; border-top: 1px solid var(--ink-edge); margin: 0.5rem 0; }

/* ------------------------------------------------------------ the way in

   A row that leads somewhere, and it has to look like one.

   The first attempt was hairline-separated text with no border — which was
   handsomely minimal and completely ambiguous: a title at reading weight over
   a sentence of prose is indistinguishable from a heading over a paragraph,
   and nothing about it said "this is a thing you press". That is the exact
   mistake this app already made once, on the screen where the only real button
   read as a heading and people asked how they were supposed to advance.

   So these use the control language the rest of the app already has:
   --edge-control, the border weight that a whole pass was spent bringing to
   3:1 against the background. Left-aligned and two lines tall rather than
   centred and one, because they are destinations rather than actions — but
   unmistakably pressable. The whole row is the target. */
.way {
  appearance: none;
  display: flex; flex-direction: column; gap: 0.25rem;
  width: 100%; text-align: left;
  background: transparent;
  border: 1px solid var(--edge-control);
  border-radius: var(--r-lg);
  padding: 1rem 1.15rem;
  cursor: pointer;
  transition: background var(--touch), border-color var(--touch), opacity var(--touch);
}
.way + .way { margin-top: var(--s-3); }
.way:hover { background: var(--ink-raised); }
.way:active { opacity: 0.7; }
.way-title { font-size: var(--t-5); color: var(--mist); line-height: 1.3; }
.way-blurb { font-size: var(--t-3); color: var(--mist-soft); line-height: 1.5; }
/* The one part of the row that is about right now rather than about what the
   thing is — "your turn", "3 to listen to". Warm, so the eye finds it, and
   the only place the clay is spent on this screen. */
.way-note { font-size: var(--t-2); color: var(--clay); margin-top: 0.2rem; }

/* The line from the coach. The only decorative element on the room screen, and
   it earns its place by being read: someone who opens this app and does
   nothing else has still been handed one true sentence. Serif, because it is
   the one thing here that is written rather than said. */
.quote {
  font-family: var(--serif);
  font-size: var(--t-5);
  line-height: 1.55;
  color: var(--mist);
  margin: 1.1rem 0 0;
  padding-left: 0.9rem;
  border-left: 2px solid color-mix(in srgb, var(--clay) 35%, transparent);
}

/* --------------------------------------------------------------- controls */

button { font-family: inherit; font-size: inherit; }

.btn, .pinned-action {
  appearance: none;
  border: 1px solid var(--edge-control);
  background: var(--ink-lift);
  color: var(--mist);
  padding: 0.85rem 1.25rem;
  border-radius: var(--r-md);
  font-size: var(--t-4);
  font-weight: 500;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: background var(--touch), border-color var(--touch), transform var(--touch), opacity var(--touch);
  text-align: center;
}

.btn:hover  { background: var(--ink-hover); }
.btn:active, .pinned-action:active { transform: translateY(1px); }

.btn.primary, .pinned-action {
  background: linear-gradient(180deg, color-mix(in srgb, var(--clay) 22%, transparent), color-mix(in srgb, var(--clay) 12%, transparent));
  /* 0.45 measured 2.26:1. 0.64 is the least that clears 3:1 both on the page
     and on a raised surface — 3.37 and 3.09. */
  border-color: color-mix(in srgb, var(--clay) 64%, transparent);
  color: var(--accent-ink);
}
.btn.primary:hover { background: linear-gradient(180deg, color-mix(in srgb, var(--clay) 30%, transparent), color-mix(in srgb, var(--clay) 16%, transparent)); }

/* The quietest button, not the invisible one. "I already have a room" is the
   only way back in for someone on a new phone, and it was drawn with a
   transparent border on a transparent fill: a 1.00:1 boundary, i.e. none. It
   keeps its lack of fill — that is what makes it read as tertiary — and gets
   the same outline as everything else. */
.btn.ghost { background: transparent; border-color: var(--edge-control); color: var(--mist-soft); }
.btn.ghost:hover { color: var(--mist); background: transparent; }

.btn.block, .pinned-action { width: 100%; }
.btn[disabled], .pinned-action[disabled] { opacity: 0.38; cursor: not-allowed; transform: none; }

:where(button, a, input, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--slate);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* choice chips — finish line, medium, severity */

.chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }

.chip {
  appearance: none;
  background: transparent;
  border: 1px solid var(--edge-control);
  color: var(--mist-soft);
  border-radius: var(--r-pill);
  /* 44px minimum. These are the primary input on the shaping screen — the
     finish line, how big it is, voice or video — and they were the only
     targets in the app under the threshold, at about 39px. */
  padding: 0.62rem 0.95rem;
  min-height: 44px;
  /* Some of these are whole sentences. Left to itself the longest one broke
     with a single orphaned word centred on the second line, which looks like
     an accident rather than a choice. */
  text-wrap: balance;
  font-size: var(--t-3);
  cursor: pointer;
  transition: all var(--touch);
}
.chip:hover { color: var(--mist); border-color: var(--edge-control); }
.chip[aria-pressed="true"] {
  color: var(--accent-ink);
  border-color: color-mix(in srgb, var(--clay) 60%, transparent);   /* 3.10:1 — 0.55 measured 2.79 */
  background: color-mix(in srgb, var(--clay) 13%, transparent);
}

/* fields */

.field {
  width: 100%;
  background: var(--ink-raised);
  border: 1px solid var(--ink-edge);
  border-radius: var(--r-md);
  color: var(--mist);
  padding: 0.85rem 0.95rem;
  font-family: inherit;
  font-size: var(--t-4);
  line-height: 1.55;
  resize: vertical;
  transition: border-color var(--touch), background var(--touch);
}
.field::placeholder { color: var(--mist-faint); }
.field:focus { border-color: var(--slate-deep); background: var(--ink-field); outline: none; }
.field:focus-visible { outline: 2px solid var(--slate); outline-offset: 2px; }

textarea.field { min-height: 6.5rem; }
textarea.script { font-family: var(--serif); font-size: var(--t-5); line-height: 1.55; min-height: 8rem; }

label.lbl { display: block; font-size: var(--t-3); color: var(--mist-soft); margin-bottom: 0.4rem; }

/* ------------------------------------------------------------------ header */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: 1.5rem;
  min-height: 1.75rem;
}

.mark {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--t-4);
  letter-spacing: 0.02em;
  color: var(--mist-soft);
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}
.mark .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--clay); box-shadow: 0 0 12px var(--clay); }

/* Quiet to the eye, but a real target for a thumb — 44px of reachable
   height, spent on padding rather than on looking bigger. */
.linkish {
  background: none; border: 0;
  /* 44px, like everything else you have to hit. These measured 40 — close
     enough to look fine and not close enough to be right, and they are the
     only way out of the coaching flow. The negative margin keeps the extra
     height from pushing the layout around. */
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 0.85rem 0.3rem; margin: -0.85rem -0.3rem;
  color: var(--mist-faint); font-size: var(--t-2); cursor: pointer;
  /* The underline was drawn in --ink-edge (#232A33), which is about 1.1:1
     against the page — so the single signal saying "this is a link" was painted
     in the background colour. These are the only way out of the coaching flow. */
  text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--mist-faint);
}
.linkish:hover { color: var(--mist-soft); }

/* ------------------------------------------------------ hearing it back

   A list of turns, in order, with the one currently speaking lit. The track
   under each row is the same idea as the one on a single recording — you can
   see where you are without a scrubber offering to skip you past it. */

.convo-stage { margin: 0; }
.convo-media {
  display: block; width: 100%;
  border-radius: var(--radius);
  background: var(--ink-deep);
  border: 1px solid var(--ink-edge);
}
/* An audio-only clip is playing through the same element. Nothing to look at,
   so it takes up nothing rather than leaving a black rectangle behind. */
.convo-media.audio-only { height: 0; border: 0; }

.convo { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.turn {
  border: 1px solid var(--ink-edge);
  border-radius: var(--radius);
  padding: 0.85rem 0.95rem 0.7rem;
  background: var(--ink-raised);
  transition: border-color var(--settle), background var(--settle), opacity var(--settle);
}
.turn-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); }
.turn-who { font-family: var(--serif); font-size: var(--t-5); color: var(--mist); }
.turn-len { font-size: var(--t-2); color: var(--mist-faint); font-variant-numeric: tabular-nums; }
.turn-track {
  margin: 0.6rem 0 0.35rem;
  height: 3px; border-radius: var(--r-pill); background: var(--ink-edge); overflow: hidden;
}
.turn-track i {
  display: block; height: 100%; width: var(--at, 0%);
  background: var(--track);
  transition: width 120ms linear;
}
.turn.now { border-color: color-mix(in srgb, var(--clay) 60%, transparent); background: color-mix(in srgb, var(--clay) 7%, transparent); }
.turn.now .turn-track i { background: var(--clay); }
.turn.done { opacity: 0.62; }
.turn.done .turn-track i { background: var(--track); }
.turn .turn-cue { font-size: var(--t-2); }

/* ------------------------------------------------------- the pinned action

   Measured, not guessed: on the shaping screen the button that sends you to
   the recorder sat 470px below the fold on an iPhone 14 and 856px below it on
   an SE — and on an SE even "Start a room", on the very first screen, was 22px
   under. A screen can look finished when it is not, and the thing you are
   meant to do next can be somewhere you have no reason to look.

   So the primary action follows you down the page — and only while it needs
   to. The moment the real button scrolls into view the bar gets out of the
   way, so at the bottom of a screen there is one button, in its place, and
   nothing hovering over it. */
.pin {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  padding: 0.9rem var(--gutter) max(0.9rem, calc(0.5rem + env(safe-area-inset-bottom)));
  background: linear-gradient(to top, var(--ink) 0%, var(--ink) 58%, color-mix(in srgb, var(--ink) 82%, transparent) 84%, color-mix(in srgb, var(--ink) 0%, transparent));
  animation: rise var(--settle) both;
}
.pin > .inner { width: 100%; max-width: var(--measure); margin: 0 auto; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .pin { animation: none; } }

/* ------------------------------------------------- the space between (canvas) */

.space-wrap {
  position: relative;
  width: 100%;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--ink-deep);
  border: 1px solid var(--ink-edge);
}
.space-wrap canvas { display: block; width: 100%; height: 100%; }
.space-caption {
  position: absolute; left: 0; right: 0; bottom: 0.6rem;
  text-align: center; pointer-events: none;
}

/* A room that is watching should look like it is watching.

   This is the screen where "is this thing stuck?" gets asked, because nothing
   on it moves while you wait. One slow pulse is enough to say: it's listening,
   you don't have to do anything. */
.waiting {
  display: inline-flex; align-items: center; gap: var(--s-2);
  color: var(--mist-faint); font-size: var(--t-2);
}
.waiting i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--slate);
  animation: breathe 3.2s var(--breath) infinite;
}
@keyframes breathe {
  0%, 100% { opacity: 0.25; transform: scale(0.9); }
  50%      { opacity: 0.9;  transform: scale(1); }
}

/* ------------------------------------------------------------ conversation */

.thread {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  padding-bottom: 0.5rem;
}

.msg { max-width: 92%; animation: arrive var(--settle) both; }

.msg.coach {
  align-self: flex-start;
  font-family: var(--serif);
  font-size: var(--t-5);
  line-height: 1.55;
  color: var(--mist);
  border-left: 2px solid var(--slate-deep);
  padding-left: 1rem;
}

.msg.you {
  align-self: flex-end;
  background: var(--ink-raised);
  border: 1px solid var(--ink-edge);
  border-radius: var(--r-lg) var(--r-lg) var(--r-sm) var(--r-lg);
  padding: 0.7rem 0.95rem;
  font-size: var(--t-4);
  color: var(--mist);
}

.msg.coach p, .msg.you p { margin: 0 0 0.6rem; }
.msg.coach p:last-child, .msg.you p:last-child { margin-bottom: 0; }
.msg.coach strong, .msg.you strong { font-weight: 600; color: var(--mist); }
.msg.coach em, .msg.you em { font-style: italic; }

.thinking { display: inline-flex; gap: 5px; align-items: center; padding-left: 1rem; }
.thinking i {
  width: 5px; height: 5px; border-radius: 50%; background: var(--slate);
  opacity: 0.35; animation: pulse 2.4s var(--breath) infinite;
}
.thinking i:nth-child(2) { animation-delay: 0.3s; }
.thinking i:nth-child(3) { animation-delay: 0.6s; }
@keyframes pulse { 0%, 100% { opacity: 0.22; transform: scale(0.85); } 50% { opacity: 0.85; transform: scale(1); } }

.composer { display: flex; gap: var(--s-3); align-items: flex-end; }
.composer textarea { max-height: 9rem; min-height: 3rem; }
.composer .send {
  flex: 0 0 auto; width: 3rem; height: 3rem; border-radius: var(--r-md);
  border: 1px solid var(--ink-edge); background: var(--ink-lift); color: var(--mist);
  cursor: pointer; display: grid; place-items: center; transition: all var(--touch);
}
.composer .send:hover { border-color: color-mix(in srgb, var(--clay) 50%, transparent); color: var(--clay); }

/* ------------------------------------------------------------ the keystone */

.keystone { display: flex; flex-direction: column; align-items: center; gap: var(--s-5); padding: 1rem 0; }

.orb {
  position: relative;
  width: 148px; height: 148px;
  border-radius: 50%;
  border: 1px solid var(--ink-edge);
  background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--clay) 14%, transparent), color-mix(in srgb, var(--ink-raised) 90%, transparent) 68%);
  display: grid; place-items: center;
  cursor: pointer;
  transition: transform var(--settle), box-shadow var(--settle), border-color var(--settle);
}
.orb:hover { border-color: color-mix(in srgb, var(--clay) 40%, transparent); }
.orb .glyph { width: 22px; height: 22px; border-radius: 50%; background: var(--clay); box-shadow: 0 0 22px var(--clay-glow); transition: all var(--settle); }

.orb.armed { animation: held 4.2s ease-in-out infinite; border-color: color-mix(in srgb, var(--clay) 55%, transparent); box-shadow: 0 0 0 0 var(--clay-glow); }
.orb.armed .glyph { width: 18px; height: 18px; border-radius: var(--r-sm); background: var(--clay); }

@keyframes held {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 0 0     var(--clay-glow); }
  50%      { transform: scale(1.045); box-shadow: 0 0 0 22px color-mix(in srgb, var(--clay) 0%, transparent); }
}

.timer { font-family: var(--serif); font-size: var(--t-6); color: var(--mist-soft); font-variant-numeric: tabular-nums; }

/* Playback, built rather than borrowed.

   The browser's own player is a grey plastic widget from another building, and
   it lets you drag past the part you're meant to hear. This one has a play
   button and a line that fills. There is no scrubber, on purpose: the only way
   through the listen-back gate is to actually listen. */

.tape { width: 100%; }

.tape video {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  border-radius: var(--r-lg); background: var(--ink-deep); display: block; margin-bottom: 0.9rem;
}

.tape-row { display: flex; align-items: center; gap: var(--s-4); }

.tape-play {
  flex: 0 0 auto; width: 52px; height: 52px; border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--clay) 40%, transparent);
  background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--clay) 16%, transparent), color-mix(in srgb, var(--ink-raised) 90%, transparent) 70%);
  color: var(--clay); cursor: pointer; display: grid; place-items: center;
  transition: border-color var(--touch), transform var(--touch);
}
.tape-play:hover { border-color: color-mix(in srgb, var(--clay) 70%, transparent); }
.tape-play:active { transform: scale(0.96); }

/* The unfilled track was --ink-edge (#232A33) on --ink (#0F1216) — about 1.1:1.
   WCAG 1.4.11 asks 3:1 for a functional non-text indicator, and this is the
   progress bar on the listen-back gate: the one screen the whole product turns
   on. You could not see how far through your own recording you were.
   --mist-faint clears it at 5.1:1 and still reads as a whisper. */
.tape-track {
  flex: 1; height: 3px; background: var(--track); border-radius: var(--r-pill); overflow: hidden;
  position: relative;
}
/* Locked until you've heard it through. The change is deliberately small — a
   slightly taller bar, a handle, a grab cursor — because it should read as a
   permission quietly granted, not a new control arriving with fanfare. */
.tape.seekable .tape-track {
  height: 6px; border-radius: var(--r-pill); cursor: grab; touch-action: none;
}
.tape.seekable .tape-track:active { cursor: grabbing; }
.tape.seekable .tape-track::after {
  content: ''; position: absolute; top: 50%; right: -1px;
  width: 12px; height: 12px; margin-top: -6px;
  border-radius: 50%; background: var(--clay);
  transform: translateX(50%); pointer-events: none;
  left: var(--at, 0%);
}
.tape.seekable .tape-track:focus-visible {
  outline: 2px solid var(--slate); outline-offset: 3px;
}
.tape-track i {
  display: block; height: 100%; width: 0%;
  background: var(--clay); border-radius: var(--r-pill);
  transition: width 220ms linear;
}
.tape-time {
  flex: 0 0 auto; font-variant-numeric: tabular-nums;
  font-size: var(--t-2); color: var(--mist-faint); min-width: 3.2rem; text-align: right;
}
.tape.playing .tape-play { box-shadow: 0 0 0 6px var(--clay-glow); }
video.preview { width: 100%; aspect-ratio: 3/4; object-fit: cover; border-radius: var(--r-md); background: var(--ink-deep); transform: scaleX(-1); }

.gate {
  display: flex; align-items: center; gap: var(--s-3);
  font-size: var(--t-3); color: var(--mist-faint);
}
.gate .tick { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--ink-edge); flex: 0 0 auto; transition: all var(--settle); }
.gate.done { color: var(--slate); }
.gate.done .tick { background: var(--slate); border-color: var(--slate); box-shadow: 0 0 14px var(--slate-glow); }

/* the exhale on approve */
.exhale { position: fixed; inset: 0; pointer-events: none; z-index: 60; display: grid; place-items: center; }
.exhale i {
  width: 120px; height: 120px; border-radius: 50%;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--clay) 0%, transparent) 52%,
    color-mix(in srgb, var(--clay) 20%, transparent) 66%,
    color-mix(in srgb, var(--clay) 0%, transparent) 82%);
  filter: blur(6px);
  animation: exhale 2.4s cubic-bezier(0.16, 0.9, 0.3, 1) forwards;
}
@keyframes exhale {
  from { transform: scale(0.35); opacity: 0.95; }
  to   { transform: scale(9);    opacity: 0; }
}

/* ---------------------------------------------------------------- together */

.trend { width: 100%; height: 130px; display: block; }
.legend { display: flex; gap: var(--s-4); flex-wrap: wrap; }
.legend span { display: inline-flex; align-items: center; gap: var(--s-2); font-size: var(--t-2); color: var(--mist-faint); }
.legend i { width: 10px; height: 2px; background: var(--clay); border-radius: 2px; }

.entry { display: flex; gap: var(--s-4); padding: 0.85rem 0; border-bottom: 1px solid var(--ink-edge); }
.entry:last-child { border-bottom: 0; }
.entry .when { flex: 0 0 4.5rem; color: var(--mist-faint); font-size: var(--t-2); padding-top: 0.15rem; }

/* ------------------------------------------------------------------ sheets */

.veil {
  position: fixed; inset: 0; background: var(--veil);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  z-index: 80; display: flex; align-items: flex-end; justify-content: center;
  animation: fade var(--settle) both;
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.sheet {
  width: 100%; max-width: var(--measure);
  background: var(--ink-raised);
  border: 1px solid var(--ink-edge);
  border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding: 1.5rem var(--gutter) calc(1.75rem + env(safe-area-inset-bottom));
  animation: rise var(--breath) both;
  max-height: 88svh; overflow-y: auto;
}
@keyframes rise { from { transform: translateY(28px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ------------------------------------------------------------------ notice */

.notice {
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
  background: color-mix(in srgb, var(--warn) 7%, transparent);
  border-radius: var(--r-md); padding: 0.85rem 1rem; font-size: var(--t-3); color: var(--warn-ink);
}
.notice.bad { border-color: color-mix(in srgb, var(--clay) 40%, transparent); background: color-mix(in srgb, var(--clay) 8%, transparent); color: var(--bad-ink); }

/* ------------------------------------------------------------------- misc */

.center { text-align: center; }
.hidden { display: none !important; }
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.footer {
  margin-top: 2rem; padding-top: 1.25rem;
  border-top: 1px solid var(--ink-edge);
  display: flex; justify-content: space-between; align-items: center; gap: var(--s-4);
}

/* ------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .screen, .msg, .sheet, .veil { animation: none; }
}

/* ===================================================== the redesign (Oct 2026)

   Lighter, airier, findable. Everything below overrides what came before
   rather than editing it in place, so the old rules still read as the record
   of what production taught the room. */

:root { --measure: 36rem; --radius: 18px; --r-md: 14px; --tabbar-h: 0px; }
@media (min-width: 900px) { :root { --measure: 40rem; } }

.card { box-shadow: var(--shadow); border-color: var(--ink-edge); }
.space-wrap {
  background: transparent;
  border: 1px solid transparent;
  background-image: linear-gradient(var(--ink-deep), var(--ink-deep)), var(--grad-edge);
  background-origin: border-box; background-clip: padding-box, border-box;
  box-shadow: var(--shadow);
  height: 190px;
}
.space-wrap.hero { height: clamp(200px, 34vh, 280px); }
:root:not([data-theme="dark"]) .space-wrap {
  background-image:
    radial-gradient(120% 90% at 20% 0%, rgba(220, 206, 248, 0.9), transparent 60%),
    radial-gradient(110% 90% at 90% 100%, rgba(204, 226, 248, 0.9), transparent 60%),
    linear-gradient(#F3F1F8, #F3F1F8), var(--grad-edge);
  background-clip: padding-box, padding-box, padding-box, border-box;
}

/* Buttons: the primary one is the only solid thing on the screen. */
.btn { background: var(--ink-raised); border-color: var(--edge-control); border-radius: var(--r-md); min-height: 48px; }
.btn.primary, .pinned-action {
  background: var(--grad-primary);
  border: 0;
  color: var(--on-accent);
  font-weight: 600;
  box-shadow: 0 6px 18px color-mix(in srgb, var(--clay) 28%, transparent);
}
.btn.primary:hover, .pinned-action:hover { background: var(--grad-primary); filter: brightness(1.06) saturate(1.05); }
.btn.ghost { background: transparent; }
.field { background: var(--ink-field); border-radius: var(--r-md); }
.notice.good { border-color: color-mix(in srgb, var(--slate) 45%, transparent); background: color-mix(in srgb, var(--slate) 10%, transparent); color: var(--mist); }

/* ------------------------------------------------------------- top bar */
.topbar {
  position: sticky; top: 0; z-index: 30;
  margin: calc(-1 * max(1.25rem, env(safe-area-inset-top))) calc(-1 * var(--gutter)) 0.5rem;
  padding: max(0.6rem, env(safe-area-inset-top)) var(--gutter) 0.6rem;
  background: color-mix(in srgb, var(--ink) 78%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.2); backdrop-filter: blur(14px) saturate(1.2);
  border-bottom: 1px solid color-mix(in srgb, var(--ink-edge) 70%, transparent);
  min-height: 3.5rem;
}
.mark { color: var(--mist); font-size: var(--t-5); font-weight: 400; gap: 0.5rem; }
.koi-mark { width: 22px; height: 22px; color: var(--clay); flex: none; }
.topbar .back { font-size: var(--t-3); text-decoration: none; color: var(--mist-soft); }
.room-switch {
  display: inline-flex; align-items: center; gap: 0.5rem;
  min-height: 44px; max-width: 60vw; padding: 0.35rem 0.85rem 0.35rem 0.6rem;
  border-radius: var(--r-pill); border: 1px solid var(--edge-control);
  background: var(--ink-raised); color: var(--mist); cursor: pointer;
  font-family: var(--serif); font-size: var(--t-4); box-shadow: var(--shadow);
}
.room-switch-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.room-switch .caret { color: var(--mist-faint); font-size: 0.7em; }
.help-btn {
  min-height: 44px; padding: 0 0.9rem; border-radius: var(--r-pill);
  border: 1px solid color-mix(in srgb, var(--pink) 55%, var(--edge-control));
  background: transparent; color: var(--mist); font-size: var(--t-2); font-weight: 500; cursor: pointer;
}

/* ------------------------------------------------------------- tab bar
   In the top bar on a wide screen; under the thumb on a phone. */
.tabbar { display: flex; gap: 0.25rem; }
.tab {
  display: inline-flex; align-items: center; gap: 0.4rem;
  min-height: 44px; padding: 0 0.8rem; border-radius: var(--r-pill);
  border: 0; background: transparent; color: var(--mist-soft);
  font-size: var(--t-2); font-weight: 500; cursor: pointer;
}
.tab svg { width: 20px; height: 20px; }
.tab:hover { color: var(--mist); background: var(--ink-hover); }
.tab.on { color: var(--accent-ink); background: color-mix(in srgb, var(--clay) 14%, transparent); }
.tab:focus-visible, .room-switch:focus-visible, .help-btn:focus-visible, .room-open:focus-visible, .seg-b:focus-visible {
  outline: 2px solid var(--slate); outline-offset: 2px;
}

.tabbar.bottom { display: none; }
@media (max-width: 719px) {
  :root { --tabbar-h: calc(64px + env(safe-area-inset-bottom)); }
  .tabbar.top { display: none; }
  .tabbar.bottom {
    display: flex;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    height: var(--tabbar-h); padding: 6px 8px env(safe-area-inset-bottom);
    justify-content: space-around;
    background: color-mix(in srgb, var(--ink-raised) 88%, transparent);
    -webkit-backdrop-filter: blur(16px) saturate(1.2); backdrop-filter: blur(16px) saturate(1.2);
    border-top: 1px solid var(--ink-edge);
  }
  .tab { flex: 1; flex-direction: column; gap: 2px; padding: 4px 0; border-radius: 12px; font-size: var(--t-1); min-height: 52px; }
  .has-nav { padding-bottom: var(--tabbar-h); }
  body:has(#cx-tabbar) .pin { bottom: var(--tabbar-h); }
  .topbar .mark span { font-size: var(--t-4); }
}

/* ------------------------------------------------------------- stepper */
.stage { display: flex; flex-direction: column; gap: 0.4rem; }
.stepper { list-style: none; margin: 0; padding: 0; display: flex; gap: 0.35rem; }
.stepper li {
  flex: 1; display: flex; flex-direction: column; gap: 0.35rem;
  font-size: var(--t-1); color: var(--mist-faint); letter-spacing: 0.02em;
}
.stepper li::before {
  content: ''; height: 4px; border-radius: 4px; background: var(--ink-edge);
}
.stepper li.done::before { background: var(--slate); }
.stepper li.now::before { background: var(--grad-primary); }
.stepper li.now { color: var(--mist); font-weight: 600; }
.stepper .st-dot { display: none; }
.stepper .st-name { line-height: 1.25; }

/* ------------------------------------------------------------- rooms */
.room-list { display: flex; flex-direction: column; gap: 0.75rem; }
.room-row { display: flex; flex-direction: column; gap: 0.25rem; }
.room-row .room-rename { align-self: flex-end; margin: 0 0.25rem 0 0; padding: 0.5rem 0.3rem; }
.room-open {
  display: flex; align-items: center; gap: 0.9rem; width: 100%; text-align: left;
  min-height: 72px; padding: 0.9rem 1rem; cursor: pointer;
  border-radius: var(--radius); border: 1px solid var(--ink-edge);
  background: var(--ink-raised); color: var(--mist); box-shadow: var(--shadow);
  transition: border-color var(--touch), transform var(--touch);
}
.room-open:hover { border-color: var(--edge-control); }
.room-open:active { transform: translateY(1px); }
.room-row.here .room-open {
  border-color: transparent;
  background-image: linear-gradient(var(--ink-raised), var(--ink-raised)), var(--grad-edge);
  background-origin: border-box; background-clip: padding-box, border-box;
}
.room-koi {
  width: 40px; height: 40px; flex: none; border-radius: 50%;
  background: var(--grad-edge); opacity: 0.85;
}
.room-text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.room-title { font-family: var(--serif); font-size: var(--t-5); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.room-sub { font-size: var(--t-2); color: var(--mist-faint); }
.room-go { color: var(--mist-faint); font-size: 1.5rem; }

/* ------------------------------------------------------------- forms */
.pw { position: relative; }
.pw .field { padding-right: 4.5rem; }
.pw .pw-eye { position: absolute; right: 0.9rem; top: 50%; transform: translateY(-50%); margin: 0; padding: 0 0.3rem; text-decoration: none; font-weight: 500; }
.seg { display: flex; gap: 0.35rem; padding: 0.25rem; border-radius: var(--r-pill); background: var(--ink-lift); border: 1px solid var(--ink-edge); }
.seg-b { flex: 1; min-height: 44px; border: 0; border-radius: var(--r-pill); background: transparent; color: var(--mist-soft); font-size: var(--t-2); font-weight: 500; cursor: pointer; }
.seg-b[aria-checked="true"] { background: var(--ink-raised); color: var(--mist); box-shadow: var(--shadow); }
details.more > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; gap: 0.35rem; color: var(--mist-soft); font-size: var(--t-3); }
details.more > summary::marker { color: var(--clay); }
h2.meta { margin: 0; }

@media (prefers-reduced-motion: reduce) { .room-open, .btn { transition: none; } }
.topbar-right { flex-wrap: nowrap; }
.mark { white-space: nowrap; }
@media (min-width: 720px) {
  /* The bar spans the window; the reading column stays narrow beneath it. */
  .topbar {
    margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
    padding-left: max(var(--gutter), calc(50vw - 32rem));
    padding-right: max(var(--gutter), calc(50vw - 32rem));
  }
}
html { overflow-x: clip; }
/* A turn with no transcript yet ("Tap play to listen.") shrank to fit those
   four words, and its scrubber collapsed to zero width — present, and
   impossible to touch. Turns are a fixed share of the line, whoever's they are. */
.convo .turn { width: 92%; }
