/* One stylesheet, no framework. Mobile first, because a link pasted into a
   Facebook group opens on a phone even though the work is done at a desk.

   THE DESIGN IDEA, so nobody has to reverse-engineer it from the rules.
   Every screen in this product is the same sentence: a measured number, an
   allowed band, and the distance between them. Five ACX specs, a LUFS target,
   a chapter against the book's median, a manuscript against a rate card. The
   first version said all of that in paragraphs and the page read as an essay
   with a file input in it. So the band and the marker are now a DRAWN
   primitive (`.gauge`), numbers are set in a monospace face because an
   instrument's readout is monospace, and the reading text is demoted to what
   it always was — the explanation that comes after the measurement.

   The serif stays, because the subject is books. It carries headings and
   considered prose. It does not carry data. */

:root {
  color-scheme: light dark;

  /* Daylight studio. The dark scheme below is the designed-for state; this is
     the same room with the blinds open, not a different product. */
  --ink: #17130e;
  --ink-soft: #5a5142;
  --paper: #faf7f2;
  --card: #ffffff;
  --sunk: #f3efe7;
  --line: #e0d9cd;
  --line-strong: #c9bfae;
  --control-boundary: #8c8477;
  --accent: #7a4a1e;
  --accent-soft: #f0e2d2;
  --accent-ink: #ffffff;
  --pass: #1f6b3a;
  --fail: #b3261e;
  --band: #e6ddcd;

  --radius: 12px;
  --radius-lg: 18px;
  --measure: 34rem;
  --shell: 78rem;

  --serif: ui-serif, Georgia, "Times New Roman", serif;
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  /* The instrument face. Every measured value on this site is set in it, so a
     column of readings lines up and a changing digit does not move its
     neighbours. */
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Warm near-black rather than blue-black: this is a recording room, and a
       cold grey turns the book art into a spreadsheet. */
    --ink: #f3ece1;
    --ink-soft: #b3a795;
    --paper: #14110d;
    --card: #1d1913;
    --sunk: #191510;
    --line: #332c22;
    --line-strong: #4a3f31;
    --control-boundary: #8a7c66;
    --accent: #e3ab77;
    --accent-soft: #2b2015;
    --accent-ink: #1c1409;
    --pass: #6fd39a;
    --fail: #ff7369;
    --band: #2e2519;
  }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 16px/1.62 var(--serif);
  -webkit-text-size-adjust: 100%;
}

/* --- shell and rhythm ---------------------------------------------------- */

.wrap, .wide-wrap { max-width: var(--shell); margin: 0 auto; padding: 1.25rem 1.15rem 4rem; }
@media (min-width: 64rem) { .wrap, .wide-wrap { padding: 1.75rem 2rem 5rem; } }

h1, h2, h3 { line-height: 1.2; font-weight: 600; letter-spacing: -0.015em; }
h1 { font-size: clamp(1.85rem, 1.4rem + 1.6vw, 2.5rem); margin: 0 0 0.7rem; }
h2 { font-size: clamp(1.35rem, 1.15rem + 0.9vw, 1.75rem); margin: 0 0 0.6rem; }
h3 { font-size: 1.08rem; margin: 1.3rem 0 0.35rem; }
p, li { max-width: var(--measure); }
p { margin: 0 0 0.9rem; }

a { color: var(--accent); text-underline-offset: 0.15em; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.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;
}

/* A section band. The first version had one column and every section looked
   equally important; alternating the ground is how a scanning eye finds the
   edges of a block without another heading. */
.band-sunk { background: var(--sunk); border-block: 1px solid var(--line); }
.section { margin: 3rem 0 0; }
.section-inset {
  margin-top: 3rem; padding: 2rem 1.25rem 2.25rem;
  background: var(--sunk); border: 1px solid var(--line); border-radius: var(--radius-lg);
}
@media (min-width: 52rem) { .section-inset { padding: 2.25rem 2rem 2.5rem; } }
.section-head { margin-bottom: 1.4rem; }
.section-head p { color: var(--ink-soft); }

