/* pod-record — component styles. The "Tape" system.
 *
 * RULE: no raw hex, no raw px font size, no raw spacing number in this file. Everything comes from
 * tokens.css. If you need a value that isn't a token, add the token — don't hardcode it here. That
 * is what makes a drastic restyle a one-file edit instead of an archaeology project.
 * `npm run test:contrast` fails the build if a raw hex appears below.
 *
 * The organising idea: the page is paper, the video pane is the only dark surface, and colour is
 * reserved for exactly three meanings — safe / rolling / in flight. Everything else is ink.
 */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  padding: var(--space-6) var(--space-5) var(--space-8);
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: var(--leading-body);
  color: var(--ink);
  background: var(--bg);
}

.rig { max-width: var(--content-max); margin: 0 auto; }

/* Visible only to screen readers. Carries the meaning that colour and glyphs alone would lose. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* 2.4.7 / 2.4.13 — one focus style everywhere, always visible, never removed. */
:focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-sm);
}

/* Headings carry tabindex="-1" purely so a stage change can move the screen reader to them. They
   are not interactive and never in the tab order, so a focus ring on them is visual noise that
   reads as "this is a control". The announcement still happens. */
h1[tabindex="-1"]:focus, h1[tabindex="-1"]:focus-visible { outline: none; }

a { color: var(--accent); text-underline-offset: 3px; }

/* ── Type ─────────────────────────────────────────────────────────────────────────────
 * Tight tracking at display sizes is what makes the headline read as equipment rather than a
 * magazine. One family throughout; mono is reserved for values you might read aloud. */
h1 {
  font-family: var(--font-display);
  font-size: var(--text-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  margin: 0 0 var(--space-3);
  font-weight: var(--weight-bold);
}

h2 {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-heading);
  margin: 0 0 var(--space-3);
}

/* A step between --text-2xl and the fluid display size, for screens whose heading is a title
   rather than a promise — the room name, the library. Derived, so it moves with --text-base. */
.h-mid { font-size: calc(var(--text-2xl) * 1.4); line-height: 1.08; letter-spacing: var(--tracking-display); }

.sub { color: var(--ink-muted); margin: 0 0 var(--space-5); max-width: var(--measure); }
/* A small line ABOVE a heading — the session you are about to join, the context before the ask. */
.eyebrow {
  font-family: var(--font-mono); font-size: var(--text-sm); color: var(--ink-muted);
  margin: 0 0 var(--space-2); letter-spacing: var(--tracking-wide);
}
.note { color: var(--ink-muted); font-size: var(--text-sm); margin: var(--space-3) 0 0; }
.label { font-size: var(--text-sm); color: var(--ink-muted); }

/* Numbers only: timecode, room codes, part counts, latency, sizes. Digits must not shift under a
   glance taken mid-interview. */
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ── Brand ────────────────────────────────────────────────────────────────────────────
 * A cassette reduced to its truth: two hubs = two people = two independent recordings. */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: var(--border-width) solid var(--border);
  margin: calc(var(--space-6) * -1) calc(var(--space-5) * -1) var(--space-7);
  background: var(--bg);
}
.brand {
  display: inline-flex; align-items: center; gap: var(--space-3);
  color: var(--ink); text-decoration: none;
}
.brand svg { display: block; }
.wordmark {
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wordmark);
}
/* 2.5.5 — these are navigation targets sitting on their own in a bar, not links inside a
   sentence, so they get the full 44px. The bar's own padding is not enough on its own. */
.topbar a { display: inline-flex; align-items: center; min-height: var(--tap-min); }
.topbar a:not(.brand) { color: var(--ink-muted); text-decoration: none; font-size: var(--text-sm); }
.topbar a:not(.brand):hover { color: var(--ink); text-decoration: underline; }

/* ── Hairline rows — the house list ───────────────────────────────────────────────────
 * No numbers, no icons, no boxes. A rule between each line is enough structure. */
.rows { display: flex; flex-direction: column; margin: var(--space-5) 0; }
.rows > li, .rows > .row {
  padding: var(--space-4) 0;
  border-top: var(--border-width) solid var(--border);
  line-height: 1.5;
}
.rows > li:last-child, .rows > .row:last-child { border-bottom: var(--border-width) solid var(--border); }
ul.rows { list-style: none; padding: 0; }
.rows .muted { color: var(--ink-muted); }

