/*
 * The interview room.
 *
 * Someone is about to say something honest about their work, out loud, to a
 * machine. The page should feel like paper and ink — a printed thing, quiet,
 * finite — rather than a dashboard that is measuring them. Every choice below
 * follows from that: flat risograph colour, grain, a print serif for human
 * words, mono reserved for the machine's own labels.
 *
 * Two columns, one viewport, no page scroll. The left is the conversation and
 * sits over the wave; the right is the record. They are side by side because
 * the consent boundary must never be somewhere you scroll TO — the control
 * someone needs in order to leave has to be visible the entire time they are
 * deciding whether to stay.
 */

/* ⚠ WHAT IS LEFT HERE IS WHAT THE ROOM GENUINELY OWNS. The teal, the coral, the
   green, the paper, the hairline, the serif and the mono were all declared here
   at values IDENTICAL to tokens.css — seven redeclarations that could only ever
   drift apart, never together. They are gone.

   The three that stayed are real differences, and each is a decision:

   · `--ink` is #16211d here against the console's #0d0f0c. The console took its
     ink to near-black because a green cast "read as washed rather than as
     text" — on a dense working screen under a heavy scrim. This column is a
     letter on cream paper beside a painting, and the warmth belongs to it. The
     room keeps its character; that is the ticket's own wording.
   · `--ink-soft` follows `--ink`, for the same reason.
   · `--lift` is heavier, because these cards float over artwork rather than
     sitting on a veil.

   The dark scheme below stays too. `color-scheme: light` in tokens.css is the
   CONSOLE's decision — a leader's desk is light-only on purpose — and this is
   the one screen an employee might open at night, on their own phone, having
   been asked to speak candidly. */
:root {
  --ink: #16211d;
  --ink-soft: #5c6660;
  --lift: 0 1px 0 rgba(22, 33, 29, 0.04), 0 10px 30px rgba(22, 33, 29, 0.09);

  /* Cream ON the artwork — a foreground, which is why it is not `--paper`. */
  --foam: #f4efe0;

  /* ⚠ Ink for surfaces whose background does NOT follow the theme. The mic
     button, the interviewer's bubbles and the type box are all fixed cream so
     they read against the artwork — but they were using var(--ink), which
     flips to cream in dark mode. Cream on cream: the interviewer's words
     vanished entirely and the mic button read as blank. A fixed background
     needs a fixed foreground. */
  --ink-on-light: #16211d;

  /* The shared name for this surface is `--sunk`. Kept as a local alias rather
     than renamed through forty uses in one styling ticket. */
  --paper-deep: var(--sunk);

  /* The artwork. One layer, not two: an SVG fallback behind this would be
     fetched on every load to guard against a case where the site is already
     broken. */
  --riso-art: url("/wave-bg.jpeg");
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #17201d;
    --paper-deep: #121917;
    --ink: #ece5d3;
    --ink-soft: #9aa39c;
    --rule: #2c3733;
    --lift: 0 1px 0 rgba(0, 0, 0, 0.4), 0 14px 36px rgba(0, 0, 0, 0.45);
  }
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: clamp(15px, 0.42vw + 14px, 17px);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;

  display: grid;
  grid-template-columns: 1.05fr 1fr;
  /* dvh, not vh: on iOS the address bar makes vh taller than the visible area,
     which would hide the bottom of whichever column someone is using. */
  height: 100dvh;
  overflow: hidden;
}