.eyebrow {
  margin: 0 0 0.4rem;
  color: var(--accent);
  font: 700 0.74rem/1.2 var(--sans);
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

/* --- masthead ------------------------------------------------------------ */

/* EVERY NAVIGATION CONTROL IS A 44px TARGET. The responsive matrix failed the
   brand and all three nav links on every phone in the set: inline text in a
   flex row is exactly as tall as its line box, around 24px, and a 24px tap
   target is a mis-tap on a phone held one-handed. min-block-size from the box,
   never padding, so the text stays where it looks like it should be.

   ONE ROW AT EVERY WIDTH. The hand-copied nav it replaces listed ten links and
   wrapped to FIVE rows at 390px, which is most of why the tool started at
   ~830px on a phone. Four group buttons fit beside the brand from 600px up;
   below that the whole catalogue sits behind one Menu button. */
.skip-link {
  position: absolute;
  inset-block-start: 0.5rem;
  inset-inline-start: 0.5rem;
  z-index: 40;
  display: inline-flex; align-items: center; min-block-size: 44px;
  padding: 0 0.9rem;
  background: var(--card); color: var(--accent);
  border: 2px solid var(--accent); border-radius: var(--radius);
  font: 600 0.95rem/1 var(--sans);
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

header.site-header {
  position: relative;
  display: flex; align-items: center; gap: 0.5rem 1.1rem; flex-wrap: wrap;
  margin-bottom: 1.5rem; padding-bottom: 0.6rem; border-bottom: 1px solid var(--line);
}
header.site-header a.brand {
  display: inline-flex; align-items: center; gap: 0.55rem; min-height: 44px;
  font: 600 1.06rem/1 var(--sans); letter-spacing: -0.01em;
  text-decoration: none; color: var(--ink);
  margin-inline-end: auto;
}
header.site-header a.brand svg { inline-size: 1.6rem; block-size: 1.6rem; color: var(--accent); flex: none; }

.nav-toggle, .nav-group {
  display: inline-flex; align-items: center; gap: 0.45rem;
  min-block-size: 44px; padding: 0 0.75rem;
  border: 1px solid transparent; border-radius: var(--radius);
  background: none; color: var(--ink-soft);
  font: 500 0.95rem/1 var(--sans); cursor: pointer;
}
.nav-toggle { border-color: var(--control-boundary); color: var(--ink); }
.nav-toggle svg { inline-size: 1.15rem; block-size: 1.15rem; }
.nav-group::after {
  content: ""; inline-size: 0.4rem; block-size: 0.4rem;
  border-inline-end: 1.5px solid currentColor; border-block-end: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}
.nav-group[aria-expanded="true"]::after { transform: translateY(1px) rotate(-135deg); }
.nav-group:hover, .nav-group[aria-expanded="true"] { color: var(--accent); background: var(--sunk); }
.nav-group.is-current { color: var(--ink); box-shadow: inset 0 -2px 0 var(--accent); border-radius: var(--radius) var(--radius) 0 0; }
.nav-groups { display: flex; gap: 0.15rem; margin: 0; padding: 0; list-style: none; }
.nav-groups li { max-width: none; }

.nav-panels { display: none; }
.nav-panel { display: none; }
.nav-panel-title {
  margin: 0 0 0.25rem; font: 700 0.72rem/1.2 var(--sans);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft);
}
.nav-panel ul { margin: 0; padding: 0; list-style: none; }
.nav-panel li { max-width: none; }
.nav-panel a {
  display: flex; align-items: center; min-block-size: 44px; padding: 0 0.6rem;
  border-radius: var(--radius); color: var(--ink); text-decoration: none; font: 0.95rem/1.25 var(--sans);
}
.nav-panel a:hover { background: var(--sunk); color: var(--accent); }
.nav-panel a[aria-current="page"] { color: var(--accent); font-weight: 600; }

/* A desktop dropdown: the open group's panel, under the header's right edge.
   Only one is ever open, and with none open the landmark takes no box at all. */
@media (min-width: 37.5rem) {
  .nav-toggle { display: none; }
  .site-nav[data-panel] .nav-panels {
    display: block; position: absolute; inset-block-start: calc(100% + 0.35rem); inset-inline-end: 0; z-index: 30;
    min-inline-size: 17rem; max-inline-size: min(22rem, 100%);
    padding: 0.6rem; background: var(--card);
    border: 1px solid var(--line); border-radius: var(--radius-lg);
    box-shadow: 0 1px 2px rgb(0 0 0 / 6%), 0 18px 40px -20px rgb(0 0 0 / 45%);
  }
  .nav-panel.is-open { display: block; }
  .nav-panel-title { padding: 0.35rem 0.6rem 0; }
}

/* A phone: brand and Menu on one 62px row; the sheet lists all four groups at
   once, because a menu inside a menu is two taps where one will do. */
@media (max-width: 37.49rem) {
  .site-nav { display: none; flex-basis: 100%; }
  .site-nav.is-open { display: block; }
  .nav-primary { display: none; }
  .site-nav.is-open .nav-panels {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.9rem 0.75rem;
    padding: 0.75rem 0 0.5rem;
  }
  .site-nav.is-open .nav-panel { display: block; min-inline-size: 0; }
  .nav-panel a { padding: 0 0.3rem; overflow-wrap: anywhere; }
}

/* --- hero ---------------------------------------------------------------- */

.hero { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.75rem; align-items: start; }
@media (min-width: 64rem) {
  /* The whole reason the shell got wider. At 1440 the old page was a 700px
     column of prose with the primary action buried in it as one more
     paragraph. The tool now sits beside the claim instead of below it. */
  .hero { grid-template-columns: minmax(0, 1fr) minmax(26rem, 1.05fr); gap: 3rem; }
}
.hero-copy .lede { font-size: 1.12rem; color: var(--ink-soft); }

/* Book-to-waveform, as a banner rather than a spot illustration. As a spot it
   sat above the eyebrow at a third of this size and read as clip-art parked in
   a corner; the metaphor only works when the wave has room to actually run out
   of the book. */
.hero-banner { margin: 0 0 2rem; }
.hero-art { display: block; inline-size: 100%; block-size: auto; }
.hero-art .page { fill: var(--card); stroke: var(--line-strong); }
.hero-art .ink { stroke: var(--line-strong); }
.hero-art .spine { stroke: var(--line-strong); }
.hero-art .wave { stroke: var(--accent); }
/* TWO DRAWINGS, NOT ONE CROPPED ONE. A 6:1 banner scaled to a phone is a
   65px strip with an unreadable book. Cropping it with `preserveAspectRatio:
   slice` looked right and was wrong for a reason worth writing down: `slice`
   scales the CONTENT to cover the box, so the wave path keeps its full drawn
   width and `getBoundingClientRect` reports it spilling 454px past its parent
   on a 320px viewport — 43 rows of the responsive matrix, on a graphic the SVG
   viewport was visually clipping anyway. A phone gets a composition drawn at a
   phone's proportions instead, and the one it does not use is `display: none`,
   which has no box to spill. */
.hero-art--compact { display: none; }
@media (max-width: 44rem) {
  .hero-art--wide { display: none; }
  .hero-art--compact { display: block; }
}

/* Trust chips. The one objection this product has to answer in the first
   screen is "am I uploading an NDA'd manuscript to a stranger". */
.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1.15rem 0 0; padding: 0; list-style: none; }
.chips li {
  display: inline-flex; align-items: center; gap: 0.4rem; max-width: none;
  padding: 0.4rem 0.7rem; border: 1px solid var(--line); border-radius: 999px;
  background: var(--card); color: var(--ink-soft); font: 0.82rem/1.2 var(--sans);
}
.chips svg { inline-size: 0.95rem; block-size: 0.95rem; color: var(--accent); flex: none; }

/* --- the tool, which has to dominate ------------------------------------- */

.tool {
  margin: 0 0 2.5rem;
  padding: 1.35rem 1.15rem 1.6rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: 0 1px 2px rgb(0 0 0 / 5%), 0 18px 40px -28px rgb(0 0 0 / 45%);
}
@media (min-width: 52rem) { .tool { padding: 1.75rem 1.75rem 2rem; } }
.tool-title { margin: 0 0 1rem; font: 700 0.74rem/1.2 var(--sans); letter-spacing: 0.11em; text-transform: uppercase; color: var(--ink-soft); }

/* `file-drop`, assembled from packages/site-components rather than invented.
   THE LABEL IS THE TARGET and it wraps the input, so the whole zone is tappable
   by construction — touch devices have no drag, and a zone whose only
   affordance is "drag files here" is dead on every phone. Drag is layered on by
   script as an enhancement and the tap path works without it. */
.file-drop {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  min-block-size: 11rem;
  padding: 2rem 1.25rem;
  border: 2px dashed var(--control-boundary);
  border-radius: var(--radius);
  text-align: center;
  cursor: pointer;
  background: var(--sunk);
  transition: border-color 120ms ease, background-color 120ms ease;
}
.file-drop:hover { border-color: var(--accent); }

/* Visually hidden, never `display: none`: a hidden input is not focusable and
   the keyboard path disappears with it. */