/* A row with a label on the left and a mono value hard right. */
.row-split { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.row-split > .val { font-family: var(--font-mono); color: var(--ink-muted); text-align: right; white-space: nowrap; }

/* ── Status pill — always visible, always honest ──────────────────────────────────────
 * Fill vs outline carries meaning, and it is deliberate:
 *   SOLID   = act now, or do not move (rolling / in flight / safe to close)
 *   OUTLINE = know this (connection lost, reconnecting, not ready, checking)
 * The recording is still safe in every outline state, so a solid alarm would overstate it. */
.pill {
  display: inline-flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  font-weight: var(--weight-bold);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-wide);
  margin-bottom: var(--space-5);
  border: var(--border-width) solid var(--border-strong);
  background: var(--surface);
  color: var(--ink-muted);
  min-height: var(--tap-min);
}
/* Outline states — coloured edge and ink, paper behind. */
.pill.idle  { color: var(--ink-muted); border-color: var(--border-strong); }
.pill.ready { color: var(--accent); border-color: var(--accent); }
.pill.lost  { color: var(--danger); border-color: var(--danger); }
/* Solid states — white on the signal colour. */
.pill.rec   { color: var(--ink-inverse); background: var(--danger);  border-color: var(--danger); }
.pill.up    { color: var(--ink-inverse); background: var(--pending); border-color: var(--pending); }
.pill.safe  { color: var(--ink-inverse); background: var(--safe);    border-color: var(--safe); }

/* The dot pulses only while rolling. Everything else in this interface is still. */
.pill-dot {
  width: var(--space-2); height: var(--space-2); border-radius: 50%;
  background: currentColor; flex: none;
}
.pill.rec .pill-dot { animation: blip 1.4s ease-in-out infinite; }

/* Elapsed time rides inside the pill, behind a hairline divider. */
.pill-time {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  padding-left: var(--space-3);
  margin-left: var(--space-1);
  border-left: var(--border-width) solid currentColor;
}

@keyframes blip { 0%, 100% { opacity: 1 } 50% { opacity: .3 } }

/* ── The part ledger ──────────────────────────────────────────────────────────────────
 * One segment per chunk. A progress bar says "60%"; it does not say what is SAFE. This says
 * exactly how many pieces of the interview the server is holding, and how many are still only on
 * a laptop that could shut. Same component in the call bar, the finish screen and the library, so
 * what a host learns to read in ten seconds keeps meaning the same thing forever.
 *
 * The "not yet sent" segment MUST stay an outline. A pale fill measures ~1.2:1 against the page
 * and vanishes — and the "nothing was recorded" screen is made entirely of those segments. */
.ledger { display: flex; gap: var(--ledger-gap-x); height: var(--ledger-height); align-items: stretch;
          justify-content: flex-start; }
/* The max-width is what keeps this a component you READ. Unbounded, a two-part recording renders
   as two 158px slabs — which is a progress bar again, the exact thing this replaced. Bounded, two
   parts look like two parts and forty still fill the strip. */
.ledger .seg { flex: 1 1 0; border-radius: var(--ledger-radius); min-width: 2px; max-width: 26px; }
.ledger .seg.is-safe   { background: var(--ledger-safe); }
.ledger .seg.is-flight { background: var(--ledger-flight); animation: blip 1.4s ease-in-out infinite; }
.ledger .seg.is-flight:nth-child(even) { animation-delay: .2s; }
.ledger .seg.is-gap    { background: var(--ledger-gap); }
.ledger .seg.is-empty  { background: transparent; border: var(--border-width) solid var(--ledger-empty); }
.ledger.sm { height: var(--ledger-height-sm); }
.ledger.xs { height: var(--space-2); }

/* Always in words as well as in colour (1.4.1). */
.ledger-count { font-size: var(--text-sm); color: var(--ink-muted); margin: var(--space-2) 0 0; }
.ledger-count .safe { color: var(--accent); font-family: var(--font-mono); }

@media (prefers-reduced-motion: reduce) {
  .ledger .seg.is-flight, .pill.rec .pill-dot { animation: none; }
}

/* ── Buttons ──────────────────────────────────────────────────────────────────────────
 * Default is an outline control on paper. Primary is ink. Record is the only red. */
.controls { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-4); }