h1, h2 { margin: 0; font-weight: 600; text-wrap: balance; }
p { margin: 0; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

:focus-visible { outline: 2px solid var(--coral); outline-offset: 3px; border-radius: 2px; }
::selection { background: var(--coral); color: var(--foam); }

.muted { color: var(--ink-soft); font-size: 0.92rem; }

/* Page-wide, both columns. `.sea .error` inverts it: on the artwork a coral
   word on cream is a word you have to hunt for, so it becomes a filled pill. */
.error { margin-top: 0.8rem; font-size: 0.9rem; font-weight: 600; color: var(--coral); }
.sea .error { color: var(--foam); background: var(--coral); padding: 0.5rem 0.7rem; border-radius: 8px; }

[hidden] { display: none !important; }

/* ── Left: the sea ──────────────────────────────────────────────────────── */

.sea {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  padding: clamp(1.4rem, 2.6vw, 2.6rem);
  overflow: hidden;

  background-image: var(--riso-art);
  background-size: cover;
  /* The image is landscape and this column is portrait, so `cover` crops the
     sides hard — roughly half the width is never seen. The curl sits at about
     40% across, so the crop is centred there: too far right and the curl falls
     out of frame leaving flat coral, too far left and it is flat teal. */
  background-position: 42% center;
}

/* A scrim, not a tint. Text over artwork is unreadable somewhere on some
   viewport, always — this keeps contrast without washing the ink out, and it
   is heavier at the bottom where the controls live.

   ⚠ The middle stop was 0.16, and that was the whole "hard to read" report.
   The painting's breaking crest is near-white and sits around a third of the
   way down, which is exactly where the theme and the conversation are — so the
   scrim was thinnest under the most text, over the palest part of the picture,
   in cream. Every element that got patched individually (the state pill, the
   transcript toggle, the progress track, the pointer) was patched because of
   this one stop.

   0.38 in the middle is enough for cream to clear 4.5:1 over the crest. The
   painting is still a painting: at these values the wave reads, the horizon
   reads, and the colour survives. A tint that hid it would have been the
   easier fix and the wrong one. */
.sea::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(10, 20, 18, 0.46) 0%,
    rgba(10, 20, 18, 0.38) 34%,
    rgba(10, 20, 18, 0.66) 100%);
  pointer-events: none;
}

.sea > * { position: relative; z-index: 1; }

/* ⚠ A floor, not a preference. Everything in this column sits on a painting,
   and mono-uppercase at 0.58rem with wide tracking was around 9px — small,
   translucent and textured all at once, which compounds rather than adds.
   Nothing over the artwork goes below 0.75rem; the paper column next door is
   free to be quieter because it has a solid ground. */
.sea .wordmark,
.sea .asking,
.sea .state,
.sea .exchange .who { font-size: 0.75rem; }

.sea__ink { color: var(--foam); flex: none; }

.wordmark {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  opacity: 0.85;
}

/* Who is asking, above what they are asking. Small and quiet: it is context,
   not the point. */
.asking {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-top: 0.9rem;
  opacity: 0.85;
}

/* The subject. Wider than the old tagline because a real theme is a sentence,
   not four words, and it must not wrap into a narrow ribbon. */
/* The round's actual theme — the most important line on the page, and the one
   element that never got a backing of its own. A 24px shadow is a glow, not a
   scrim: it spreads the ink instead of darkening what is behind it, and cream
   at this size over near-white foam needs the second thing.

   The shadow stays, tightened, because it does the edges; the panel does the
   contrast. Which of the two is load-bearing depends on the viewport — `cover`
   moves the crop, so whether this lands on crest or on teal is not something
   the stylesheet gets to know. */
.sea__line {
  font-size: clamp(1.35rem, 2.1vw, 1.95rem);
  line-height: 1.16;
  letter-spacing: -0.02em;
  margin-top: 0.35rem;
  max-width: 22ch;
  padding: 0.5rem 0.75rem;
  margin-left: -0.75rem;
  border-radius: 10px;
  background: rgba(10, 20, 18, 0.42);
  text-shadow: 0 1px 6px rgba(10, 20, 18, 0.7);
}

/* Was the headline. Demoted deliberately: it is reassurance, and reassurance
   should not outrank the question someone is being asked. */
.sea__note {
  margin-top: 0.7rem;
  font-size: 0.9rem;
  /* Was opacity. On a solid ground that reads as "quieter"; on a painting
     whose lightness swings from foam to deep teal it reads as "sometimes
     gone", because the contrast it lands at depends on the pixel behind it. */
  color: rgba(244, 239, 224, 0.92);
  max-width: 36ch;
  /* Stops the last word wrapping alone onto its own line, which it did at 30ch
     and which reads as a mistake rather than a line break. */
  text-wrap: pretty;
}