.file-drop input[type="file"],
.file-drop-actions .ghost input[type="file"] {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.file-drop:focus-within { border-color: var(--accent); outline: 3px solid var(--accent); outline-offset: 3px; }
.file-drop-mark { color: var(--accent); font: 700 1.2rem/1 var(--sans); letter-spacing: 0.04em; }
.file-drop-mark svg { inline-size: 2.6rem; block-size: 2.6rem; display: block; }
.file-drop-mark:has(svg) { font: inherit; letter-spacing: normal; }
.file-drop-label { font: 600 1.15rem/1.3 var(--sans); color: var(--ink); }
.file-drop-hint { color: var(--ink-soft); font: 0.9rem/1.45 var(--sans); max-width: 26rem; }
/* Set by script while a drag is over the zone. Pointer-based, so it never fires
   on touch — which is why it can only ever be an enhancement. */
.file-drop.is-dragging { border-color: var(--accent); border-style: solid; background: var(--accent-soft); }

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

/* --- the gauge: this site's one invented primitive ------------------------ */

/* A measured value against its allowed band, drawn rather than described.
   Geometry lives in SVG attributes, NOT in a style attribute: the production
   CSP is `default-src 'self'` with no `unsafe-inline`, so every `style="..."`
   on this site is refused by the browser. Script moves the marker with
   setAttribute on x/x1/x2, which is geometry, not CSS. */
.gauge { display: block; inline-size: 100%; block-size: auto; }
/* THE BAND IS A SEGMENT OF THE BAR, never a shape sitting on top of one.
   Two earlier attempts — a rounded knob on a 6px track, then an outlined box
   on a hairline — both read as a range slider with a handle to drag. The eye
   sorts a bar into coloured stretches without being told; it cannot help
   reading a detached rounded box as a control. */
.gauge .track { fill: var(--line); }
.gauge .allowed { fill: var(--accent); }
.gauge .tick { stroke: var(--accent); stroke-width: 1.5; }
.gauge .marker { stroke: var(--ink); stroke-width: 3; stroke-linecap: round; }
.gauge.is-pass .marker { stroke: var(--pass); }
.gauge.is-fail .marker { stroke: var(--fail); }
/* THE RANGE IS HTML, NOT SVG TEXT. As `<text>` inside a 240-unit viewBox it
   scaled with the drawing: 8.4px on a 320px phone, and it was also the element
   Firefox measured 3px outside its own viewport when anchored to the edge.
   Real text in the card scales like text, is selectable and translatable, and
   cannot leak past an SVG boundary. */
.scale-range {
  display: flex; justify-content: space-between; gap: 1rem;
  margin: -0.15rem 0 0; max-width: none;
  font: 500 0.76rem/1.3 var(--mono); color: var(--ink-soft);
}
.gauge .wave-mark { stroke: var(--accent); }

/* The gain diagram. Its own classes rather than `stroke="var(--fail)"` on the
   element: a CSS variable inside an SVG presentation attribute is not reliably
   resolved across the three engines this site is tested on, and the failure is
   silent — the stroke simply renders black. */
.diagram { display: block; inline-size: 100%; block-size: auto; }
.diagram .limit { stroke: var(--line-strong); stroke-width: 1.5; stroke-dasharray: 4 4; }
.diagram .arrow { stroke: var(--line-strong); stroke-width: 1.5; fill: none; }
.diagram .arrow-head { fill: var(--line-strong); }
.diagram .bar { stroke-width: 8; stroke-linecap: round; }
.diagram .bar-now { stroke: var(--ink-soft); }
.diagram .bar-pass { stroke: var(--pass); }
.diagram .bar-fail { stroke: var(--fail); }
.diagram .label { fill: var(--ink-soft); font: 500 10px var(--mono); }
.diagram .label-strong { fill: var(--ink); font: 600 10px var(--mono); }
.diagram .label-limit { fill: var(--ink-soft); font: 500 10px var(--sans); letter-spacing: 0.04em; text-transform: uppercase; }

/* A derivation drawn as a chain of boxes. Used where a number a narrator will
   quote a client from is computed from inputs they can change — showing the
   division makes the pace argue-with-able instead of magic. */
.chain { display: block; inline-size: 100%; block-size: auto; }
.chain .box { fill: var(--card); stroke: var(--line-strong); stroke-width: 1.5; }
.chain .box-key { stroke: var(--accent); }
.chain .box-label { fill: var(--ink); font: 600 13px var(--sans); }
.chain .box-note { fill: var(--ink-soft); font: 400 10px var(--sans); }
.chain .op { fill: var(--accent); font: 600 11px var(--mono); }
.chain .arrow { stroke: var(--line-strong); stroke-width: 1.5; fill: none; }
.chain .arrow-head { fill: var(--line-strong); }

/* Chapters as distance from the book's own median. The band means what a
   tinted band means everywhere else here: this stretch is acceptable. */
.spread { display: block; inline-size: 100%; block-size: auto; }
.spread .band { fill: var(--accent-soft); }
.spread .median { stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 5 4; }
.spread .stem { stroke: var(--line-strong); stroke-width: 1.5; }
.spread .point { fill: var(--ink-soft); }
.spread .point-out { fill: var(--fail); }
.spread .label { fill: var(--ink-soft); font: 500 10px var(--mono); }
.spread .label-median { fill: var(--accent); font: 600 10px var(--sans); }
.spread .label-out { fill: var(--fail); font: 600 10px var(--mono); }

/* A reference page has no tool beside its claim, so the hero is one column
   with a reading measure rather than the two-column split. */
.hero-solo { max-width: 46rem; margin-bottom: 1rem; }
.hero-solo .lede { font-size: 1.12rem; color: var(--ink-soft); }

/* A spec card that is also a link into the long-form section for that number.
   The board doubles as the page's table of contents. */
a.spec-card { text-decoration: none; color: inherit; }
a.spec-card:hover { border-color: var(--accent); }
a.spec-card h3 { text-decoration: underline; text-underline-offset: 0.18em; text-decoration-color: var(--line-strong); }

/* The fixability matrix. The question every reader of a requirements list
   actually has is "which of these can be fixed", and the list never says. */
.matrix { width: 100%; min-width: 34rem; border-collapse: collapse; font: 0.94rem/1.45 var(--sans); background: var(--card); }
.matrix th, .matrix td { padding: 0.75rem 0.9rem; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.matrix thead th { font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-soft); }
.matrix tbody td:first-child { font-weight: 600; }
.matrix .verdict { font-family: var(--mono); font-weight: 600; white-space: nowrap; }
.matrix .verdict.yes { color: var(--pass); }
.matrix .verdict.no { color: var(--fail); }
.matrix .verdict.maybe { color: var(--accent); }
/* Measured values line up as a column of readings, so they are set in the
   instrument face and right-aligned with tabular figures. */
.matrix .num { font-family: var(--mono); text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.matrix .pass-cell { font-family: var(--mono); font-weight: 600; color: var(--pass); white-space: nowrap; }
/* The conformance table is seven columns of short readings, and the column that
   matters — what we measured — is the sixth. On a phone the default padding
   pushed it past the edge of the scroller, so the reader had to discover the
   sideways scroll to see the point of the table. Tighter here, and the signal
   description gives up its width first. */
@media (max-width: 40rem) {
  #ebu-conformance .matrix { min-width: 30rem; font-size: 0.8rem; }
  #ebu-conformance .matrix th, #ebu-conformance .matrix td { padding: 0.5rem 0.45rem; }
  #ebu-conformance .matrix tbody td:nth-child(2) { min-inline-size: 6.5rem; }
}

blockquote { margin: 0; padding: 0; }
blockquote p { color: var(--ink-soft); max-width: none; }
blockquote strong { color: var(--ink); }

/* The coupling cycle. Three specifications that move together, drawn as the
   loop a narrator has already lived through twice. */
.cycle { display: block; inline-size: 100%; block-size: auto; }
.cycle .node { fill: var(--card); stroke: var(--line-strong); stroke-width: 1.5; }
.cycle .node-label { fill: var(--ink); font: 600 13px var(--sans); letter-spacing: 0.06em; }
.cycle .edge { stroke: var(--accent); stroke-width: 1.8; fill: none; }
.cycle .edge-head { fill: var(--accent); }
.cycle .edge-label { fill: var(--ink-soft); font: 500 10px var(--sans); }

/* SVG TEXT SCALES WITH THE VIEWBOX, SO A DIAGRAM THAT FITS A PHONE IS A
   DIAGRAM NOBODY ON A PHONE CAN READ. Measured on the live site: the chain and
   the spread rendered their labels at 4.3px, the gain diagram at 6.1px and the
   cycle at 6.8px on an iPhone 13. The responsive matrix passed all of it,
   because it asks about overflow and touch targets and has no opinion about
   whether text is legible.

   So each figure declares the width its smallest label needs to clear 11px,
   and the container scrolls instead of the drawing shrinking — the same answer
   this site already gives for the batch table and the fixability matrix.
   Keyboard-reachable, because a scroll region that only a finger can move is
   not reachable at all. */
.figure-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: var(--radius);
  /* A scroll container inside a grid or flex item does NOT clip until both it
     and its ancestors are allowed to be narrower than their content. An `auto`
     track refuses to shrink, so the card grows instead and the page scrolls
     sideways — the defect this repo already records as "every grid track needs
     minmax(0, ...) or it escapes the card". */
  min-inline-size: 0;
  max-inline-size: 100%;
}
.figure-scroll > svg { display: block; block-size: auto; }
[tabindex]:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* 11px ÷ smallest font in user units × viewBox width, rounded up.
   THE FLOOR MUST ALSO FIT THE DESKTOP CONTAINER, which is the half of this
   check I got wrong first time: `.diagram` sits inside a `.note` inside the
   two-column `.note-grid`, so on every desktop width its container is 543px.
   A 36rem floor — derived from a single 9-unit `label-limit` — clipped the
   page's key explanatory figure by 33px and made it scroll on a 1920 monitor.
   Raising that one class to 10u drops the floor to 32rem, which clears 11px on
   a phone AND fits 543px, so the figure scrolls only where it has to. */
.diagram { min-inline-size: 32rem; }   /* 10u in a 460 viewBox */
.cycle   { min-inline-size: 32rem; }   /* 10u in a 460 viewBox */
.spread  { min-inline-size: 50rem; }   /* 10u in a 720 viewBox */

/* The chain is the one figure that would need 2.5 screens of swiping, and a
   pipeline is the one shape that reads BETTER stacked. It gets a portrait
   drawing instead, on the banner's precedent: two compositions, and the one
   not in use is `display: none` so it has no box at all. */
.chain--portrait { display: none; }
/* Sized so the smallest label still clears 11px on the narrowest phone this
   site is measured at: a 320px viewport puts the drawing in a ~250px card, so
   360 viewBox units scale by 0.69 and 17u is the measured floor. */
.chain--portrait .box-label { font-size: 20px; }
.chain--portrait .box-note { font-size: 17px; }
.chain--portrait .op { font-size: 17px; }
@media (max-width: 44rem) {
  .chain--wide { display: none; }
  .chain--portrait { display: block; }
}

.spec-card {
  display: grid; gap: 0.55rem; align-content: start;
  padding: 1.15rem 1.15rem 1.25rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
}
.spec-card h3 { margin: 0; font: 600 1rem/1.3 var(--sans); }
.spec-card p { margin: 0; color: var(--ink-soft); font: 0.92rem/1.5 var(--serif); max-width: none; }
.spec-card .bound { font: 600 0.88rem/1.3 var(--mono); color: var(--accent); font-variant-numeric: tabular-nums; }
.spec-board { display: grid; gap: 0.9rem; }
@media (min-width: 44rem) { .spec-board { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 72rem) { .spec-board { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* --- the production flow -------------------------------------------------- */

/* Three stages of one production. This was a paragraph containing three links,
   which is the least scannable way to express a sequence. */
.flow { display: grid; gap: 0.9rem; margin: 0; padding: 0; list-style: none; counter-reset: stage; }
@media (min-width: 56rem) { .flow { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.flow li { max-width: none; }
.flow-step {
  display: grid; gap: 0.5rem; block-size: 100%; align-content: start;
  padding: 1.15rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); text-decoration: none; color: inherit;
}
.flow-step:hover { border-color: var(--accent); }
.flow-step .stage-mark { display: flex; align-items: center; gap: 0.6rem; color: var(--accent); font: 700 0.74rem/1 var(--sans); letter-spacing: 0.11em; text-transform: uppercase; }
.flow-step .stage-mark svg { inline-size: 1.5rem; block-size: 1.5rem; flex: none; }
.flow-step strong { font: 600 1.05rem/1.3 var(--sans); }
.flow-step span { color: var(--ink-soft); font: 0.92rem/1.5 var(--serif); }

/* --- tool grid ------------------------------------------------------------ */

.tool-grid { display: grid; gap: 0.9rem; margin: 0; padding: 0; list-style: none; }
@media (min-width: 44rem) { .tool-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 72rem) { .tool-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.tool-grid li { max-width: none; }
.tool-card {
  display: grid; gap: 0.45rem; block-size: 100%; align-content: start; min-block-size: 44px;
  padding: 1.2rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); text-decoration: none; color: inherit;
}
.tool-card:hover { border-color: var(--accent); }
.tool-card[aria-current="page"] { border-color: var(--accent); background: var(--accent-soft); }
.tool-card svg { inline-size: 1.9rem; block-size: 1.9rem; color: var(--accent); }
.tool-card strong { font: 600 1.02rem/1.3 var(--sans); }
.tool-card span { color: var(--ink-soft); font: 0.9rem/1.5 var(--serif); }

/* --- the panel ------------------------------------------------------------ */

.panel { margin-top: 1.5rem; }
.tool .panel:not([hidden]) { border-top: 1px solid var(--line); padding-top: 1.25rem; }

.progress {
  height: 6px;
  border-radius: 3px;
  background: var(--line);
  overflow: hidden;
  margin: 0.5rem 0 1rem;
  font: 0.8rem/6px var(--sans);
  color: var(--ink-soft);
}
.progress::after {
  content: "";
  display: block;
  height: 100%;
  width: calc(var(--fraction, 0) * 100%);
  background: var(--accent);
  transition: width 120ms linear;
}
@media (prefers-reduced-motion: reduce) {
  .progress { background: none; height: auto; line-height: 1.4; }
  .progress::after { display: none; }
}

/* Space is reserved before the table exists, so the page does not jump when
   the first result lands. That is the CLS budget in the build spec. */
.results { min-height: 16rem; }

table.specs { width: 100%; border-collapse: collapse; font-size: 0.94rem; font-family: var(--sans); }
table.specs th, table.specs td { text-align: left; padding: 0.6rem 0.45rem; border-bottom: 1px solid var(--line); vertical-align: top; }
table.specs thead th { font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-soft); }
table.specs .measured { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 600; }
table.specs .requirement { color: var(--ink-soft); font-family: var(--mono); font-size: 0.88em; }
table.specs .mark { text-align: right; font-size: 1.1rem; }
table.specs tr.pass .mark { color: var(--pass); }
table.specs tr.fail .mark { color: var(--fail); }
table.specs tr.fail .measured { color: var(--fail); }
.gap { display: block; font-weight: 400; font-size: 0.85em; color: var(--fail); font-family: var(--mono); }

.primary {
  display: inline-flex; align-items: center; justify-content: center;
  margin-top: 1rem;
  padding: 0.7rem 1.2rem;
  border: 0;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  font: 600 1rem/1.2 var(--sans);
  text-decoration: none;
  cursor: pointer;
  min-height: 44px;
}

/* THE REFUSAL LOOKS AS CONSIDERED AS THE SUCCESS, deliberately.
   When the tool says "this is a re-record, not a fix", that is the screen a
   narrator remembers and reposts, and it is the one no competitor has. It is
   advice, so it is set in the reading serif on the page's own paper with the
   accent rule that marks every other considered aside — never a red error box.
   Red belongs to the specification rows, where it is data. */
.honest {
  margin-top: 1.25rem;
  padding: 1.15rem 1.25rem;
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  background: var(--sunk);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.honest h3 { margin-top: 0; font-size: 1.12rem; }
.quiet { color: var(--ink-soft); font-size: 0.92rem; }

audio { width: 100%; margin-top: 1rem; }

/* Element-agnostic on purpose. A file input is opened by its LABEL, so the two
   controls that pick a folder and pick files are `<label class="ghost">` — and
   while this rule said `button.ghost` they inherited nothing, rendering as
   26px of bare body text where a button belonged. inline-flex is what makes
   min-height mean anything on a label. */
.ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 1rem;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--control-boundary);
  border-radius: var(--radius);
  background: none;
  color: var(--ink-soft);
  font: 0.92rem var(--sans);
  cursor: pointer;
  min-height: 44px;
}
/* The pickers sit in their own row under the drop zone and supply the gap. */
.file-drop-actions .ghost { margin-top: 0; }
/* A label has no :focus of its own, so the ring comes from the input it wraps —
   which is why that input is clipped rather than `hidden`. */
.file-drop-actions .ghost:focus-within { outline: 3px solid var(--accent); outline-offset: 2px; border-color: var(--accent); }

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

/* THE TRACK IS SIZED BY THE CARD, NOT BY THE VIEWPORT.
   This grid used to go to three columns at a `min-width: 44rem` VIEWPORT
   query while living inside the hero's right-hand card, which at 1024–1440 is
   only 409–524px wide. Result: the pace `<select>` got 126–164px for an option
   that needs ~194px, and every engine clipped it — "Typical / 155 wpm" read as
   "155 wpn". A native select cannot ellipsize, so the only real fix is to stop
   promising it a track narrower than its own longest option. 13rem is that
   longest option measured in all three engines, plus the control's padding and
   its dropdown indicator — the loudness preset, not the pace, is the widest
   control on the site, and 768px was the last width where a 13rem floor still
   let three tracks pack in at 220px against its 224px. */
.control-grid {
  display: grid;
  gap: 1rem;
  margin-top: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}
.control-grid label { display: grid; gap: 0.35rem; font: 600 0.92rem/1.35 var(--sans); }
.control-grid small, .section-row small, .measurement-card small { display: block; color: var(--ink-soft); font-weight: 400; font-family: var(--sans); }
select, input[type="number"] {
  inline-size: 100%; min-block-size: 46px; padding: 0.62rem 0.72rem;
  border: 1px solid var(--control-boundary); border-radius: var(--radius);
  background: var(--paper); color: var(--ink); font: inherit; font-family: var(--sans);
}
/* WebKit sizes a native select from its own metrics and ignored the logical
   minimum: 36 rows of the responsive matrix failed on it. An explicit block
   size is the only thing all three engines agreed on. */
select { block-size: 46px; }
input[type="number"] { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.input-unit { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.55rem; }
.input-unit b { color: var(--ink-soft); font: 600 0.85rem var(--mono); }

.section-list { display: grid; gap: 0.35rem; margin-top: 1rem; max-height: 24rem; overflow: auto; }
.section-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 0.75rem;
  min-block-size: 44px; padding: 0.65rem; border: 1px solid var(--line); border-radius: var(--radius);
  font-family: var(--sans);
}
.section-row input { margin-top: 0.3rem; inline-size: 1.1rem; block-size: 1.1rem; }
.section-row strong { display: block; overflow-wrap: anywhere; }

/* --- readouts ------------------------------------------------------------- */

.metric-grid, .measurement-grid { display: grid; gap: 0.75rem; margin-top: 1.2rem; }
.metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.metric-card, .measurement-card { padding: 0.95rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--sunk); }
.metric-card span, .measurement-card strong { display: block; color: var(--ink-soft); font: 0.78rem/1.3 var(--sans); text-transform: uppercase; letter-spacing: 0.06em; }
.metric-card strong { display: block; margin-top: 0.3rem; font: 600 1.45rem/1.2 var(--mono); font-variant-numeric: tabular-nums; text-transform: none; letter-spacing: -0.01em; color: var(--ink); }
.measurement-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.measurement-card span { display: block; margin: 0.35rem 0; font: 600 1.4rem/1.2 var(--mono); font-variant-numeric: tabular-nums; }
@media (max-width: 38rem) { .measurement-grid { grid-template-columns: 1fr; } }

/* Same rule as .figure-scroll above: a scroll container inside a grid item
   does not clip until it and its ancestors may be narrower than their
   content. Without these two lines the batch results table widened the whole
   page on a phone. */
.table-scroll { overflow: auto; margin-top: 1rem; border: 1px solid var(--line); border-radius: var(--radius); min-inline-size: 0; max-inline-size: 100%; }
.batch-table { width: 100%; min-width: 48rem; border-collapse: collapse; font: 0.9rem/1.35 var(--sans); }
.batch-table th, .batch-table td { padding: 0.7rem; border-bottom: 1px solid var(--line); text-align: left; font-variant-numeric: tabular-nums; }
.batch-table td { font-family: var(--mono); }
.batch-table td:first-child { max-width: 18rem; overflow-wrap: anywhere; font-family: var(--sans); }
.batch-table th { position: sticky; top: 0; background: var(--card); font-family: var(--sans); text-transform: uppercase; font-size: 0.76rem; letter-spacing: 0.06em; color: var(--ink-soft); }
.summary-line { font-weight: 600; }

/* --- reference and explanation surfaces ----------------------------------- */

/* The rejection guide was 120 lines of prose about causes and fixes. A reader
   arrives at it holding one symptom and wants the branch that matches, so it
   is a two-column card — symptom on the left, what to do on the right. */
.diagnosis { display: grid; gap: 0.9rem; margin: 0; padding: 0; list-style: none; }
.diagnosis li { max-width: none; }
.diagnosis-card {
  display: grid; gap: 0.65rem; padding: 1.15rem;
  border: 1px solid var(--line); border-left: 4px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0; background: var(--card);
}
@media (min-width: 56rem) {
  .diagnosis-card { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: 1.5rem; align-items: start; }
}
.diagnosis-card h3 { margin: 0; font: 600 1.02rem/1.35 var(--sans); }
.diagnosis-card .symptom { color: var(--fail); font: 0.86rem/1.4 var(--mono); }
.diagnosis-card p { margin: 0 0 0.6rem; max-width: none; }
.diagnosis-card p:last-child { margin-bottom: 0; }

.note-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.9rem; align-items: start; }
@media (min-width: 56rem) { .note-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.note {
  padding: 1.15rem 1.25rem; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--card);
  min-inline-size: 0;
}
.note h3 { margin: 0 0 0.45rem; font: 600 1.02rem/1.3 var(--sans); }
.note p { margin: 0 0 0.7rem; max-width: none; }
.note p:last-child { margin-bottom: 0; }
.note ul { margin: 0; padding-left: 1.1rem; }
.note li { max-width: none; margin-bottom: 0.35rem; }

/* A refusal list. What a tool declines to do is a feature statement here, so
   it gets a mark of its own rather than hiding in a paragraph. */
.refusals { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.6rem; }
.refusals li {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0.7rem; align-items: start;
  max-width: none; color: var(--ink-soft); font: 0.95rem/1.5 var(--serif);
}
.refusals svg { inline-size: 1.15rem; block-size: 1.15rem; margin-top: 0.2rem; color: var(--line-strong); flex: none; }

.formula {
  display: block; margin: 0 0 0.9rem; padding: 0.9rem 1rem;
  background: var(--sunk); border: 1px solid var(--line); border-radius: var(--radius);
  font: 0.95rem/1.6 var(--mono); overflow-x: auto; white-space: nowrap;
}

/* A reading column, CENTRED in the wide shell. Left-aligned it left a third
   of a 1440 viewport empty beside every legal page and read as a layout bug
   rather than a measure. */
.prose { max-width: 44rem; margin-inline: auto; }
.prose h2 { margin-top: 2.2rem; }
.prose h3 { margin-top: 1.5rem; }

dl.specs-list dt { font-weight: 600; margin-top: 1rem; }
dl.specs-list dd { margin: 0.2rem 0 0; color: var(--ink-soft); max-width: var(--measure); }

.tool-links { margin-top: 2.2rem; padding: 0.25rem 1rem 0.1rem; border-left: 4px solid var(--accent); }
.tool-links h2 { margin-top: 0; }

/* --- footer --------------------------------------------------------------- */

/* EVERY ROUTE, GROUPED THE WAY THE HEADER GROUPS IT. The hand-copied footers
   listed seven to fifteen of twenty routes, and three converter pages were
   linked from exactly one other page on the whole site. */
.site-footer {
  margin-top: 3.5rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line);
  font: 0.9rem var(--sans);
  color: var(--ink-soft);
}
.footer-nav {
  display: grid; gap: 1.1rem 1.25rem; margin-bottom: 1rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 44rem) { .footer-nav { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .footer-nav { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.footer-title {
  margin: 0 0 0.2rem; font: 700 0.72rem/1.2 var(--sans);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink);
}
.footer-group ul { margin: 0; padding: 0; list-style: none; }
.footer-group li { max-width: none; }
.site-footer a { display: flex; align-items: center; min-height: 44px; line-height: 1.25; overflow-wrap: anywhere; }
.site-footer a[aria-current="page"] { color: var(--ink); text-decoration: none; font-weight: 600; }
/* The honesty line is trust work for a stranger being asked to open an NDA'd
   manuscript in someone's web page. It stays legible, not greyed to nothing. */
.site-footer > p { color: var(--ink); max-width: 46rem; }

/* The audible before/after transport under a fixed file's download. */
.preview-row { display: grid; gap: 0.5rem; margin-top: 1rem; }
.preview-transport { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.preview-clock { font-variant-numeric: tabular-nums; color: var(--ink-soft); font-size: 0.9rem; }
#preview-wave { width: 100%; height: 44px; display: block; }
#preview-seek { width: 100%; accent-color: var(--accent); block-size: 28px; }
#preview-wave { cursor: pointer; }

/* The homepage FAQ, injected at build time from one source of truth. */
.faq-item + .faq-item { margin-top: 1.1rem; }
.faq-item h3 { margin: 0 0 0.35rem; font-size: 1.02rem; }
.faq-item p { margin: 0; color: var(--ink-soft); }

/* Audible spec demonstrations: synthesized clips on the reference page. */
.demo-slot { margin: 1rem 0 1.6rem; padding: 0.9rem 1.1rem; background: var(--sunk); border: 1px solid var(--line); border-radius: var(--radius); }
.demo-slot > p { margin: 0 0 0.5rem; }
.demo-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.5rem; }
.demo-row button[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.demo-note:empty { display: none; }

/* The room test's live input meter and verdict. */
.room-meter { --level: 0; --progress: 0; position: relative; block-size: 14px; margin: 0.9rem 0; border-radius: 7px; background: var(--sunk); border: 1px solid var(--line); overflow: hidden; }
.room-meter::before { content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: calc(var(--level) * 100%); background: var(--accent); opacity: 0.85; }
.room-meter::after { content: ""; position: absolute; inset-block-end: 0; inset-inline-start: 0; inline-size: calc(var(--progress) * 100%); block-size: 3px; background: var(--ink-soft); }
.room-verdict { margin-top: 1rem; }
.room-verdict.room-pass { border-inline-start: 3px solid var(--pass); }
.room-verdict.room-warn { border-inline-start: 3px solid var(--accent); }
.room-verdict.room-fail { border-inline-start: 3px solid var(--fail); }
.room-phases { margin: 0 0 1rem; padding-inline-start: 1.2rem; color: var(--ink-soft); font-size: 0.94rem; }
.room-phases li + li { margin-top: 0.4rem; }
.room-phases strong { color: var(--ink); }

/* The delivery-target picker above the chapter drop zone. */
.target-picker { display: grid; gap: 0.35rem; margin: 1rem 0 0; }
.target-picker > span { font: 700 0.74rem/1.2 var(--sans); letter-spacing: 0.11em; text-transform: uppercase; color: var(--ink-soft); }
.target-picker select { inline-size: 100%; min-block-size: 46px; }
.target-picker small { color: var(--ink-soft); font-size: 0.86rem; }

/* The suite bar: what else is here, stated in the hero rather than 70% down
   the page. Compact on purpose — the descriptive grid follows immediately. */
.suite { margin-top: 1.4rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.suite-label { margin: 0 0 0.55rem; font: 700 0.72rem/1.2 var(--sans); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); }
.suite ul { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0; padding: 0; list-style: none; }
.suite a {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.42rem 0.7rem; border: 1px solid var(--control-boundary); border-radius: 999px;
  font: 600 0.86rem/1.1 var(--sans); color: var(--ink); text-decoration: none; background: var(--card);
}
.suite a:hover { border-color: var(--accent); color: var(--accent); }
.suite svg { inline-size: 1.05rem; block-size: 1.05rem; color: var(--accent); }

/* Each tool card now carries the stage it belongs to and what it hands back. */
.tool-card .stage { font: 700 0.68rem/1.2 var(--sans); letter-spacing: 0.09em; text-transform: uppercase; color: var(--accent); }
.tool-card .gives { margin-top: 0.15rem; font-size: 0.84rem; color: var(--ink-soft); font-style: italic; }

/* Ten cards: two rows of five on a desktop, pairs below it. Five was three
   columns (3 + 2) when the grid held five tools and claimed that was all of
   them; the site had ten. */
@media (min-width: 72rem) { .tool-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }

/* Trust chips and the suite bar sit below the pitch on a desktop and below
   the drop zone on a phone, without reordering anything: they are a third
   grid item, so the layout moves them and the reading order never changes. */
.hero-extras { display: grid; gap: 0; }
@media (min-width: 64rem) {
  .hero-extras { grid-column: 1; }
  /* The tool spans both rows, so the chips sit directly under the pitch
     instead of below the whole tool card with a column of air beside it. */
  .hero:has(> .hero-extras) { grid-template-rows: auto 1fr; }
  .hero > .tool:has(+ .hero-extras) { grid-column: 2; grid-row: 1 / span 2; }
}
.hero-extras .suite { margin-top: 1.1rem; }
/* The illustration is decoration, and on a phone it was pushing the one
   control that matters below the fold. */
@media (max-width: 48rem) {
  /* Height alone squashes an SVG that carries its own viewBox — the book came
     out squat. Constrain both and let the aspect ratio decide the width. */
  .hero-art { max-block-size: 88px; inline-size: auto; max-inline-size: 100%; margin-inline: auto; }
  .hero-banner { margin-bottom: 1.25rem; }
}

/* The batch intake takes a folder as well as files, so the drop zone carries
   two explicit choices rather than one implicit one. */
.file-drop-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; margin-top: 0.9rem; }
.file-drop-actions .ghost { cursor: pointer; }
.batch-table tr[data-state="queued"] td,
.batch-table tr[data-state="measuring"] td,
.batch-table tr[data-state="fixing"] td { color: var(--ink-soft); }
.queue-state { font-variant-numeric: tabular-nums; }
.batch-table tr[data-state="measuring"] .queue-state,
.batch-table tr[data-state="fixing"] .queue-state { color: var(--accent); }
/* Fixed position in the flow: the queue control must not drift down the page
   as the table it governs grows a row per chapter. */
.queue-control { margin-bottom: 0.75rem; }

/* The microphone test's live meter.
   The bar alone is what every competing mic test shows, and it answers "can we
   hear you" rather than "is my level right". The zone colour and the dBFS
   readout beside it are the answer; the scale underneath names the zones so the
   colour is not the only carrier of the meaning. */
.mic-meter-row { margin: 0.9rem 0 0.2rem; }
.mic-meter[data-zone="quiet"]::before { background: var(--ink-soft); }
.mic-meter[data-zone="good"]::before { background: var(--pass); }
.mic-meter[data-zone="clipping"]::before { background: var(--fail); }
.mic-meter-scale {
  display: flex; justify-content: space-between; margin: 0.15rem 0 0;
  font: 600 0.7rem/1.2 var(--sans); letter-spacing: 0.07em; text-transform: uppercase; color: var(--ink-soft);
}
.mic-meter-value { margin: 0.35rem 0 0; font: 600 1.05rem/1.2 var(--mono); font-variant-numeric: tabular-nums; color: var(--ink); }
.mic-meter-value[data-zone="clipping"] { color: var(--fail); }
.mic-meter-value[data-zone="good"] { color: var(--pass); }
/* A device name is somebody else's string and can be long; it must wrap rather
   than widen the card, which is what broke the figure-legibility check once. */
.mic-device-name { font-size: 1rem !important; overflow-wrap: anywhere; }
#mic-wave { width: 100%; height: 44px; display: block; }
.mic-next { margin-top: 1rem; }

/* The calculator's pasted-text path. Collapsed by default: the manuscript drop
   is the primary job and a textarea above it would bury the thing most visitors
   came for. */
.paste-text { margin-top: 1rem; border: 1px solid var(--line); border-radius: var(--radius); padding: 0.85rem 1rem; background: var(--sunk); }
.paste-text > summary { cursor: pointer; font: 600 0.95rem/1.3 var(--sans); color: var(--ink); }
.paste-text > summary:hover { color: var(--accent); }
.paste-text textarea {
  inline-size: 100%; min-block-size: 8rem; margin-top: 0.6rem; padding: 0.65rem;
  border: 1px solid var(--control-boundary); border-radius: var(--radius);
  background: var(--card); color: var(--ink); font: 0.95rem/1.5 var(--sans); resize: vertical;
}
#paste-count { margin: 0.5rem 0 0; font-variant-numeric: tabular-nums; }

/* The denoiser's strength slider. A range input is 20-ish pixels tall by
   default and the responsive matrix refuses anything under 44 on a phone —
   correctly, because a thumb does not get smaller on a small screen. */
/* `margin: 0` matters: a range input carries a default horizontal margin, so
   `inline-size: 100%` overflows the label it sits in by exactly that much. */
#denoise-strength { inline-size: 100%; max-inline-size: 100%; margin: 0; min-block-size: 44px; accent-color: var(--accent); box-sizing: border-box; }
#denoise-strength-value { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
#denoise-results { margin-top: 0; }
#denoise-actions { display: grid; gap: 0.75rem; margin-top: 1rem; }

/* The joiner's ordered parts list. A row is a name plus its controls, and the
   name is somebody else's file name — it wraps rather than pushing the buttons
   off a phone. */
.edit-list { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: 0.5rem; }
.edit-row {
  display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center;
  padding: 0.6rem 0.8rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--sunk);
}
.edit-row-name { flex: 1 1 12rem; min-inline-size: 0; overflow-wrap: anywhere; font: 600 0.95rem/1.4 var(--sans); }
.edit-row button { min-block-size: 44px; }
#edit-run { margin-top: 1rem; }
#edit-actions { display: grid; gap: 0.75rem; margin-top: 1rem; }

/* WebKit sizes a <select> to its widest option's intrinsic width and ignores
   `inline-size: 100%` doing it, so a long option label pushes the page wider
   than the phone. The labels are short now; this is the belt to that braces. */
.target-picker select { max-inline-size: 100%; }

/* "Was this result what you needed?" — after the work, never before it, and
   never as an overlay. It sits in the flow where the download already is. */
.feedback { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--line); display: grid; gap: 0.6rem; }
.feedback-question { margin: 0; font: 600 0.98rem/1.4 var(--sans); color: var(--ink); }
.feedback-votes { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.feedback-vote { min-block-size: 44px; }
.feedback textarea {
  inline-size: 100%; max-inline-size: 100%; box-sizing: border-box; min-block-size: 6rem; padding: 0.65rem;
  border: 1px solid var(--control-boundary); border-radius: var(--radius);
  background: var(--card); color: var(--ink); font: 0.95rem/1.5 var(--sans); resize: vertical;
}
.feedback-send { justify-self: start; min-block-size: 44px; display: inline-flex; align-items: center; }
.feedback-thanks { margin: 0; }

/* --- tool first on a phone -------------------------------------------------- */

/* Measured before this wave at 390x844: the home tool card began at ~830px,
   behind a five-row nav, a 200px illustration, the H1 and a seven-line lede.
   Under 600px the illustration goes, and a tool page's trust chips move out of
   the way — the drop zone's own hint already says nothing is uploaded. */
@media (max-width: 37.49rem) {
  .hero-banner { display: none; }
  .hero-copy .chips, .hero-copy .suite { display: none; }
  .hero { gap: 1.1rem; }
  h1 { font-size: 1.7rem; }
  .hero-copy .lede { font-size: 1.02rem; margin-bottom: 0; }
}

/* --- "Try a sample chapter" -------------------------------------------------- */

.sample-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: 0.9rem; }
.sample-row .sample-label { flex-basis: 100%; margin: 0; font: 600 0.9rem/1.35 var(--sans); color: var(--ink); }
.sample-row .ghost { margin-top: 0; }
.sample-row .sample-note { flex-basis: 100%; margin: 0; font-size: 0.84rem; }