.btn {
  font: inherit;
  font-weight: var(--weight-medium);
  padding: var(--space-3) var(--space-4);
  min-height: var(--control-h);
  min-width: var(--tap-min);
  border-radius: var(--radius-md);
  border: var(--border-width) solid var(--border-strong);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  text-decoration: none;
  transition: background var(--motion-fast) var(--motion-ease),
              color var(--motion-fast) var(--motion-ease),
              border-color var(--motion-fast) var(--motion-ease);
}
.btn:hover:not(:disabled) { background: var(--ink); color: var(--ink-inverse); border-color: var(--ink); }
/* 1.4.3 exempts inactive controls from contrast, but half-invisible is still bad UI. */
.btn:disabled {
  cursor: not-allowed;
  background: var(--surface-sunken);
  color: var(--ink-muted);
  border-color: var(--border-strong);
}
.btn.primary {
  background: var(--ink); color: var(--ink-inverse); border-color: var(--ink);
  min-height: var(--control-h-lg); font-size: var(--text-lg);
}
.btn.primary:hover:not(:disabled) { background: var(--neutral-deep); }
.btn.accent { background: var(--accent); color: var(--ink-inverse); border-color: var(--accent); }
.btn.accent:hover:not(:disabled) { background: var(--ink); border-color: var(--ink); }
.btn.danger { border-color: var(--danger); color: var(--danger); }
.btn.danger:hover:not(:disabled) { background: var(--danger); color: var(--ink-inverse); }
.btn.danger-ghost { border-color: var(--border-strong); color: var(--danger); background: var(--surface); }
.btn.danger-ghost:hover:not(:disabled) { background: var(--danger); color: var(--ink-inverse); border-color: var(--danger); }
.btn.ghost { border-color: var(--border-strong); color: var(--ink-muted); }
.btn.ghost:hover:not(:disabled) { background: var(--ink); color: var(--ink-inverse); border-color: var(--ink); }
.btn.wide { width: 100%; margin-top: var(--space-2); text-align: center; }
/* The only red button in the product. Stopping is ink — it is not an alarm, it is an intention. */
.btn.rec { background: var(--danger); border-color: var(--danger); color: var(--ink-inverse); }
.btn.rec:hover:not(:disabled) { background: var(--ink); border-color: var(--ink); }
.btn.rec.stop { background: var(--danger); border-color: var(--danger); }
.btn.small { font-size: var(--text-sm); padding: var(--space-2) var(--space-3); min-height: var(--tap-min); }

/* The glyph inside the record / stop button: a circle to start, a square to stop. */
.btn-glyph { width: var(--space-3); height: var(--space-3); background: currentColor; flex: none; }
.btn-glyph.round { border-radius: 50%; }

/* ── Fields ───────────────────────────────────────────────────────────────────────────*/
.field { margin: var(--space-4) 0; text-align: left; }
.field label {
  display: block; font-size: var(--text-sm); font-weight: var(--weight-normal);
  margin-bottom: var(--space-2); color: var(--ink-muted);
}
.field select, .field input, .linkrow input {
  width: 100%; font: inherit; padding: var(--space-3) var(--space-4);
  min-height: var(--control-h);
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--surface); color: var(--ink);
}
.field input::placeholder, .linkrow input::placeholder { color: var(--ink-placeholder); }

.panel {
  background: var(--surface);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
}

video {
  width: 100%;
  border-radius: var(--radius-lg);
  background: var(--surface-inverse);
  aspect-ratio: 16 / 9;
  display: block;
}

/* Kept for loop1.html, the dev rig — not a product surface. */
.bar, .meter {
  height: var(--space-3);
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
#barFill { height: 100%; width: 0; background: var(--safe); transition: width var(--motion-base) var(--motion-ease); }

.stats { margin: var(--space-3) 0 0; font-size: var(--text-sm); }
.net { color: var(--safe); font-weight: var(--weight-medium); }
.net.bad { color: var(--danger); }

pre#log {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.7;
  max-height: 320px;
  overflow: auto;
  margin: 0;
  white-space: pre-wrap;
  color: var(--ink);
}

/* ── Room stages ──────────────────────────────────────────────────────────────────────*/

/* MUST come before any author `display` rule on a hideable element.
   `[hidden] { display: none }` lives in the UA stylesheet at the lowest precedence, so ANY author
   display rule (like `.stage { display: flex }` below) silently beats it and every stage renders
   at once. Learned the hard way — the lobby, the browser gate, and the call all stacked. */
[hidden] { display: none !important; }

.room-body { padding: 0; min-height: 100vh; }

.stage {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  /* Top padding clears the fixed status pill. Without it the pill sits on top of the heading on
     short viewports — and the pill is the one element that must always be readable. */
  padding: var(--space-8) var(--space-4) var(--space-5);
}