/* ── The entry card ─────────────────────────────────────────────────────── */

.card {
  background: var(--paper);
  border-radius: 14px;
  padding: clamp(1.1rem, 2vw, 1.6rem);
  box-shadow: var(--lift);
  max-width: 27rem;
}

.card--entry { margin-top: auto; flex: none; animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) both; }

.card__title { font-size: 1.16rem; margin-bottom: 0.3rem; }

label {
  display: block;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0.9rem 0 0.3rem;
}

input, textarea {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--paper-deep);
  border: 1px solid var(--rule);
  border-radius: 9px;
  padding: 0.6rem 0.7rem;
}

input:focus, textarea:focus { border-color: var(--teal); }

/* ── Buttons ────────────────────────────────────────────────────────────── */

.btn {
  font: inherit;
  font-size: 0.94rem;
  font-weight: 600;
  padding: 0.62rem 1.1rem;
  border-radius: 9px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.14s ease, filter 0.14s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: 0.42; cursor: not-allowed; transform: none; }

.btn--go { background: var(--green); color: var(--foam); margin-top: 1.1rem; }
.btn--quiet { background: transparent; color: var(--ink); border-color: var(--rule); }

/* For controls that must be reachable without competing for attention — the
   transcript toggle sits in the room the whole time and is used once, if ever. */
.btn--small {
  font-size: 0.78rem;
  padding: 0.34rem 0.7rem;
  align-self: flex-start;
  color: var(--foam);
  border-color: rgba(244, 239, 224, 0.32);
  background: rgba(10, 20, 18, 0.42);
  backdrop-filter: blur(3px);
}

/* Discard is a real, safe choice — not a warning. Colouring it like danger
   would discourage the one action the consent boundary exists to guarantee. */
.btn--leave { background: transparent; color: var(--coral); border-color: var(--coral); }

/* ── The microphone ─────────────────────────────────────────────────────── */

.talk {
  /* Takes ALL the leftover column height. Without flex-grow here the whole
     block sized to its content, the transcript collapsed to one visible turn,
     and the conversation — the thing this column exists for — became a
     letterbox. min-height:0 is what actually permits a flex child to be
     smaller than its content and therefore to scroll. */
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}

.mic { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }

.mic__button {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font: inherit;
  font-weight: 600;
  color: var(--ink-on-light);
  background: var(--foam);
  border: none;
  border-radius: 999px;
  padding: 0.6rem 1.2rem 0.6rem 0.7rem;
  cursor: pointer;
  box-shadow: var(--lift);
}

.mic__glyph {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--coral);
  flex: none;
}

/* Breathing, only while live. A permanent pulse is decoration; one that starts
   when recording starts is a status you can read from across the room. */
.mic__button[aria-pressed="true"] .mic__glyph { animation: breathe 2.4s ease-in-out infinite; }

/* The same white pill as the mic button beside it. It used to be .btn--quiet —
   a transparent box with a hairline border — and on the painting that is very
   nearly invisible. The one control someone reaches for when a colleague walks
   into the room was the one they could not find. */
.pause {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font: inherit;
  font-weight: 600;
  color: var(--ink-on-light);
  background: var(--foam);
  border: none;
  border-radius: 999px;
  padding: 0.6rem 1.15rem;
  cursor: pointer;
  box-shadow: var(--lift);
}

/* Two bars, drawn rather than typed. The ⏸ character arrives as a colour emoji
   on one platform and a hollow box on another, and this glyph has to be legible
   at a glance in a room where someone has just been interrupted. */
.pause__glyph { display: inline-flex; gap: 3px; }

.pause__glyph::before,
.pause__glyph::after {
  content: "";
  width: 3px;
  height: 12px;
  border-radius: 1px;
  background: currentColor;
}