/* --- the verdict, in one line ------------------------------------------------ */

/* Colour is never the only carrier: the mark and the words say the same thing
   as the tint, and the tint is a border, not a fill a phone in sunlight loses. */
.verdict-banner {
  display: flex; align-items: center; gap: 0.6rem;
  margin: 0 0 1rem; max-width: none;
  padding: 0.8rem 1rem; border: 1px solid var(--line); border-inline-start-width: 5px;
  border-radius: var(--radius); background: var(--sunk);
  font: 700 1.05rem/1.3 var(--sans); color: var(--ink);
}
.verdict-banner[data-verdict="pass"] { border-inline-start-color: var(--pass); }
.verdict-banner[data-verdict="fixable"] { border-inline-start-color: var(--accent); }
.verdict-banner[data-verdict="rerecord"], .verdict-banner[data-verdict="blocked"] { border-inline-start-color: var(--fail); }
.verdict-mark { font-size: 1.2rem; line-height: 1; }
.verdict-banner[data-verdict="pass"] .verdict-mark { color: var(--pass); }
.verdict-banner:not([data-verdict="pass"]) .verdict-mark { color: var(--fail); }
/* Inside the batch summary line the banner is a block of its own above it. */
.summary-line .verdict-banner { margin-bottom: 0.6rem; }