.card { width: 100%; max-width: var(--card-max); }
.card.narrow { max-width: var(--card-narrow-max); }
.card h1 { font-size: var(--text-xl); }

/* Centred WITHOUT `left: 50%` + a transform. An absolutely positioned box with `left: 50%` and
   `right: auto` shrink-to-fits against (container − 50%), so on a 375px screen the most important
   element in the product had 176px to work with and wrapped "Recording — both sides · 00:09" onto
   three lines. Auto margins between left:0 and right:0 centre it against the FULL width. */
.pill.floating {
  position: fixed; top: var(--space-5); left: 0; right: 0;
  margin: 0 auto; width: fit-content;
  z-index: 50; max-width: calc(100% - var(--space-6));
}

/* ── The green room ───────────────────────────────────────────────────────────────────*/
.greenroom {
  display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--space-7);
  width: 100%; max-width: 940px; align-items: start;
}
.greenroom .preview-col { display: flex; flex-direction: column; gap: var(--space-4); }
.preview-frame { position: relative; border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-inverse); }
.preview-frame video { border-radius: 0; }
.preview-none {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--ink-on-dark); font-size: var(--text-sm);
}

/* The mic meter reads as an instrument, not a loading bar: 14 discrete lit segments.
   #micFill is still a plain width-driven bar underneath — the gaps are painted on top in the page
   colour, so the controller keeps setting one number and knows nothing about segments. */
.mic-row { display: flex; align-items: center; gap: var(--space-3); }
.mic-meter {
  position: relative; flex: 1; height: var(--ledger-height);
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden; background: var(--surface);
}
.mic-meter > .fill { height: 100%; width: 0; background: var(--accent); transition: width var(--motion-fast) linear; }
.mic-meter::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(to right,
    transparent 0 calc(100% / 14 - 3px), var(--surface) calc(100% / 14 - 3px) calc(100% / 14));
}

.checks { list-style: none; padding: 0; margin: var(--space-5) 0; font-size: var(--text-md); text-align: left; }
.checks li {
  display: flex; align-items: baseline; gap: var(--space-3);
  padding: var(--space-3) 0;
  border-top: var(--border-width) solid var(--border);
  line-height: 1.45;
}
.checks li:last-child { border-bottom: var(--border-width) solid var(--border); }
.checks li .glyph { flex: none; width: var(--space-4); color: var(--ink-muted); }
.checks li .val { margin-left: auto; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--ink-muted); white-space: nowrap; }
.checks li.good .glyph { color: var(--accent); }
.checks li.bad { color: var(--danger); }
.checks li.bad .glyph { color: var(--danger); }

/* Notices are a rule and a coloured left edge, never a filled box. A yellow panel reads as an
   error page; this reads as a margin note, which is what these actually are. */
.warn {
  border-left: var(--space-1) solid var(--notice-border);
  color: var(--ink);
  padding: var(--space-3) 0 var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  margin-top: var(--space-4);
  text-align: left;
}
.warn strong { display: block; color: var(--notice-ink); }

.linkrow { display: flex; gap: var(--space-2); margin: var(--space-3) 0; }
.linkrow input { flex: 1; font-family: var(--font-mono); font-size: var(--text-sm); }

/* The room code, said down a phone. */
.roomcode {
  font-family: var(--font-mono);
  font-size: calc(var(--text-2xl) * 1.55);
  font-weight: var(--weight-medium);
  letter-spacing: 0.12em;
  line-height: 1;
  display: block;
}

/* "Room is live · nobody has joined yet" */
.liveline { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--accent); font-size: var(--text-sm); }
.liveline::before { content: ''; width: var(--space-2); height: var(--space-2); border-radius: 50%; background: currentColor; }

/* ── The call ─────────────────────────────────────────────────────────────────────────
 * The page stays paper; the video pane is a dark inset. This is not dark mode — faces read wrong
 * on grey, and every recording tool in the category does the same thing. */
/* align-items must be stretch, not the .stage default of center: the pane sizes itself from its
   margins, so a centred flex child collapses to the width of the video inside it. */
.call-stage { flex-direction: column; padding: 0; justify-content: stretch; align-items: stretch; }