/* Paused, so the button now resumes: one triangle instead of two bars. The
   glyph has to say which way the control goes, not which state it is in. */
.pause[aria-pressed="true"] .pause__glyph::before {
  width: 0;
  height: 0;
  background: none;
  border-radius: 0;
  border-left: 9px solid currentColor;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
}
.pause[aria-pressed="true"] .pause__glyph::after { display: none; }

.mic__read { display: flex; align-items: center; gap: 0.6rem; }

.state {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--foam);

  /* Its own backing, because it sits ON the artwork and the artwork has a
     cream foam in it — pale text over pale foam disappeared exactly where the
     wave breaks. The page scrim is a gradient and cannot guarantee contrast at
     any particular point; a pill can. */
  background: rgba(10, 20, 18, 0.55);
  padding: 0.16rem 0.5rem;
  border-radius: 999px;
  backdrop-filter: blur(3px);
}

.state--count { align-self: flex-start; }

/* How far into the interview they are.

   A hairline, not a bar: this should register at the edge of attention and
   never compete with the question someone is being asked. An interview with no
   visible shape feels endless, and someone who thinks it might never stop
   starts giving shorter answers to get out — which is precisely the thing this
   product cannot afford.

   It eases rather than jumps, because a bar that lurches forward reads as a
   score going up, and nobody is being scored here. */
.progress {
  width: min(100%, 15rem);
  height: 3px;
  border-radius: 999px;
  /* Pale, not dark. A dark track vanished into the artwork and left only the
     filled part visible — which reads as a short line rather than a bar with
     distance still to run, and the distance still to run is the entire point.
     The unfilled part has to be as legible as the fill. */
  background: rgba(244, 239, 224, 0.26);
  /* And a halo, for the same reason the wave stroke has one: a pale track over
     the pale crest is a bar with no visible ends, which reads as no bar. */
  box-shadow: 0 0 0 1px rgba(10, 20, 18, 0.45);
  overflow: hidden;
  margin-bottom: 0.5rem;
}

.progress__fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: 999px;
  background: var(--foam);
  opacity: 0.85;
  transition: width 0.9s cubic-bezier(0.22, 0.68, 0.24, 1);
}

@media (prefers-reduced-motion: reduce) {
  .progress__fill { transition: none; }
}

/* ── The line ───────────────────────────────────────────────────────────

   One travelling wave, and nothing else. It replaced an orb, which replaced a
   waveform: the orb read as a THING sitting in the room, and the room already
   has a painting in it.

   A line is quieter and says the same thing — it moves while someone is heard
   and lies flat when they are not — and a travelling wave stays legibly alive
   through a pause for thought, which a level meter does not. */

.wave {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  place-items: center;
}

#wave {
  /* Two thirds of the column: long enough to read as a wave rather than a
     wobble, short enough not to run under the artwork's breaking crest. */
  width: 66%;
  height: 72px;
  display: block;
}

/* ── The transcript ─────────────────────────────────────────────────────── */