/* The specification table becomes one card per specification on a phone:
   label and mark on a line, the measured value under it, the requirement under
   that with its column heading carried along. Roles in app.js keep it a table
   for assistive technology whatever the display does. */
@media (max-width: 37.49rem) {
  table.specs thead { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }
  table.specs, table.specs tbody { display: block; }
  table.specs tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.2rem 0.75rem;
    margin-bottom: 0.6rem; padding: 0.75rem 0.85rem;
    border: 1px solid var(--line); border-radius: var(--radius); background: var(--card);
  }
  table.specs tr.fail { border-inline-start: 4px solid var(--fail); }
  table.specs tr.pass { border-inline-start: 4px solid var(--pass); }
  table.specs th, table.specs td { display: block; padding: 0; border: 0; }
  table.specs th[scope="row"] { grid-column: 1; grid-row: 1; font-weight: 600; }
  table.specs td.mark { grid-column: 2; grid-row: 1; }
  table.specs td.measured { grid-column: 1 / -1; }
  table.specs td.requirement { grid-column: 1 / -1; }
  table.specs td.requirement::before { content: attr(data-label) ": "; font-family: var(--sans); }

  .batch-table { min-width: 0; }
  .batch-table thead { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }
  .batch-table, .batch-table tbody, .batch-table tr, .batch-table td { display: block; }
  .batch-table tr { padding: 0.65rem 0.8rem; border-bottom: 1px solid var(--line); }
  .batch-table td { padding: 0.12rem 0; border: 0; }
  .batch-table td[data-label] { display: flex; justify-content: space-between; gap: 1rem; }
  .batch-table td[data-label]::before { content: attr(data-label); color: var(--ink-soft); font-family: var(--sans); }
  .batch-table td:first-child { max-width: none; font-weight: 600; }
}