.videos {
  position: relative; flex: 1; width: 100%;
  background: var(--surface-inverse);
  min-height: 60vh;
  margin: var(--space-5) var(--space-5) 0;
  width: auto;
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.videos .remote { width: 100%; height: 100%; object-fit: contain; aspect-ratio: auto; border-radius: 0; }
/* ── The self view, as a movable object ───────────────────────────────────────────────
 * It starts bottom-right, which is where every video tool puts it, and then gets out of the way
 * on request: drag it anywhere in the pane, drag the grip to resize. The default is CSS; the
 * moment the user touches it, JS writes left/top/width as PERCENTAGES of the pane, so a stored
 * position survives a window resize and a rotation instead of stranding the box off-screen.
 *
 * It sits under .countdown (z-index 10) on purpose — the 3-2-1 owns the pane while it runs. */
.self-pip {
  position: absolute; right: var(--space-4); bottom: var(--space-4);
  width: 22%; max-width: 280px; min-width: 120px;
  z-index: 5;
  border-radius: var(--radius-md);
  /* A hairline against the video behind it. Without an edge, a dark self-view on a dark pane
     stops looking like an object you can pick up. */
  box-shadow: 0 0 0 var(--border-width) rgb(255 255 255 / .3);
  cursor: grab;
  /* Without this the browser claims the gesture for scrolling and the drag never starts on touch. */
  touch-action: none;
}
.self-pip.is-dragging { cursor: grabbing; }
.self-pip .self {
  width: 100%; display: block;
  border-radius: var(--radius-md); border: none;
  object-fit: cover; aspect-ratio: 16/9;
}

/* 2.5.5 — the grip is a full 44px target with a small glyph inside it, not a 12px corner nub.
   The scrim is what makes it legible over an arbitrary video frame; white alone disappears on a
   bright shirt. */
.pip-grip {
  position: absolute; left: 0; top: 0;
  width: var(--tap-min); height: var(--tap-min);
  padding: 0; margin: 0; border: none;
  display: grid; place-items: center;
  background: rgb(0 0 0 / .45);
  color: var(--ink-inverse);
  border-radius: var(--radius-md) 0 0 0;
  cursor: nwse-resize;
  /* Quiet at rest. This sits in the corner of a face for 60 minutes; it should be findable, not
     something you keep noticing. It comes up to full on hover and on focus. */
  opacity: .4;
  transition: opacity var(--motion-fast) var(--motion-ease);
}
.pip-grip::before {
  content: '';
  width: var(--space-3); height: var(--space-3);
  border-left: 2px solid currentColor; border-top: 2px solid currentColor;
  border-top-left-radius: 3px;
}
.self-pip:hover .pip-grip, .pip-grip:focus-visible { opacity: 1; }
/* No hover on touch, so the grip has to be visible without one. */
@media (pointer: coarse) { .pip-grip { opacity: 1; } }
/* DELETED: `.videos .pill.floating`. It carried a confident comment — "the pill sits inside the
   pane on the call screen" — for a selector that has never matched anything. `#pill` is a sibling
   of the stages, not a child of `.videos` (r.html line 17), so the rule was inert and the comment
   was describing an intention as though it were behaviour.
   What actually happens is fine: the pill is `position: fixed` near the top of the viewport, which
   on the call screen lands it over the pane anyway, and its z-index of 50 keeps it clear of the
   draggable self view at 5 — so no amount of dragging can cover the one element that must always
   be readable. That relationship is asserted by tests/test-pip.js rather than left to a comment. */

.namechip {
  position: absolute; left: var(--space-4); bottom: var(--space-4);
  font-size: var(--text-sm); font-weight: var(--weight-medium);
  color: var(--ink-inverse); background: rgb(0 0 0 / .5);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
}
.waiting {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: var(--space-3);
  color: var(--ink-on-dark); font-size: var(--text-md); text-align: center; padding: var(--space-5);
}
.waiting strong { color: var(--ink-inverse); font-size: var(--text-xl); font-weight: var(--weight-bold); }
.waiting p { margin: 0; max-width: 44ch; color: var(--ink-on-dark-dim); font-size: var(--text-sm); }

/* 3-2-1. It exists to kill the "wait, are we rolling?" opening that every host edits out. */
.countdown {
  position: absolute; inset: 0; z-index: 10;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3);
  background: var(--surface-inverse); color: var(--ink-inverse); text-align: center;
}
.countdown .num {
  font-family: var(--font-mono); font-weight: var(--weight-medium);
  font-size: calc(var(--text-2xl) * 4.8); line-height: 1;
}
.countdown .lead { color: var(--ink-on-dark); font-size: var(--text-md); }
.countdown .tail { color: var(--ink-on-dark-dim); font-size: var(--text-sm); margin: 0; }