.exchange {
  list-style: none;
  margin: 0;
  padding: 0.2rem 0.4rem 0.2rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;

  /* Bounded and scrolling inside itself. flex-basis 0 + flex-grow lets it take
     the leftover column height and no more, so the page never grows. */
  flex: 1 1 0;
  min-height: 5rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.exchange li {
  padding: 0.55rem 0.8rem;
  border-radius: 11px;
  max-width: 92%;
  font-size: 0.94rem;
  animation: rise 0.32s ease both;
}

.exchange li.them {
  background: rgba(244, 239, 224, 0.94);
  color: var(--ink-on-light);
  align-self: flex-start;
  border-bottom-left-radius: 3px;
}

.exchange li.you {
  background: var(--green);
  color: var(--foam);
  align-self: flex-end;
  border-bottom-right-radius: 3px;
}

/* A turn whose words have not arrived from transcription yet. Present enough to
   hold its place in the order, quiet enough not to be read as something said. */
.exchange li.pending { opacity: 0.5; }

/* ⚠ A turn the sidecar threw away. Drawn as machinery rather than as speech —
   outlined, centred, no side — because it is not part of the conversation and
   must not read as though somebody said it to somebody. It is here so a tester
   can see the gate working, or see it eating a real answer, which is invisible
   everywhere else. See SHOW_FULL_TRANSCRIPT in voice.js. */
.exchange li.dropped {
  align-self: center;
  max-width: 100%;
  background: transparent;
  border: 1px dashed rgba(244, 239, 224, 0.35);
  color: rgba(244, 239, 224, 0.62);
  font-size: 0.86rem;
  font-style: italic;
}
.exchange li.dropped .who { font-style: normal; opacity: 0.85; }

.exchange .who {
  display: block;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  opacity: 0.6;
  margin-bottom: 0.16rem;
}

.typed { display: flex; gap: 0.5rem; align-items: flex-end; }
.typed textarea {
  resize: none;
  background: rgba(244, 239, 224, 0.94);
  color: var(--ink-on-light);
  border-color: transparent;
}
.typed textarea::placeholder { color: rgba(22, 33, 29, 0.5); }

/* ── Motion ─────────────────────────────────────────────────────────────── */

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

@keyframes breathe {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 0 0 rgba(240, 87, 74, 0.55); }
  50%      { transform: scale(1.08); box-shadow: 0 0 0 9px rgba(240, 87, 74, 0); }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ── Narrow: one column, and the page may scroll ────────────────────────── */

@media (max-width: 900px) {
  body {
    grid-template-columns: 1fr;
    height: auto;
    min-height: 100dvh;
    overflow: auto;
  }

  .sea { min-height: 78dvh; }

  /* On a phone the columns become sections, so the boundary can no longer be
     permanently visible. Keeping it pinned to the bottom of the viewport is
     the nearest honest equivalent. */
  .exchange { max-height: 42dvh; }
}


/* ── The right column is in paper.css ────────────────────────────────────────
 *
 * The folds, the draft, the box the employee writes into, the actions and every
 * state after them. This file had reached 949 lines describing two columns that
 * share a page and almost nothing else; the seam between them is the consent
 * boundary, so it is the one worth cutting along.
 *
 * ⚠ Its half of the narrow media query above moved with it, deliberately. See
 * the note at the bottom of paper.css for why leaving it here would break the
 * phone layout silently.
 */

/* ⚠ THE MOST DANGEROUS PAUSE IN THE PRODUCT, made to look like one.
   The interviewer has said goodbye, the microphone is off, and nothing has been
   stored yet — so somebody who reads this stretch as "finished" closes the tab
   and loses the interview and their key with it. A sentence swapped into the
   draft box is what "done" looks like; this is what "working" looks like. */
.working {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  padding: 2.2rem 1.2rem;
  text-align: center;
}

/* A ring that turns. Motion is the signal that this is work rather than a
   result — the whole reason the previous version failed was that a sentence in
   a box looks exactly like an answer. */
.working__ring {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  border: 3px solid rgba(244, 239, 224, 0.18);
  border-top-color: var(--teal);
  animation: working-spin 0.9s linear infinite;
}

@keyframes working-spin {
  to { transform: rotate(360deg); }
}

.working__what { margin: 0; font-size: 1.02rem; }
.working__wait { margin: 0; font-size: 0.9rem; color: rgba(244, 239, 224, 0.66); }

/* ⚠ Motion is not the ONLY signal. With it off, the ring still reads as a
   marker and the words carry the whole message — "please do not close this
   page" is the part that actually prevents the loss. */
@media (prefers-reduced-motion: reduce) {
  .working__ring { animation: none; border-top-color: var(--teal); opacity: 0.8; }
}

/* ⚠ Over the panel, not the page. The employee's own words stay visible behind
   it: a dialog that hides the thing it is asking about makes "let me edit" a
   decision taken blind. */
.confirm {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.2rem;
  background: rgba(11, 20, 18, 0.72);
  z-index: 5;
}

/* ⚠ `color` IS NOT OPTIONAL ON A DARK SURFACE, and leaving it off made the last
   control in the product unreadable. This card is near-black; its title, its
   body and its second button all inherited `--ink`, which is #0d0f0c — so the
   dialog rendered as a dark box containing one green button and, beside it, an
   outlined rectangle with an invisible label. A tester clicked what looked like
   blank space, landed back on the review screen, and reported that "it doesn't
   say anything on the screen". It was saying it; the words were the same colour
   as what they were printed on.

   ⚠ AND THE PRECEDENT WAS ALREADY WRITTEN DOWN, in paper.css beside `.pointer`:
   "the background is a near-black pill and the paragraph inherits --ink ... so
   this read at about 1.1:1 and was invisible". Same file family, same mistake,
   a few hundred lines apart. Set the foreground wherever you set a background
   that is not the page's own. */
.confirm__card {
  max-width: 26rem;
  padding: 1.3rem 1.4rem;
  border-radius: 12px;
  border: 1px solid rgba(244, 239, 224, 0.16);
  background: #16211d;
  color: var(--foam);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
}

.confirm__title { margin: 0 0 0.5rem; font-size: 1.15rem; color: var(--foam); }
.confirm__body { margin: 0 0 1rem; font-size: 0.96rem; line-height: 1.5; color: var(--foam); }
.confirm__acts { display: flex; flex-wrap: wrap; gap: 0.6rem; }

/* ⚠ The refusal must be as readable as the confirmation. `.btn--quiet` is
   `color: var(--ink)` for a light card, and this one is dark — so the way OUT
   of a one-way action was the invisible half of the dialog. */
.confirm .btn--quiet {
  color: var(--foam);
  border-color: rgba(244, 239, 224, 0.45);
}

.confirm .btn--quiet:hover { border-color: var(--foam); background: rgba(244, 239, 224, 0.08); }

/* The one step left, said once the draft exists and there is a step to take. */
.draft-ready {
  margin: 1rem 0 0.6rem;
  padding: 0.6rem 0.9rem;
  border-left: 3px solid var(--teal);
  background: rgba(15, 139, 130, 0.08);
  font-size: 0.94rem;
  line-height: 1.45;
}

/* ⚠ The positioning context for `.confirm`. Without it the overlay escapes to
   the nearest positioned ancestor and covers the whole page, which hides the
   draft the dialog is asking about. */
#draft-step { position: relative; }

/* ⚠ THE ONLY REMAINING STEP MUST NOT BE SOMETHING TO GO LOOKING FOR.
   A tester reached the draft and said "I don't even see the button to approve.
   I don't see anything." The panel runs banner → heading → paragraph → the
   account → hint → add box → label before it gets here, which on a laptop is
   well past the fold — and somebody who read the anonymising as the finish
   closes the tab, losing the interview and the key with it.

   So the bar follows them down the panel. The cue rides inside it, or it
   scrolls away from the button it is describing. */
.actions--stuck {
  position: sticky;
  bottom: 0;
  z-index: 3;
  margin-top: 1.2rem;
  /* ⚠ THE FADE MUST FIT INSIDE THE BAR'S OWN PADDING. It was a percentage —
     transparent to 24% of the bar's height — which on a two-line cue reaches
     well past the 0.8rem of padding above it, so whatever scrolls underneath
     shows through the translucent part. A tester saw "Anonymise what I added"
     peering out from behind the approve button.
     Fixed lengths instead: opaque by 1.5rem, with 1.5rem of padding for it to
     happen in, so nothing but the bar is ever visible through it. */
  padding: 1.5rem 0 0.9rem;
  /* ⚠ THE PANEL'S OWN SURFACE, not a guess at it. This was hardcoded to
     rgba(11,20,18) — several shades darker than `--paper` at #17201d — so the
     bar read as a black slab bolted under the buttons rather than as the panel
     continuing. A sticky element has to be painted in the colour of what it is
     covering, and that colour has a variable. */
  background: linear-gradient(to bottom, transparent 0, var(--paper) 1.5rem, var(--paper) 100%);
}

/* ⚠ NOT TWO EQUAL CHOICES. They were the same size and the destructive one was
   red, which pulls harder than green — so the loudest thing on a screen whose
   only real step is "approve" was "discard everything". A tester who could see
   both still said it was "not very clear visually that I have to click this
   button".
   Approve takes the room. Discard stays reachable, because throwing it all away
   is a promise this product makes, and quiet is not the same as hidden. */
.actions__row {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

.actions__row #approve {
  flex: 1 1 auto;
  padding: 0.85rem 1.4rem;
  font-size: 1.04rem;
}

.actions__row #discard {
  flex: 0 0 auto;
  padding: 0.5rem 0.7rem;
  border-color: transparent;
  background: transparent;
  font-size: 0.86rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.actions__row #discard:hover,
.actions__row #discard:focus-visible {
  border-color: var(--coral);
  text-decoration: none;
}