/* --- where to go from here ----------------------------------------------------- */

.next-steps { margin-top: 1.4rem; }
.next-steps h3 { margin: 0 0 0.6rem; font: 700 0.74rem/1.2 var(--sans); letter-spacing: 0.11em; text-transform: uppercase; color: var(--ink-soft); }
.next-steps ul { display: grid; gap: 0.6rem; margin: 0; padding: 0; list-style: none; }
@media (min-width: 44rem) { .next-steps ul { grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); } }
.next-steps li { max-width: none; }
.next-card {
  display: grid; gap: 0.25rem; block-size: 100%; min-block-size: 44px;
  padding: 0.85rem 1rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--sunk); color: inherit; text-decoration: none;
}
.next-card:hover { border-color: var(--accent); }
.next-card strong { font: 600 0.98rem/1.3 var(--sans); color: var(--accent); }
.next-card span { font: 0.88rem/1.45 var(--sans); color: var(--ink-soft); }

/* The home page's spec cards carry their own demonstration buttons. */
.demo-slot--compact { margin: 0.35rem 0 0; padding: 0; background: none; border: 0; }
.demo-slot--compact .demo-row { margin-bottom: 0; }
.demo-slot--compact .ghost { margin-top: 0; padding: 0.4rem 0.7rem; font-size: 0.84rem; }