/* NOTE: named .callbar, not .bar — loop1.html already uses .bar for the upload progress track,
   and a second .bar rule silently broke it. */
.callbar {
  display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
  padding: var(--space-4) var(--space-5);
  background: var(--bg);
  padding-bottom: max(var(--space-4), env(safe-area-inset-bottom));
}
/* The ledger is a component you read, not a bar that fills the room. Left it unbounded and two
   confirmed parts became two 500px slabs — which reads as a progress bar again. */
.callbar .status-col { display: flex; flex-direction: column; gap: var(--space-1); flex: 0 1 340px; min-width: 0; }
.callbar .ledger { max-width: 320px; }
.bar-actions { display: flex; gap: var(--space-3); margin-left: auto; }
.health { font-size: var(--text-sm); font-family: var(--font-mono); color: var(--ink-muted); }
.health.good { color: var(--ink-muted); }
.health.poor { color: var(--pending); }
.progress { font-size: var(--text-sm); color: var(--ink-muted); }

/* ── The finish screen ────────────────────────────────────────────────────────────────
 * The emotional peak: where someone finds out whether the thing they cannot re-record survived.
 * Every state answers, IN ITS FIRST LINE, whether it is safe to close the tab — in words, never
 * in colour alone (1.4.1). */
.finish { max-width: 640px; width: 100%; }

.finish-mark {
  width: var(--space-7); height: var(--space-7);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-md);
  font-size: var(--text-xl); line-height: 1;
  color: var(--ink-inverse); background: var(--border-strong);
  margin-bottom: var(--space-4);
}
.finish.working .finish-mark { background: var(--pending); }
.finish.safe .finish-mark    { background: var(--safe); }
.finish.broken .finish-mark  { background: var(--danger); }
.finish.empty .finish-mark   { background: var(--border-strong); }

.finish h1 { font-size: var(--text-display); }

/* Length · parts · total, in one rule-bounded row. Mono, because these are numbers a person
   checks twice. */
.finish-stats {
  display: flex; flex-wrap: wrap; gap: var(--space-7);
  padding: var(--space-5) 0;
  border-top: var(--border-width) solid var(--border);
  border-bottom: var(--border-width) solid var(--border);
  margin: var(--space-5) 0;
}
.finish-stats .stat { display: flex; flex-direction: column; gap: var(--space-1); }
.finish-stats .k { font-size: var(--text-sm); color: var(--ink-muted); }
.finish-stats .v { font-family: var(--font-mono); font-size: var(--text-xl); font-variant-numeric: tabular-nums; }
.finish-stats .v.is-safe { color: var(--accent); }
.finish-stats .v.is-short { color: var(--danger); }

.finish-count { font-size: var(--text-sm); color: var(--ink-muted); margin: var(--space-2) 0 var(--space-5); }

.finish-tracks, #peopleList {
  list-style: none; padding: 0; margin: 0 0 var(--space-5);
  font-size: var(--text-md); text-align: left;
}
.finish-tracks li, #peopleList li {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-4);
  padding: var(--space-3) 0;
  border-top: var(--border-width) solid var(--border);
}
.finish-tracks li:last-child, #peopleList li:last-child { border-bottom: var(--border-width) solid var(--border); }
.finish-tracks li.good, #peopleList li.good { color: var(--ink); }
/* The tick belongs INSIDE the label, not as a sibling of it. As a child of the li it becomes a
   third flex item and `space-between` pushes the label into the middle of the row. */
.finish-tracks li.good > span:first-child::before,
#peopleList li.good > span:first-child::before { content: '✓ '; color: var(--accent); }
.finish-tracks li.bad > span:first-child::before,
#peopleList li.bad > span:first-child::before { content: '! '; color: var(--pending); }
.finish-tracks li.bad, #peopleList li.bad { color: var(--pending); }
/* Mono is for the value only. The label is prose and reads as prose. */
.finish-tracks li > span:last-child, #peopleList li > span:last-child {
  color: var(--ink-muted); text-align: right; font-family: var(--font-mono); font-size: var(--text-sm);
}

.finish-people { margin-top: var(--space-5); text-align: left; }
.finish-people h2 { font-size: var(--text-md); }

/* The files, inline on the finish screen. This is the payoff, so it gets a rule above it and its
   own heading rather than being another row in the summary. */