/* ⚠ ONE PULSE, THEN STILL. The draft has just appeared and the eye is on the
   text; this says where the step is and then stops, because a control that
   never stops moving is one people learn to ignore — and this screen already
   asks somebody to read carefully. */
.actions__row #approve:not(:disabled).is-ready {
  animation: approve-ready 1.1s ease-out 3;
}

@keyframes approve-ready {
  0%, 100% { box-shadow: 0 0 0 0 rgba(47, 107, 69, 0); }
  40% { box-shadow: 0 0 0 6px rgba(47, 107, 69, 0.32); }
}

@media (prefers-reduced-motion: reduce) {
  .actions__row #approve:not(:disabled).is-ready { animation: none; }
}

/* Sits above its own buttons, and only once there is something to approve. */
.actions--stuck .draft-ready {
  margin: 0 0 0.75rem;
  font-size: 1rem;
  border-left-width: 4px;
}

/* One line, one click. Sits with the transcript toggle as the two quiet
   controls of the interview column, rather than as an input competing with the
   conversation. */
.type-toggle {
  align-self: flex-start;
  padding: 0.35rem 0.7rem;
  border: 1px solid rgba(244, 239, 224, 0.22);
  border-radius: var(--radius-pill, 100px);
  background: rgba(22, 33, 29, 0.55);
  color: rgba(244, 239, 224, 0.82);
  font-size: 0.8rem;
  cursor: pointer;
}
.type-toggle:hover,
.type-toggle:focus-visible { border-color: var(--teal); color: var(--foam, #f4efe0); }

/* ── The phone proper (N32) ──────────────────────────────────────────────── */

/* ⚠ AT THE END OF THE FILE ON PURPOSE. The overrides below tie on specificity
   with the base rules above (`.actions__row #approve` most of all), so source
   order is what makes them win — a media query is not specificity, and this
   block placed earlier in the file silently lost exactly that fight once. */
@media (max-width: 600px) {
  /* ⚠ THE INVITATION MUST NOT SIT A FULL SCREEN BELOW THE KEY. At 78dvh of
     painting, the promise the person is supposed to read BEFORE presenting a
     key started an entire scroll below the key card. The artwork stays — it
     is the product's face — but on a phone it yields the room. */
  .sea { min-height: 44dvh; }

  /* ⚠ THE CONFIRM DIALOG CENTRES IN THE VIEWPORT, NOT THE PANEL. It was
     absolute inside #draft-step, which on a phone is taller than the screen —
     so the one dialog that guards "discard everything" could open entirely
     off-screen, and a tap that expected it did nothing visible. */
  .confirm { position: fixed; }

  /* ⚠ THE ROW MAY WRAP, AND APPROVE TAKES ITS OWN LINE. Three labels that
     cannot wrap overflowed 375px; approve going full-width keeps it the
     loudest thing on the screen, which the not-two-equal-choices note above
     already demands. */
  .actions__row { flex-wrap: wrap; }
  .actions__row #approve { flex: 1 1 100%; }
}