/* --- the joiner's output choice, and the chapters it wrote ------------------- */

/* A real fieldset of radios, each label a 44px target. A browser with no AAC
   encoder gets the M4B radio disabled and the reason in the note under it. */
.output-choice { display: grid; gap: 0.45rem; margin: 1rem 0 0; padding: 0; border: 0; min-inline-size: 0; }
.output-choice legend { padding: 0; margin-bottom: 0.35rem; font: 700 0.74rem/1.2 var(--sans); letter-spacing: 0.11em; text-transform: uppercase; color: var(--ink-soft); }
.output-choice label { display: flex; align-items: flex-start; gap: 0.6rem; min-block-size: 44px; padding: 0.55rem 0.75rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--sunk); font: 600 0.94rem/1.35 var(--sans); cursor: pointer; }
.output-choice label:has(input:checked) { border-color: var(--accent); }
.output-choice label:has(input:disabled) { cursor: not-allowed; opacity: 0.7; }
.output-choice input { margin-top: 0.2rem; inline-size: 1.1rem; block-size: 1.1rem; accent-color: var(--accent); flex: none; }
.output-choice small { display: block; color: var(--ink-soft); font-weight: 400; }
.output-choice .quiet { margin: 0.2rem 0 0; font-size: 0.86rem; }
.chapter-list { grid-column: 1 / -1; margin: 0; padding-inline-start: 1.4rem; font: 0.92rem/1.5 var(--sans); }
.chapter-list .chapter-at { display: inline-block; min-inline-size: 3.2rem; font-family: var(--mono); color: var(--ink-soft); font-variant-numeric: tabular-nums; }
#edit-results > p.quiet { grid-column: 1 / -1; margin: 0; }
.tone-subhead { margin: 1.2rem 0 0.6rem; font: 700 0.74rem/1.2 var(--sans); letter-spacing: 0.11em; text-transform: uppercase; color: var(--ink-soft); }