.finish-files { margin-top: var(--space-5); text-align: left; }
.finish-files h2 { font-size: var(--text-md); }
.finish-files video { margin-bottom: var(--space-3); }
/* Reserved so the status line appearing does not shove the list down mid-read. */
.finish-files .note[role="status"] { min-height: 1.4em; margin-top: 0; }

.finish-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-5); }
.finish-actions .btn { flex: 1 1 auto; }
.finish-actions .btn.primary { flex: 2 1 auto; }

/* On the landing page the ✕ items are deliberate non-features, not failures.
   Red would read as "something is broken" for choices we are proud of. */
.checks.muted-x li.bad { color: var(--ink-muted); }
.checks.muted-x li.bad .glyph { color: var(--ink-muted); }

/* ── Sharing the invite ───────────────────────────────────────────────────────────────*/
.share-row { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-3) 0; }
.share-row .btn { flex: 1 1 0; min-width: 30%; text-align: center; }

.qr {
  width: 200px; height: 200px; background: var(--surface);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg); padding: var(--space-4);
}
.qr svg, .qr img { width: 100%; height: 100%; display: block; }

/* ── The recordings library ───────────────────────────────────────────────────────────*/
.rec-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-4); margin-bottom: var(--space-4);
}
.rec-head h2 { margin-bottom: var(--space-1); font-size: var(--text-xl); }
.rec-meta { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--ink-muted); }
.rec-state { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-1); white-space: nowrap; }
.rec-state .dot { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--accent); }
.rec-state .dot::before { content: ''; width: var(--space-2); height: var(--space-2); border-radius: 50%; background: currentColor; }
.rec-expiry { font-size: var(--text-sm); font-family: var(--font-mono); color: var(--ink-muted); }
.rec-expiry.soon { color: var(--pending); }

/* A track row that carries controls, not just a value. Shared by the library and the finish
   screen so a Play button is the same object in both places. */
.rec-card .finish-tracks li, .finish-files .finish-tracks li { align-items: center; }
.rec-card .finish-tracks em { color: var(--ink-muted); font-style: normal; }
.rec-card .finish-tracks li > span:last-child,
.finish-files .finish-tracks li > span:last-child {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; justify-content: flex-end;
}

.rec-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  margin-top: var(--space-5); padding-top: var(--space-4);
  border-top: var(--border-width) solid var(--border);
}
.rec-actions .btn.del { margin-left: auto; border-color: transparent; color: var(--ink-muted); background: transparent; }
.rec-actions .btn.del:hover { background: var(--danger); color: var(--ink-inverse); border-color: var(--danger); }
.rec-status { min-height: 1.2em; }

dialog {
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  max-width: min(720px, 92vw);
  background: var(--surface);
  color: var(--ink);
}
dialog::backdrop { background: rgb(0 0 0 / .55); }
dialog video { margin: var(--space-3) 0; }

/* The backup-track rescue notice. A coloured left edge, not a filled box — and it appears ONLY on
   the day the guest's own recording actually fell short. Shouting about the safety net every
   session trains the host to ignore it on the one day it matters. */
.rescue {
  border-left: var(--space-1) solid var(--pending);
  padding: var(--space-2) 0 var(--space-2) var(--space-4);
  margin-bottom: var(--space-5);
}
.rescue strong { color: var(--notice-ink); }
.rescue p { margin: var(--space-1) 0 0; font-size: var(--text-sm); color: var(--ink-muted); }

/* ── Responsive ───────────────────────────────────────────────────────────────────────
 * Single column below 900. No horizontal overflow at 375 — test-enforced. */
@media (max-width: 900px) {
  .greenroom { grid-template-columns: 1fr; gap: var(--space-5); }
}

@media (max-width: 600px) {
  body { padding: var(--space-5) var(--space-4) var(--space-7); }
  .topbar { margin: calc(var(--space-5) * -1) calc(var(--space-4) * -1) var(--space-6); padding: var(--space-3) var(--space-4); }
  .videos { margin: var(--space-3) var(--space-3) 0; }
  .self-pip { width: 32%; right: var(--space-3); bottom: var(--space-3); min-width: 96px; }
  .callbar { padding: var(--space-3) var(--space-4); }
  .callbar .status-col { min-width: 0; }
  .bar-actions { margin-left: 0; width: 100%; }
  .bar-actions .btn { flex: 1; }
  .controls .btn { flex: 1 1 100%; }
  .finish-stats { gap: var(--space-5); }
  .rec-head { flex-direction: column; }
  .rec-state { align-items: flex-start; }
  .rec-card .finish-tracks li { flex-direction: column; align-items: flex-start; }
  .rec-card .finish-tracks li > span:last-child { justify-content: flex-start; }
  .finish-actions .btn { flex: 1 1 100%; }
}