/* --- the checking aids: read-back, pronunciation guide, proof-listen -------- */

/* A chapter title is somebody else's heading and can be long; a native select
   cannot ellipsize, and WebKit lets the widest option's text overflow the
   control's own box: measured 2026-09-23 at 390px, a 50-character chapter title
   left the select 314px wide but made the PAGE 486px wide, with no element's
   rectangle past the edge to find it by. `overflow: hidden` on the select is the
   one property that brought the page back to 390 (ellipsis, width, min-width and
   containment did not). */
.control-grid select { inline-size: 100%; max-inline-size: 100%; min-inline-size: 0; overflow: hidden; }
/* The label is a grid of its own; its implicit `auto` column is sized to the
   select's min-content — the longest option — unless it is told it may shrink.
   Linux WebKit in CI widened the page to 577px at 390 through exactly this. */
.control-grid label { min-inline-size: 0; grid-template-columns: minmax(0, 1fr); }

/* A primary action beside a ghost one in the same row: the row supplies the gap,
   so neither carries its own top margin, or the two sit at different heights. */
.file-drop-actions .primary { margin-top: 0; }
.panel .file-drop-actions, .tool > .file-drop-actions { margin-top: 1rem; }

/* Hashes and archive URLs on /licences/ are single 64-character words. */
.prose code { overflow-wrap: anywhere; }

/* The second drop zone (proof-listen's manuscript) is the smaller of the two. */
.file-drop--second { margin-top: 0.75rem; min-block-size: 6rem; padding: 1.1rem 1rem; }

/* One row per word: the word and where it was found, the hint, and its controls.
   Stacks on a phone; three columns once the card has room. */
.guide-list { display: grid; gap: 0.5rem; margin-top: 1rem; max-block-size: 34rem; overflow: auto; }
.guide-row {
  display: grid; gap: 0.5rem; grid-template-columns: minmax(0, 1fr);
  padding: 0.7rem 0.8rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--sunk);
}
.guide-word strong { display: block; font: 600 1rem/1.3 var(--sans); overflow-wrap: anywhere; }
.guide-word small { display: block; color: var(--ink-soft); font: 0.84rem/1.45 var(--sans); }
.guide-example { font-style: italic; overflow-wrap: anywhere; }
.guide-hint input, .guide-add input {
  inline-size: 100%; min-block-size: 44px; padding: 0.55rem 0.7rem;
  border: 1px solid var(--control-boundary); border-radius: var(--radius);
  background: var(--paper); color: var(--ink); font: 0.98rem/1.3 var(--sans);
}
.guide-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.guide-controls .ghost { margin-top: 0; }
.guide-ok { display: inline-flex; align-items: center; gap: 0.4rem; min-block-size: 44px; font: 600 0.92rem var(--sans); cursor: pointer; }
.guide-ok input { inline-size: 1.1rem; block-size: 1.1rem; accent-color: var(--accent); }
.guide-add { display: grid; gap: 0.35rem; margin-top: 1rem; font: 600 0.92rem/1.35 var(--sans); }
.guide-add .ghost { margin-top: 0; }
@media (min-width: 60rem) {
  .guide-row { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto; align-items: center; }
}

/* Proof-listen's list: a timecode, what differed, and a button to hear it. */
.proof-list { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: 0.5rem; }
.proof-row {
  display: grid; gap: 0.35rem 0.75rem; grid-template-columns: auto minmax(0, 1fr); align-items: start;
  padding: 0.7rem 0.8rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--sunk);
}
.proof-row .ghost { grid-column: 1 / -1; justify-self: start; margin-top: 0; }
.proof-time { font: 600 0.95rem/1.4 var(--mono); font-variant-numeric: tabular-nums; color: var(--ink); }
.proof-what { display: grid; gap: 0.15rem; font: 0.94rem/1.45 var(--sans); overflow-wrap: anywhere; }
.proof-what strong { font-weight: 600; }
@media (min-width: 48rem) {
  .proof-row { grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; }
  .proof-row .ghost { grid-column: auto; }
}
/* --- the developer API pages ---------------------------------------------------

   A code block scrolls inside itself: a curl line is wider than a phone, and a
   page that scrolls sideways because of one is mindatlas's trap 7 (a 912px
   /developers/ at a 390px viewport). */
.code-block {
  margin: 1rem 0; padding: 0.9rem 1rem; overflow-x: auto; max-inline-size: 100%;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--sunk);
  font: 0.84rem/1.5 var(--mono); color: var(--ink);
}
.code-block code { white-space: pre; }
.prose code { overflow-wrap: anywhere; }
.api-status { margin-block: 1.5rem; }
.api-status h3 { margin: 0 0 0.35rem; }
.api-status p { margin: 0; }
.account-mount { margin-block: 1.5rem; }
.account-lead { font: 600 1.05rem/1.4 var(--sans); }
.account-table th { text-align: left; }
.text-input {
  inline-size: 100%; min-block-size: 46px; padding: 0.62rem 0.72rem;
  border: 1px solid var(--control-boundary); border-radius: var(--radius);
  background: var(--paper); color: var(--ink); font: 0.95rem var(--sans);
}
.key-mint { display: grid; gap: 0.6rem; grid-template-columns: minmax(0, 1fr); margin-top: 1rem; }
.key-mint .primary, .key-mint .ghost { margin-top: 0; }
.key-line { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }
.key-secret { font: 600 0.9rem/1.4 var(--mono); overflow-wrap: anywhere; }
.key-line .ghost { margin-top: 0; }