/* Headlines wrap balanced rather than greedily. Without this the hero breaks as
   "The interview survives the / call." at 1440 - one orphaned word under a 77px line, which
   reads as a mistake in a page whose whole job is looking dependable. */
h1, h2 { text-wrap: balance; }

/* ── Landing page ─────────────────────────────────────────────────────────────────────
 * Sections separated by rhythm and a hairline rather than by boxes and cards. The Tape rule
 * still holds here: NOTHING on this page is coloured. The three signal colours mean recording
 * states, and spending one on a marketing accent would cost the other two their meaning.
 * The only saturated thing on the page is the primary button, which is the one action. */

.hero-form { max-width: 520px; }

.sell-section {
  padding: var(--space-7) 0;
  border-top: var(--border-width) solid var(--border);
}
.sell-section > h2 { font-size: var(--text-xl); max-width: var(--measure); }
/* The last paragraph in a section already has the section's padding under it; its own bottom
   margin on top of that was reading as a gap rather than as rhythm. */
.sell-section > .sub:last-child { margin-bottom: 0; }

/* ── The three steps ──────────────────────────────────────────────────────────────────
 * Numbered, not icon'd. An icon per step would be decoration standing where a fact should be. */
.steps { list-style: none; padding: 0; margin: var(--space-5) 0 0; }
.steps > .step {
  display: flex; gap: var(--space-4); align-items: baseline;
  padding: var(--space-5) 0;
  border-top: var(--border-width) solid var(--border);
}
.steps > .step:last-child { border-bottom: var(--border-width) solid var(--border); }
.step-n {
  flex: 0 0 auto; min-width: 2ch;
  color: var(--ink-muted); font-size: var(--text-sm);
}
.step-t { margin: 0; font-weight: var(--weight-bold); }
.step .note { margin-top: var(--space-2); max-width: var(--measure); }

/* ── The absence ──────────────────────────────────────────────────────────────────────
 * This block exists because the absence USED to be the fifth item in the capability list, which
 * rendered a deliberate non-feature as one more feature — and a slightly weak one. Set apart and
 * inset, it reads as the choice it is. */
.absence {
  border-left: 3px solid var(--border-strong);
  padding: var(--space-2) 0 var(--space-2) var(--space-5);
}
.absence-line {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-heading);
  max-width: var(--measure);
}
.absence .note { max-width: var(--measure); }

/* ── Pricing — one plan, so there is no grid of tiers to compare ──────────────────────── */
.plan {
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-top: var(--space-5);
  max-width: 480px;
  background: var(--surface);
}
.plan-amount {
  margin: 0;
  font-size: calc(var(--text-2xl) * 1.2);
  line-height: 1.05;
  letter-spacing: var(--tracking-display);
  font-weight: var(--weight-bold);
}
.plan .note:first-of-type { margin-top: var(--space-2); }
.plan .rows { margin: var(--space-5) 0 0; }

/* ── FAQ — real <details>, so it works before JavaScript and for a screen reader ──────── */
.faq { margin-top: var(--space-5); }
.faq-item {
  border-top: var(--border-width) solid var(--border);
  padding: var(--space-4) 0;
}
.faq-item:last-child { border-bottom: var(--border-width) solid var(--border); }
.faq-item > summary {
  cursor: pointer;
  font-weight: var(--weight-medium);
  /* The default marker is a tiny triangle with a tiny hit area. A whole row is the target. */
  list-style: none;
  display: flex; justify-content: space-between; align-items: center; gap: var(--space-4);
  min-height: 44px;
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary::after {
  content: '+';
  font-family: var(--font-mono); color: var(--ink-muted); flex: 0 0 auto;
}
.faq-item[open] > summary::after { content: '\2013'; }
.faq-item .note { margin-top: 0; max-width: var(--measure); }

.sell-section.final { text-align: left; }
.sell-section.final .btn { max-width: 520px; }

@media (max-width: 640px) {
  .sell-section { padding: var(--space-7) 0; }
  .absence { padding-left: var(--space-4); }
  .plan { padding: var(--space-5); }
}
