:root {
  color-scheme: light;
  --ink: #0D171D;
  --teal: #0B8392;
  --slate: #819098;
  --mist: #E8ECEE;
  --paper: #FFFFFF;
  --soft: #F6F8F9;
  --line: #CFD7DB;
  --line-strong: #AEBBC1;
  --bench: #101D24;
  --bench-2: #182933;
  --bench-3: #223640;
  --teal-soft: #E2F3F5;
  --muted: #52646D;
  --muted-2: #65757D;
  --teal-on-dark: #8FD3DD;
  --on-fill: #FFFFFF;
  --body-text: #0D171D;
  --red: #B9504B;
  /* --red is a warning on paper and is barely legible on the rack, so the dark
     surface has its own. It was already in the stylesheet as a raw hex on one
     Bench rule; naming it is what let the demo's error line use the same red
     without a second spelling of it. */
  --red-on-dark: #E7A6A2;
  /* The same pair for a figure that has moved the good way: --green is a fill and
     is about 3.5:1 as text on the rack, so the dark surface reads this one. */
  --green-on-dark: #8FD3A8;
  /* What a failure message is coloured. --red on paper, --red-on-dark on the
     rack, so one rule serves both and no view has to patch it. It exists
     because .status.error hardcoded #FFD2CF - a dark-surface pink - and was
     applied globally, so on the light Collection every Add Record failure
     rendered at about 1.3:1 and said nothing anybody could read. */
  --danger-text: #B9504B;
  --green: #2E8A57;
  /* "Changed" on a drift reading: a caution, not a failure. The rack's own
     amber (#E8B25C, Set up's --amber) is too pale on paper, so the dark
     surfaces redefine it below as they do --danger-text. */
  --amber: #A86A12;
  --shadow: 0 18px 48px rgba(13, 23, 29, .08);
  --radius: 4px;
  /* The content column, named once. The pinned transport is outside .app-main -
     it is fixed to the viewport - and has to sit on the same axis as the
     instruments above it, so the width lives in a token rather than in two
     places that can drift apart. */
  --page-column: min(1220px, calc(100% - 40px));
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--mist);
  color: var(--body-text);
}

button, input, select { font: inherit; }

button {
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  padding: 12px 16px;
  background: var(--ink);
  color: var(--on-fill);
  font-weight: 800;
  cursor: pointer;
}

button:hover:not(:disabled) { border-color: var(--teal); background: var(--teal); }
button:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 3px;
}
button:disabled { opacity: .42; cursor: not-allowed; }

/* The header (Home, Bench, Collection, the account menu) is `shell/frame.js`'s
   own module now (`docs/briefs/navigation.md`), styled by `shell/frame.css`
   rather than the rules that used to live here for `.app-header`,
   `.brand-lockup`, `.primary-nav`, `.nav-link`, `.account-area`, `.auth-user`
   and `.account-button` - none of index.html, bench/setup.html or the static
   pages carries that markup any more. */
.section-number {
  display: block;
  color: var(--teal);
  font: 800 .68rem/1.35 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .1em;
}

.app-main {
  width: var(--page-column);
  margin: 0 auto;
  padding: 34px 0 72px;
}
/* THE BENCH AND THE COLLECTION RUN NEARLY FULL WIDTH (Jacob, 28 Sep: "Is
   there some good reason that I'm only using half the available width?",
   `docs/briefs/navigation.md`). One `.app-main` wraps every route, so its own
   width has to change per route rather than in one place - the same `:has()`
   the pinned transport's footer padding above already uses for the same
   reason. The value is `shell/frame.css`'s `.tool-page` rule, restated rather
   than shared: the two stylesheets are deliberately independent, so neither
   page has to load the other's. Home keeps `--page-column`, unmentioned here
   on purpose - its reading column is not this brief's to widen. */
body:has(#bench-view:not([hidden])) .app-main,
body:has(#collection-view:not([hidden])) .app-main {
  width: min(1600px, 100% - 2 * clamp(16px, 3vw, 40px));
}

/* THE FOOTER, ON EVERY PAGE (area 1 finding 3, built once Brainstorm said the
   privacy and terms drafts were approved, 28 Sep). Outside .app-main, a
   sibling of the header, so it shows under whichever view is current rather
   than being one more thing each view has to remember to draw. */
.site-footer {
  width: var(--page-column);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  padding: 24px 0 40px;
  color: var(--muted);
  font-size: .85rem;
}
.site-footer a { color: var(--muted); text-decoration: none; }
.site-footer a:hover { color: var(--teal); text-decoration: underline; }
/* The Bench's transport is pinned to the bottom of the viewport while that
   route is open (screen height allowing) - #bench-view reserves the same
   clearance for its own last unit, and the footer needs it too, or scrolling
   to the very end slides it in behind the dock. */
body:has(#bench-view:not([hidden])) .site-footer { padding-bottom: 170px; }
/* ...and not before there is a result: the dock is hidden then, so nothing
   needs the clearance (see "[data-needs-result]" on the Bench). */
body:has(#bench-view:not([hidden]) .transport-dock[hidden]) .site-footer { padding-bottom: 40px; }

.app-view[hidden], .hidden { display: none !important; }
.workbench, .results { margin-bottom: 48px; }

/* ---- Account -----------------------------------------------------------------
   Profile and preferences (`docs/briefs/navigation.md`, /#account). A reading
   page, not a tool page - three short facts and the two controls each one
   implies, so it keeps the narrow column the brief asks reading pages to keep
   rather than `.tool-page`'s near-full width. */
#account-view { max-width: 560px; display: grid; gap: 20px; }
/* `:not([hidden])`, the same guard `.home-cases` carries and
   `tests/styles-tokens.test.cjs` checks for: `account/view.js` toggles this
   element's `hidden` attribute, and an unguarded `display` here would beat
   it permanently, the same failure that left the library's filing panel
   open from page load. */
.account-signed-out:not([hidden]) { display: grid; gap: 14px; }
#account-title { margin: 0; }
.account-email { margin: 0; color: var(--muted); }
.account-section { display: grid; gap: 6px; padding: 16px 0; border-top: 1px solid var(--line); }
.account-section h2 { margin: 0; font-size: 1rem; }
.account-section p { margin: 0; color: var(--muted); }
.account-levels .level-group { display: grid; gap: 10px; margin-top: 10px; }
.account-levels .level-group h3 { margin: 8px 0 0; font-size: .95rem; }
.level-row { display: grid; gap: 4px; padding: 10px 0; border-top: 1px solid var(--line); }
.account-levels .level-heading { color: inherit; }
.account-levels .level-name { margin: 0; font-size: 0.95rem; }
.level-edit { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.level-field { display: inline-flex; align-items: center; gap: 4px; }
.level-field input { width: 7em; }
.account-levels .level-status:empty { display: none; }
.account-close { color: var(--muted); font-size: .9rem; }

/* ---- Home ------------------------------------------------------------------
   The front of the instrument, drawn on the rack's surface. `body.is-rack`
   redefines the surface tokens for this route the same way it does for the
   Bench, so everything below names tokens and never a colour: --paper is the
   faceplate, --soft the recess behind it, --line and --line-strong its edges,
   --muted its engraved labels, --teal-on-dark its readable accent. The same
   rules therefore hold on the light palette, which is what they fall back to if
   the body class is ever not there. */
.home-view {
  display: grid;
  /* One explicit column that may shrink: with no column set, the grid sizes
     itself to its widest word and a narrow phone scrolls sideways. */
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
}
/* The demo's welcome panel (demo/welcome.js): once, under the demo strip, on
   whatever page the demo lands on. The frame holds its place. */
.gb-demo-welcome-host:empty { display: none; }
.gb-demo-welcome-host { padding: 12px clamp(18px, 3vw, 28px) 0; }
.demo-welcome:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.demo-welcome {
  display: grid;
  gap: 10px;
  padding: 18px clamp(18px, 3vw, 28px);
  border: 1px solid var(--teal);
  border-left-width: 4px;
  background: var(--soft);
  color: var(--body-text);
}
.demo-welcome-title { margin: 0; font-size: 1.25rem; }
.demo-welcome-lead { margin: 0; }
.demo-welcome-points { margin: 0; padding-left: 1.2em; display: grid; gap: 4px; }
.demo-welcome-actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.home-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 18px;
  min-height: 380px;
  padding: clamp(28px, 5vw, 56px);
  border: 1px solid var(--line-strong);
  background: var(--paper);
  box-shadow: var(--shadow);
}
.home-hero h1 {
  max-width: 880px;
  margin: 0;
  font-size: clamp(2.4rem, 6vw, 5.3rem);
  line-height: .94;
  letter-spacing: 0;
}
/* The promise under the headline, a little smaller and on its own line. */
.home-hero .home-tagline {
  margin: -6px 0 0;
  font-size: clamp(1.4rem, 3.4vw, 2.9rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
}
.home-lead {
  max-width: 620px;
  margin: 0;
  color: var(--muted);
  font-size: 1.03rem;
  line-height: 1.6;
}
.home-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
/* The plain line under the button (`docs/ux/home-direction.md`, comment 4):
   visible without a click, never a button that only scrolls the page. */
.home-needs-line {
  max-width: 620px;
  margin: 0;
  color: var(--muted);
  font-size: .95rem;
  line-height: 1.6;
}
/* What is free: three short lines under the needs line. Hidden signed in; the
   attribute is guarded for the reason `.home-cases` gives. */
.home-plans:not([hidden]) { display: grid; gap: 6px; max-width: 620px; }
.home-plans-heading { margin: 0; color: inherit; font-size: .95rem; font-weight: 600; }
.home-plans-list { display: grid; gap: 4px; margin: 0; }
.home-plans-row { display: grid; grid-template-columns: 11rem minmax(0, 1fr); gap: 4px 12px; color: var(--muted); font-size: .92rem; line-height: 1.5; }
.home-plans-row dt { color: inherit; }
.home-plans-row dd { margin: 0; }
.home-plans-link { justify-self: start; padding-block: 2px; }
@media (max-width: 640px) { .home-plans-row { grid-template-columns: minmax(0, 1fr); } }
/* Signed in the same headline is a heading rather than a hero. Half a screen of
   welcome above the thing somebody came back to finish is half a screen too much. */
/* Signed in (option A, `docs/ux/home-signed-in.md`): no card round the welcome.
   The heading and its line sit on the left and the one button on the right, on
   the page itself, so the records below are the first thing with a picture. */
.home-view.is-dashboard .home-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 6px 32px;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}
/* The biggest type on the signed-in Home is what to do next, not the greeting
   (outside UX review, Oct 2026, item 14): the greeting is a heading at reading
   size, and the one button carries the largest words on the page. Sizes only. */
.home-view.is-dashboard .home-hero h1 { font-size: clamp(1.1rem, 2vw, 1.3rem); line-height: 1.25; font-weight: 600; }
.home-view.is-dashboard .home-actions .primary-command { font-size: clamp(1.4rem, 3.2vw, 2rem); line-height: 1.15; padding: .55em 1.1em; }
.home-view.is-dashboard .home-hero h1,
.home-view.is-dashboard .home-setup-line { grid-column: 1; }
.home-view.is-dashboard .home-actions { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }
.home-setup-line {
  max-width: 720px;
  margin: 0;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
}

/* Signed out: the four use-case cards (comment 5), each a situation a
   collector is in and what GrooveBench does about it - the journey, not a
   feature list. */
/* `:not([hidden])` because a display of anything beats the browser's own rule
   for the attribute: a hidden grid is a visible grid. The page swaps these two
   by the attribute, so getting this wrong shows both halves at once. */
.home-cases:not([hidden]) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
}
.home-case {
  display: grid;
  align-content: start;
  gap: 10px;
  padding: 24px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  box-shadow: var(--shadow);
}
.home-case-heading {
  margin: 0;
  font-size: 1.05rem;
  letter-spacing: 0;
}
.home-case-body {
  margin: 0;
  color: var(--muted);
  line-height: 1.6;
}
.home-case-link { justify-self: start; padding-block: 2px; }

/* Signed in: Recent, then To finish (option A). Every section is drawn only when
   the model gives it something, and each one that carries a display is guarded
   with `:not([hidden])` for the reason given at `.home-cases`. */
.home-recent:not([hidden]), .home-finish:not([hidden]), .home-steps:not([hidden]) {
  display: grid;
  gap: 18px;
}
/* Signed in the sections sit further apart than the welcome's cards do. */
.home-view.is-dashboard { gap: 32px; }
.home-recent-heading {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px 12px;
}
.home-recent-heading h2, .home-finish h2 { margin: 0; font-size: 1.25rem; letter-spacing: 0; }
.home-more { color: var(--teal-on-dark); font-weight: 600; }
.home-more:hover { color: var(--body-text); }

/* Four records across, covers filling the width. */
.home-records {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 28px 20px;
}
.home-record { display: grid; gap: 10px; align-content: start; min-width: 0; }
.home-record-cover { display: block; color: inherit; text-decoration: none; }
.home-cover {
  aspect-ratio: 1 / 1;
  width: 100%;
  overflow: hidden;
  border-radius: 3px;
  background: var(--soft);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
}
.home-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* A plain sleeve with the album's name drawn on it, in the colour the Collection
   draws the same record. */
.home-sleeve {
  display: flex;
  align-items: flex-end;
  padding: 14px;
  background: hsl(var(--art-hue, 200) 38% 28%);
  color: hsl(var(--art-hue, 200) 60% 92%);
}
.home-sleeve-title {
  font-size: clamp(1rem, 2vw, 1.6rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.01em;
  overflow-wrap: anywhere;
}
.home-record-caption { display: grid; gap: 2px; min-width: 0; }
.home-record-album {
  color: var(--body-text);
  font-size: 1.06rem;
  font-weight: 700;
  text-decoration: none;
  overflow-wrap: anywhere;
}
.home-record-album:hover { text-decoration: underline; }
.home-record-artist { color: var(--muted); font-size: .94rem; overflow-wrap: anywhere; }
.home-record-name { color: var(--teal-on-dark); }
.home-record-measure {
  margin-top: 4px;
  color: var(--muted-2);
  font-size: .88rem;
  font-variant-numeric: tabular-nums;
}
.home-record-measure b { color: var(--body-text); font-weight: 600; }
.home-record-measure .down { color: var(--green-on-dark); }
.home-record-measure .up { color: var(--red-on-dark); }

/* A new account: two steps where the records will be. */
.home-steps-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 0; padding: 0; list-style: none; }
.home-step-link {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 20px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  color: var(--body-text);
  font-weight: 700;
  text-decoration: none;
}
.home-step-link:hover { border-color: var(--teal); }
.home-step-number {
  display: grid;
  place-items: center;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--teal);
  color: #FFFFFF;
}

.home-finish-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.home-todo {
  display: grid;
  gap: 8px;
  align-content: start;
  padding: 16px 18px;
  border-radius: 6px;
  background: var(--paper);
}
.home-todo strong { font-size: 1rem; overflow-wrap: anywhere; }
.home-todo p { margin: 0; color: var(--muted); font-size: .94rem; overflow-wrap: anywhere; }
.home-todo-actions { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: .94rem; font-weight: 600; }
.home-todo-actions .text-button { padding: 0; border: 0; background: none; }

/* The three shared controls that the rack's palette alone cannot reach. Each is
   scoped to this view rather than restated globally, so nothing else moves. */
#home-view .section-number { color: var(--teal-on-dark); }
/* The generic primary hover paints --ink on --ink once the surface flips: the
   trap the art direction records, where anything already dark breaks in the
   opposite direction from everything else. */
#home-view .primary-command:hover:not(:disabled) {
  border-color: var(--teal);
  background: var(--bench-3);
  color: var(--teal-on-dark);
}
#home-view .text-button { color: var(--teal-on-dark); }
#home-view .text-button:hover:not(:disabled) { color: var(--body-text); }
#home-view .home-record-name:hover { color: var(--body-text); }

/* ---- Demo -------------------------------------------------------------------
   The tour, worn on the same rack surface as Home and the Bench, because it is
   the front of the same machine seen by somebody who has not signed in. Every
   colour here is a token that `body.is-rack` has already redefined for the dark
   palette, so nothing below names one and all of it falls back correctly if the
   body class is ever not there. */
.demo-view { display: grid; gap: 16px; }
.demo-hero {
  display: grid;
  gap: 14px;
  padding: clamp(24px, 4vw, 44px);
  border: 1px solid var(--line-strong);
  background: var(--paper);
  box-shadow: var(--shadow);
}
.demo-hero h2 {
  max-width: 880px;
  margin: 0;
  font-size: clamp(1.9rem, 4.4vw, 3.4rem);
  line-height: 1;
  letter-spacing: 0;
}
.demo-lead {
  max-width: 660px;
  margin: 0;
  color: var(--muted);
  line-height: 1.6;
}
#demo-view .section-number { color: var(--teal-on-dark); }
#demo-view .text-button { color: var(--teal-on-dark); }
#demo-view .text-button:hover:not(:disabled) { color: var(--body-text); }

/* One card per entry, each of which answers one question. Two columns rather
   than a long single file, so the tour reads as a short list and not a feed. */
.demo-list:not([hidden]) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 16px;
}
.demo-entry {
  display: grid;
  align-content: start;
  gap: 12px;
  padding: 22px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  box-shadow: var(--shadow);
}
.demo-question {
  margin: 0;
  font-size: 1.1rem;
  font-weight: 800;
  line-height: 1.35;
}
.demo-answer, .demo-note {
  margin: 0;
  color: var(--muted);
  line-height: 1.6;
}
.demo-note { font-size: .86rem; }
.demo-takes { display: grid; gap: 6px; }
.demo-take {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: var(--soft);
}
.demo-take-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.demo-take-detail {
  color: var(--muted);
  font: 600 .78rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
}
.demo-compare { justify-self: start; }
/* The claim, in the units the software measures, shown to the visitor rather
   than kept in a test. A demo that says what it expects and is then watched
   doing it is a different kind of argument from one that just plays audio. */
.demo-expects-label {
  margin: 4px 0 0;
  color: var(--teal-on-dark);
  font: 800 .62rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.demo-expects {
  margin: 0;
  padding-left: 18px;
  color: var(--muted);
  font-size: .82rem;
  line-height: 1.55;
}
.demo-own {
  display: grid;
  gap: 10px;
  justify-items: start;
  padding: 22px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  box-shadow: var(--shadow);
}
.demo-own-heading { margin: 0; font-size: 1.1rem; letter-spacing: 0; }
.demo-own-body { margin: 0; max-width: 640px; color: var(--muted); line-height: 1.6; }
/* The source bar (bench/source-bar.css) takes the width of the card. */
.demo-own .demo-try-bar { justify-self: stretch; }
/* Where things get kept. Said once, at the foot of the page, rather than
   attached to every control as a reason it is not there. */
.demo-boundary {
  margin: 0;
  padding: 18px 22px;
  border: 1px solid var(--line);
  background: var(--soft);
  color: var(--muted);
  font-size: .88rem;
  line-height: 1.6;
}
/* Only ever seen by whoever is editing the manifest. */
.demo-problems:not([hidden]) {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 14px 14px 14px 32px;
  border: 1px solid var(--red-on-dark);
  background: var(--soft);
  color: var(--red-on-dark);
  font-size: .85rem;
}

.primary-command {
  border-color: var(--teal);
  background: var(--teal);
  color: var(--on-fill);
  letter-spacing: .03em;
}
.primary-command:hover:not(:disabled) {
  border-color: var(--body-text);
  background: var(--ink);
}
.primary-command.compact { white-space: nowrap; }
.secondary-button {
  flex: 0 0 auto;
  border: 1px solid var(--teal);
  background: var(--paper);
  color: var(--teal);
}
.secondary-button:hover:not(:disabled) { background: var(--teal); color: var(--on-fill); }
/* AN ANCHOR DRESSED AS ONE: Home's "What you need" is a jump within the page,
   so an <a>, and without this it sat underlined with its text at the top of
   the box - the third of three buttons dressed three ways (UX re-review 1,
   finding 3). What `button` gets above and an anchor does not. The display is
   on `:not([hidden])` only: the link is hidden once signed in, and a display
   beats the attribute (see `.nav-link[hidden]`). The 404 page's links are
   the same case. */
a.primary-command, a.secondary-button {
  border-radius: var(--radius);
  padding: 12px 16px;
  font-weight: 800;
  text-decoration: none;
}
a.primary-command:not([hidden]), a.secondary-button:not([hidden]) { display: inline-flex; align-items: center; justify-content: center; }
.text-button {
  padding: 6px 0;
  border: 0;
  background: transparent;
  color: var(--teal);
}
.text-button:hover:not(:disabled) {
  background: transparent;
  color: var(--body-text);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.panel-heading {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 18px;
}
.panel-heading h2 {
  margin: 3px 0 0;
  font-size: 1.28rem;
  letter-spacing: 0;
}
.status-pill {
  flex: 0 0 auto;
  border: 1px solid rgba(255, 255, 255, .28);
  padding: 5px 8px;
  color: #D8F2F5;
  font: 800 .68rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.panel-status {
  margin: 0 0 14px;
  /* Was #5C6C74, a mid-slate picked for paper. On the rack it read at about
     2.7:1, and five separate rules had grown to patch one hardcoded colour -
     which is what a literal in a shared control costs. */
  color: var(--muted);
  line-height: 1.5;
}

.section-heading {
  display: grid;
  grid-template-columns: 1fr minmax(260px, 460px);
  gap: 28px;
  align-items: end;
  margin-bottom: 22px;
}
.section-heading h2 {
  margin: 4px 0 0;
  font-size: clamp(1.8rem, 3.6vw, 3rem);
  letter-spacing: 0;
}
.section-help {
  color: var(--muted);
  margin: 0;
  line-height: 1.55;
}

.capture-grid {
  display: grid;
  grid-template-columns: 1.35fr .85fr;
  border: 1px solid #314650;
  background: var(--bench);
  color: var(--on-fill);
  box-shadow: var(--shadow);
}
.drop-zone {
  min-height: 336px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 32px;
  border-right: 1px solid #314650;
  cursor: pointer;
  text-align: center;
}
.drop-zone:hover, .drop-zone.dragging {
  background: #132630;
  box-shadow: inset 0 0 0 2px var(--teal);
}
.drop-zone input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.record-icon {
  width: 102px;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 20px solid #273A44;
  display: grid;
  place-items: center;
  margin-bottom: 12px;
  box-shadow: inset 0 0 0 1px #61727A, 0 0 0 1px #071015;
}
.record-icon::before {
  content: "";
  position: absolute;
  width: 52px;
  height: 1px;
  background: #61727A;
  transform: rotate(-22deg);
}
.record-icon i {
  width: 12px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--teal);
  z-index: 1;
}
.drop-title {
  max-width: 100%;
  font-size: 1.15rem;
  font-weight: 850;
  overflow-wrap: anywhere;
}
.drop-detail {
  color: #B9C5CA;
  font-size: .9rem;
}

.settings-panel {
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  background: var(--bench-2);
}
.field-label {
  color: inherit;
  font-size: .78rem;
  font-weight: 850;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.field-note {
  display: block;
  color: #B4C0C5;
  font-size: .84rem;
  line-height: 1.45;
  margin-top: 5px;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}
select,
textarea,
input[type="date"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="search"],
input[type="text"],
input[type="url"] {
  width: 100%;
  padding: 12px 13px;
  border: 1px solid var(--line-strong);
  color: var(--body-text);
  background: var(--paper);
  border-radius: var(--radius);
}
.settings-panel select {
  border-color: #3E5661;
  color: var(--on-fill);
  background: #0B171D;
}
.switch-row {
  margin-top: 4px;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 16px;
  align-items: center;
  border-top: 1px solid #314650;
  border-bottom: 1px solid #314650;
  padding: 18px 0;
}
.switch input { position: absolute; opacity: 0; }
.switch span {
  display: block;
  width: 46px;
  height: 25px;
  border-radius: 999px;
  background: #586970;
  padding: 3px;
  cursor: pointer;
}
.switch span::after {
  content: "";
  display: block;
  width: 19px;
  height: 19px;
  background: var(--paper);
  border-radius: 50%;
  transition: transform .2s;
}
.switch input:checked + span { background: var(--teal); }
.switch input:checked + span::after { transform: translateX(21px); }
.switch input:focus-visible + span { outline: 2px solid var(--paper); outline-offset: 3px; }
.status {
  min-height: 1.4em;
  margin: 0;
  /* Was #B4C0C5, a colour chosen for the rack and then applied everywhere. The
     dialogs inherit whichever surface the route is wearing, so on the light
     Collection this was about 1.8:1 - and its .error variant was worse than
     its normal one, which is exactly backwards. */
  color: var(--muted);
  font-size: .88rem;
}
.status.error { color: var(--danger-text); }

.analysis-progress {
  border: 1px solid #314650;
  background: #0A151A;
  padding: 14px;
}
.progress-track {
  height: 6px;
  overflow: hidden;
  background: #2B404A;
  margin-bottom: 12px;
}
.progress-track span {
  display: block;
  width: 0;
  height: 100%;
  background: var(--teal);
  transition: width .18s ease-out;
}
.progress-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.progress-heading strong { font-size: .84rem; }
.progress-heading span {
  color: #CFECEF;
  font: 800 .76rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
}
.analysis-progress > p {
  min-height: 1.25em;
  margin: 5px 0 10px;
  color: #B4C0C5;
  font: .73rem/1.45 ui-monospace, SFMono-Regular, Consolas, monospace;
}
.bench-notes-log {
  border-top: 1px solid #314650;
  padding-top: 9px;
  margin-top: 12px;
}
.bench-notes-details summary,
.bench-notes-log summary {
  cursor: pointer;
  color: #D6E1E5;
  font-size: .8125rem;
  font-weight: 750;
}
/* Nothing measured, nothing to open. */
.bench-notes-details:has(> ol:empty) { display: none; }
.bench-notes-summary { margin: 12px 0 0; }
.bench-notes-details { margin-top: 10px; }
.bench-notes-log pre {
  max-height: 132px;
  overflow: auto;
  margin: 9px 0 0;
  white-space: pre-wrap;
  color: #D6E1E5;
  font: .7rem/1.55 ui-monospace, SFMono-Regular, Consolas, monospace;
}

.result-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  align-items: center;
  padding: 20px 28px;
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
.score-ring {
  width: 156px;
  aspect-ratio: 1;
  border-radius: 50%;
  display: grid;
  place-content: center;
  text-align: center;
  background: conic-gradient(var(--teal) 0deg, var(--teal) var(--score-angle, 0deg), var(--mist) var(--score-angle, 0deg));
  position: relative;
}
.score-ring::after {
  content: "";
  position: absolute;
  inset: 9px;
  border-radius: 50%;
  background: var(--paper);
}
.score-ring strong, .score-ring span { position: relative; z-index: 1; }
.score-ring strong { font: 850 2.7rem/1 ui-monospace, SFMono-Regular, Consolas, monospace; }
.score-ring span {
  color: var(--muted-2);
  font-size: .8rem;
  margin-top: 5px;
}
/* The one badge for "this number is not final" - reused wherever a score
   appears on its own, in place of the letter grade that used to stand there.
   Never on a sentence that already says so, and never a new sentence of its
   own: just the tag. */
.experimental-tag {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--mist);
  color: var(--muted-2);
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.capture-summary {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin: 0;
}
.capture-summary div {
  border-left: 2px solid var(--line);
  padding-left: 14px;
}
.capture-summary dt, .metric-card dt {
  color: var(--muted-2);
  font-size: .78rem;
}
.capture-summary dd {
  margin: 5px 0 0;
  font-weight: 750;
}

.report-actions {
  margin-top: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--teal);
  background: var(--paper);
  padding: 18px 20px;
}
.report-actions strong { display: block; font-size: .95rem; }
.report-actions span {
  display: block;
  max-width: 690px;
  margin-top: 4px;
  color: var(--muted);
  font-size: .86rem;
  line-height: 1.45;
}

/* The result, directly under the capture row (UX review area 2, finding 1):
   score and one plain-language reason (finding 3), not the full measurement
   set further down the rack. scroll-margin-top keeps it clear of nothing
   fixed here, but matches the other rack units' spacing when scrolled to. */
.bench-result-card {
  display: flex;
  align-items: center;
  gap: 26px;
  margin: 20px 0;
  padding: 24px 28px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 4px solid var(--teal);
  box-shadow: var(--shadow);
  scroll-margin-top: 24px;
}
.bench-result-card { flex-wrap: wrap; }
.bench-result-text { flex: 1 1 320px; min-width: 0; }
/* What was measured, and what could not be: a quiet strip across the top of the
   card, above the score it qualifies. A part that could not be measured has the
   amber mark, never red: it is a limit of the recording, not a fault in it. */
.bench-result-coverage { flex: 1 0 100%; display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 0; padding: 0 0 12px; list-style: none; border-bottom: 1px solid var(--line); font-size: .86rem; color: var(--muted); }
.bench-result-coverage:empty { display: none; }
.bench-result-coverage .coverage-missing, .bench-result-coverage .coverage-noscore { color: var(--body-text); border-left: 3px solid var(--amber); padding-left: 8px; }
.score-ring--compact { width: 96px; flex: none; }
.score-ring--compact strong { font-size: 1.7rem; }
.bench-result-text h2 { margin: 2px 0 10px; font-size: 1.2rem; line-height: 1.35; max-width: 620px; }
.bench-result-text p { margin: 0 0 10px; color: var(--muted); line-height: 1.45; max-width: 620px; }
/* The four measurements under the sentence (UX review 8, finding 3): Home's
   and the Collection's words, as tiles. */
.bench-result-measures { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin: 0 0 14px; max-width: 720px; }
.bench-result-measures div { padding: 10px 12px; background: rgba(0, 0, 0, .18); border: 1px solid var(--line); }
.bench-result-measures dt { margin: 0 0 4px; color: var(--muted); font-size: .8rem; }
.bench-result-measures dd { margin: 0; font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums; }
@media (max-width: 720px) {
  .bench-result-measures { grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
}
/* Compare's opener, under the result and above the panel it opens. */
.compare-offer { margin: 18px 0 0; }
.compare-offer:has(#compare-open[hidden]) { display: none; }
/* What the score cannot see, as a muted note under the reason - not a warning. */
.bench-result-text .bench-result-note { font-size: .82rem; }
/* Skip findings (config/skip-findings.js): a short list under the reason,
   in the same muted voice as the note it replaces. */
.skip-findings[hidden] { display: none; }
.skip-findings .skip-findings-heading { margin: 0 0 4px; font-size: .95rem; }
.skip-findings p { font-size: .82rem; }
.skip-findings-list { list-style: none; margin: 0 0 10px; padding: 0; }
.skip-findings-list li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; padding: 3px 0; font-size: .85rem; }
.skip-findings-when { font-variant-numeric: tabular-nums; }
.skip-findings-peak, .skip-findings-clipped { color: var(--muted); }
/* "Has anything changed?" (calibration/drift-view.js): the same muted voice
   as the skip findings. Amber for changed, never red. */
.drift-findings[hidden] { display: none; }
.drift-findings .drift-heading { margin: 0 0 4px; font-size: .95rem; }
.drift-findings .drift-line { margin: 0 0 4px; font-size: .85rem; }
.drift-findings .drift-line.drift-note, .drift-findings .drift-line.drift-quiet { font-size: .82rem; }
.drift-findings .drift-line.drift-changed { color: var(--body-text); border-left: 3px solid var(--amber); padding-left: 8px; }
.drift-findings .drift-line.drift-step { color: var(--body-text); font-weight: 600; }
.skip-findings-mark { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.skip-findings-mark [aria-pressed="true"] { font-weight: 600; text-decoration: underline; }
.skip-findings-call { color: var(--muted); }
.bench-result-text .bench-result-condition { margin: 2px 0 6px; font-size: .9rem; }
.bench-result-condition[hidden] { display: none; }
.bench-result-next[hidden], .bench-result-next [hidden] { display: none; }
.bench-result-next p { margin: 2px 0 6px; font-size: .9rem; }
.bench-result-next .bench-result-clipped { color: var(--body-text); border-left: 3px solid var(--amber); padding-left: 8px; }
.bench-result-coverage .coverage-part { color: var(--body-text); }
.bench-result-condition .experimental-tag { margin-right: 6px; }
.skip-findings .skip-findings-setup { margin: 0 0 8px; }
.skip-findings .skip-findings-setup-unchecked { border-left: 3px solid var(--slate); padding-left: 8px; }
@media (max-width: 720px) {
  .bench-result-card { flex-direction: column; align-items: flex-start; text-align: left; }
}
.report-buttons {
  display: flex;
  flex: 0 0 auto;
  gap: 10px;
}

.spectrogram-card, .metric-card, .chart-card, .method-note, .collection-toolbar, .collection-shell {
  border: 1px solid var(--line);
  background: var(--paper);
  box-shadow: var(--shadow);
}
.spectrogram-card {
  margin-top: 16px;
  padding: 20px;
}
.spectrogram-heading {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  margin-bottom: 14px;
}
.spectrogram-heading > div > span {
  display: block;
  font-weight: 850;
}
.spectrogram-heading small {
  display: block;
  color: var(--muted);
  margin-top: 4px;
  line-height: 1.45;
}
.spectrogram-readout {
  color: var(--teal);
  text-align: right;
  font: 800 .78rem/1.4 ui-monospace, SFMono-Regular, Consolas, monospace;
}
#audio-player {
  display: block;
  width: 100%;
  height: 42px;
  margin-bottom: 12px;
  accent-color: var(--teal);
}
.spectrogram-stack {
  position: relative;
  width: 100%;
  background: #080F13;
  border: 1px solid #223640;
  touch-action: pan-y;
}
.spectrogram-stack canvas {
  width: 100%;
  display: block;
  border: 0;
  background: transparent;
}
#spectrogram-overlay {
  position: absolute;
  inset: 0;
  height: 100%;
  cursor: crosshair;
}
#spectrogram-overlay:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}
.spectrogram-legend:not([hidden]) {
  display: flex;
  flex-wrap: wrap;
  gap: 9px 18px;
  margin-top: 13px;
  color: var(--muted);
  font-size: .78rem;
}
.spectrogram-legend span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.spectrogram-legend i {
  display: inline-block;
  width: 16px;
  height: 7px;
  border-radius: 1px;
}
.legend-lead { background: var(--teal); }
.legend-program { background: var(--slate); }
.legend-runout { background: #6B5D88; }
.legend-click { background: var(--red); }
.legend-crackle { background: #B77832; }
.legend-repeat { background: #844E98; }
.legend-playhead { background: var(--ink); }

.metrics-grid {
  margin-top: 16px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
.metric-card { padding: 22px; }
.metric-card header {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: center;
  border-bottom: 1px solid var(--line);
  padding-bottom: 14px;
  margin-bottom: 18px;
}
.metric-card header span { font-weight: 850; }
.metric-card header b {
  color: var(--teal);
  font: 800 .7rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em;
}
.metric-card > strong {
  font: 850 2rem/1.1 ui-monospace, SFMono-Regular, Consolas, monospace;
}
.metric-card > p {
  margin: 7px 0 20px;
  color: var(--muted);
  line-height: 1.45;
}
.metric-card dl {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin: 0;
}
.metric-card dl div {
  border-top: 1px solid var(--line);
  padding-top: 12px;
}
.metric-card dd {
  margin: 5px 0 0;
  font-weight: 750;
}
.source-card {
  border-left: 4px solid var(--teal);
  background: var(--soft);
}
.callout {
  color: var(--body-text);
  background: var(--teal-soft);
  border: 1px solid #B8DDE2;
  padding: 11px;
  font-size: .84rem;
  line-height: 1.45;
}

.charts-grid {
  margin-top: 16px;
  display: grid;
  gap: 16px;
}
.chart-card {
  padding: 20px;
  overflow: hidden;
}
.chart-heading {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 14px;
}
.chart-heading span { font-weight: 850; }
.chart-heading small {
  display: block;
  color: var(--muted);
  margin-top: 3px;
}
canvas {
  width: 100%;
  display: block;
  background: #101A20;
  border: 1px solid #223640;
}
.method-note {
  margin-top: 16px;
  padding: 17px 20px;
  color: var(--muted);
}
.method-note summary {
  cursor: pointer;
  color: var(--body-text);
  font-weight: 800;
}
.method-note p {
  max-width: 850px;
  line-height: 1.6;
  margin-bottom: 0;
}

.collection-toolbar[hidden] { display: none; }
.collection-toolbar {
  display: grid;
  /* View, search (takes what is left), the Show menu, Filter, Columns (table
     only). Add a record and Import sit in the heading row, not here. */
  grid-template-columns: auto minmax(220px, 1fr) minmax(140px, auto) auto auto;
  gap: 12px;
  align-items: end;
  padding: 16px;
  margin-bottom: 16px;
}
/* The Collection heading: the title and its one line on the left, Add a record
   and Import on the right; under the title on a phone. */
#collection-view > .section-heading {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px 20px;
  margin-bottom: 14px;
}
#collection-view > .section-heading .section-help { margin-top: 6px; }
.collection-heading-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}
.collection-heading-actions [hidden] { display: none; }
.segmented-control {
  display: inline-grid;
  grid-auto-flow: column;
  border: 1px solid var(--line-strong);
  background: var(--soft);
  padding: 3px;
}
.segmented-control button {
  border: 0;
  padding: 9px 12px;
  background: transparent;
  color: var(--body-text);
}
.segmented-control button.is-active {
  background: var(--ink);
  color: var(--on-fill);
}
.toolbar-field {
  display: grid;
  gap: 6px;
}
.toolbar-field span {
  color: var(--muted);
  font-size: .72rem;
  font-weight: 850;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.collection-shell { padding: 20px; }
.collection-meta {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  color: var(--muted);
  margin-bottom: 14px;
  font-size: .86rem;
}
.collection-meta span:first-child {
  color: var(--body-text);
  font-weight: 850;
}
.collection-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 12px;
}
.copy-card {
  min-height: 280px;
  display: grid;
  grid-template-rows: minmax(132px, .9fr) auto;
  border: 1px solid var(--line);
  background: var(--paper);
}
.copy-card-content {
  display: grid;
  align-content: end;
  gap: 7px;
  padding: 16px;
}
.copy-card strong { font-size: 1.08rem; }
.copy-card span { color: var(--muted); }
.copy-card small { color: var(--teal); font-weight: 800; }
.copy-art {
  min-height: 132px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background: var(--soft);
}
.copy-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* A TILE DRAWN FROM THE RECORD (area 3 finding 8), not the grey monogram
   repeated. The hue is a custom property so the colour is computed once, in
   script, from the artist and album - the stylesheet only turns a number
   into a colour. */
.copy-art-drawn {
  grid-auto-flow: row;
  gap: 2px;
  padding: 14px;
  text-align: center;
  background: hsl(var(--art-hue, 200) 46% 88%);
  color: hsl(var(--art-hue, 200) 46% 22%);
}
.copy-art-drawn .copy-art-title {
  font-size: .92rem;
  font-weight: 850;
  line-height: 1.25;
}
.copy-art-drawn .copy-art-artist {
  font-size: .76rem;
  font-weight: 650;
  opacity: .85;
}
.copy-art-mark {
  width: 72px;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border: 5px solid var(--ink);
  border-right-color: transparent;
  border-radius: 50%;
  color: var(--body-text);
  font-weight: 900;
  letter-spacing: 0;
}
.grade-chip {
  width: fit-content;
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 4px 8px;
  border: 1px solid var(--teal);
  background: var(--teal-soft);
  color: var(--body-text);
  font-weight: 900;
  font-size: .78rem;
}
.grade-chip.muted {
  border-color: var(--line);
  background: var(--soft);
  color: var(--muted);
}
/* The tag beside a score in the Collection (Jacob, 29 Sep: too loud). It is the
   qualifier, not the figure: smaller, lighter and without the pill's fill, with
   clear space between it and the number so the two never read as one word. */
.grade-chip > .experimental-tag {
  margin-left: 14px;
  padding: 0;
  background: transparent;
  color: var(--muted);
  font-size: .56rem;
  font-weight: 600;
  letter-spacing: .08em;
}
/* The condition cell: the score and its Experimental mark; no arrow, no change. */
.condition-cell { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.copy-card-condition { display: flex; }
.copy-card small.copy-card-measured { color: var(--muted); font-weight: 400; }
.copy-actions, .copy-detail-actions, .dialog-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.secondary-button.small {
  padding: 7px 10px;
  font-size: .78rem;
}
.danger-button {
  border-color: var(--red);
  background: var(--paper);
  color: var(--red);
}
.danger-button:hover:not(:disabled) {
  border-color: var(--red);
  background: var(--red);
  color: var(--on-fill);
}
.collection-table-wrap { overflow: auto; }
.collection-table {
  /* No pinned minimum. It was 1680px, and 1320px on a phone, because the table
     was one flat row of twenty columns and every one of them needed space. The
     table is titles now, with four or five columns a level, so the browser can
     be trusted with the widths again - which is most of the fix for a view that
     was four screens wide inside a 324px window. */
  width: 100%;
  border-collapse: collapse;
  font-size: .84rem;
  /* Columns are given widths below rather than sized to their contents. Each
     level is its own table, so content sizing meant no two levels agreed on
     anything and the whole shelf read as random - the owner's word. */
  table-layout: fixed;
}
.collection-table th, .collection-table td {
  padding: 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.collection-table th {
  color: var(--muted);
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.empty-state {
  margin-top: 14px;
  padding: 34px;
  border: 1px dashed var(--line-strong);
  background: var(--soft);
  text-align: center;
}
.empty-state h3 {
  margin: 8px 0;
  font-size: 1.5rem;
}
.empty-state p:last-child {
  max-width: 540px;
  margin: 0 auto;
  color: var(--muted);
  line-height: 1.55;
}
.empty-state-copy {
  max-width: 540px;
  margin: 0 auto;
  color: var(--muted);
  line-height: 1.55;
}
.empty-state-actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
}
.copy-detail {
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 22px;
  box-shadow: var(--shadow);
}
.copy-detail > .text-button { margin-bottom: 16px; }
.copy-detail-hero {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr) auto;
  gap: 18px;
  align-items: stretch;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--line);
}
.copy-detail-hero .copy-art {
  min-height: 180px;
  border: 1px solid var(--line);
}
.copy-detail-title {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  min-width: 0;
}
.copy-detail-title h3 {
  margin: 0;
  font-size: clamp(2rem, 4vw, 3.6rem);
  line-height: 1;
  letter-spacing: 0;
}
.copy-detail-title p {
  margin: 0;
  color: var(--muted);
  font-size: 1.04rem;
}
.copy-detail-actions {
  align-content: center;
  justify-content: flex-end;
}
.detail-section {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
.copy-detail-hero + .detail-section { border-top: 0; }
.detail-section h4 {
  margin: 0 0 12px;
  font-size: 1.02rem;
}
.detail-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  margin: 0;
}
.detail-grid.compact {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.detail-grid div {
  min-width: 0;
  padding: 11px;
  border: 1px solid var(--line);
  background: var(--soft);
}
.detail-grid dt {
  color: var(--muted);
  font-size: .68rem;
  font-weight: 850;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.detail-grid dd {
  margin: 4px 0 0;
  overflow-wrap: anywhere;
  font-weight: 750;
}
.copy-notes {
  margin: 14px 0 0;
  padding: 14px;
  border-left: 3px solid var(--teal);
  background: var(--soft);
  color: #344851;
  line-height: 1.55;
}
.analysis-history {
  display: grid;
  gap: 10px;
}
.analysis-history-item {
  padding: 14px;
  border: 1px solid var(--line);
  background: var(--soft);
}
.analysis-history-heading {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: center;
  margin-bottom: 10px;
}
.report-detail {
  margin-top: 10px;
}
.report-detail pre {
  max-height: 320px;
  overflow: auto;
  padding: 12px;
  background: var(--ink);
  color: var(--on-fill);
  white-space: pre-wrap;
}
.bench-copy-panel {
  margin: 18px 0;
  padding: 20px;
  border: 1px solid #35505C;
  background: #13242D;
  color: var(--on-fill);
}
.source-id-panel {
  margin: 18px 0;
  padding: 20px;
  border: 1px solid #35505C;
  border-left: 4px solid var(--teal);
  background: #13242D;
  color: var(--on-fill);
}
.source-id-panel .panel-heading {
  margin-bottom: 10px;
}
.source-id-panel h3 {
  margin: 3px 0 0;
  font-size: 1.25rem;
}
.source-id-panel .panel-status,
.source-id-panel .source-id-meta,
.source-id-panel .discogs-release-option span,
.source-id-panel .discogs-release-row span,
.source-id-panel .discogs-release-row small,
.source-id-discogs-heading p {
  color: #A6DCE2;
}
.source-id-panel .status-pill {
  border-color: #35505C;
  color: #D8F2F5;
}
/* Folded to one line by default (UX review area 2, finding 2): a native
   disclosure, not a second "expand" control, so the whole line is the
   target and no JS is needed to open or close it. */
#source-id-summary {
  list-style: none;
  cursor: pointer;
  font-weight: 750;
  color: var(--on-fill);
}
#source-id-summary::-webkit-details-marker { display: none; }
#source-id-summary::before { content: "▸ "; color: #A6DCE2; }
.source-id-panel[open] #source-id-summary::before { content: "▾ "; }
.source-id-panel .source-id-body { margin-top: 16px; }
.source-id-progress {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 4px 0 12px;
  color: #D8F2F5;
  font-size: .82rem;
}
.source-id-progress[hidden] {
  display: none;
}
.source-id-progress span {
  width: 9px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--teal);
}
.source-id-command-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin: 8px 0 14px;
}
.source-id-command-row[hidden] {
  display: none;
}
.intake-state-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin: 12px 0;
}
.intake-state-grid div {
  padding: 10px;
  border: 1px solid #35505C;
  background: rgba(255,255,255,.035);
}
.intake-state-grid span,
.intake-form-grid span {
  display: block;
  margin-bottom: 5px;
  color: #A6DCE2;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: 0;
}
.intake-state-grid[hidden], #source-id-skip[hidden], .toolbar-field[hidden], #compare-open[hidden] { display: none; }
.intake-more { margin-top: 12px; }
.intake-more > summary { cursor: pointer; color: var(--teal-on-dark); font-size: .8125rem; font-weight: 600; }
.intake-more > .intake-form-grid { margin-top: 10px; }
.intake-state-grid strong {
  color: var(--on-fill);
  font-size: .9rem;
}
.intake-record-summary {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid #35505C;
}
.intake-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 10px;
}
.intake-form-grid label {
  min-width: 0;
}
.intake-form-grid input,
.intake-form-grid select {
  width: 100%;
  min-height: 38px;
  border: 1px solid #4D717C;
  background: #0D171D;
  color: var(--on-fill);
  padding: 8px 10px;
  border-radius: 6px;
}
.intake-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.source-id-candidates,
.discogs-results {
  display: grid;
  gap: 10px;
}
.source-id-candidate,
.discogs-release-option {
  display: grid;
  gap: 10px;
  padding: 13px;
  border: 1px solid #35505C;
  background: rgba(255,255,255,.04);
}
.source-id-candidate.compact {
  background: rgba(255,255,255,.025);
}
.source-id-candidate-heading {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: start;
}
.source-id-candidate-heading strong,
.discogs-release-option strong {
  display: block;
  color: var(--on-fill);
}
.source-id-candidate-heading span {
  display: block;
  margin-top: 3px;
  color: #D8F2F5;
}
.source-id-candidate-heading b {
  color: var(--on-fill);
  border: 1px solid #4D717C;
  padding: 5px 7px;
  font: 900 .66rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
}
.source-id-meta {
  margin: 0;
  font-size: .82rem;
}
.source-id-actions,
.source-id-alternatives {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.source-id-alternatives {
  margin-top: 12px;
}
.source-id-alternatives h4 {
  flex: 1 0 100%;
  margin: 4px 0 0;
  color: var(--on-fill);
}
.source-id-discogs {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid #35505C;
}
.source-id-discogs-heading {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: start;
  margin-bottom: 12px;
}
.source-id-discogs-heading h4 {
  margin: 0 0 4px;
  color: var(--on-fill);
}
.source-id-discogs-heading p {
  margin: 0;
  line-height: 1.45;
}
.discogs-notice {
  margin: -4px 0 12px;
  color: #A6DCE2;
  font-size: .78rem;
}
.discogs-release-option a {
  color: #D8F2F5;
  font-size: .8rem;
}
.discogs-table {
  display: grid;
  gap: 8px;
}
.discogs-release-row {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 10px;
  border: 1px solid #35505C;
  background: rgba(255,255,255,.035);
}
.discogs-release-row img,
.discogs-cover-placeholder {
  width: 56px;
  aspect-ratio: 1;
  object-fit: cover;
  background: #0D171D;
  border: 1px solid #35505C;
}
.discogs-release-body {
  display: grid;
  gap: 3px;
  min-width: 0;
}
.discogs-release-body strong {
  color: var(--on-fill);
}
.discogs-release-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 6px;
}
/* The chosen release. Colour is the last of three signals, not the only one:
   the row carries a "Selected" marker in place of the button that chose it,
   and the bar down its edge survives a colour-blind or low-contrast reading. */
.discogs-release-row.is-selected {
  border-color: var(--teal-on-dark);
  box-shadow: inset 4px 0 0 var(--teal-on-dark);
  background: rgba(255, 255, 255, .075);
}
.discogs-selected-mark {
  color: var(--teal-on-dark);
  border: 1px solid var(--teal-on-dark);
  padding: 5px 7px;
  font: 900 .66rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
}
/* "None of these" rejects the list, so it sits under the list once rather than
   on every row. Any note about what a choice left alone sits beside it. */
.discogs-list-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}
.discogs-list-footer .panel-status {
  margin: 0;
  flex: 1 1 260px;
  font-size: .82rem;
}
.source-id-panel > .secondary-button {
  margin-top: 14px;
}
.bench-copy-panel .panel-heading {
  margin-bottom: 10px;
}
.bench-copy-panel h3 {
  margin: 3px 0 0;
  font-size: 1.25rem;
}
.bench-copy-panel .panel-status,
.bench-copy-panel .toolbar-field span {
  color: #A6DCE2;
}
.bench-selected-copy {
  margin: 12px 0;
  padding: 12px;
  border: 1px solid #35505C;
  background: rgba(255,255,255,.04);
  color: var(--on-fill);
  font-weight: 850;
}
.bench-copy-controls {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) auto;
  gap: 10px;
  align-items: end;
}
.bench-copy-results {
  display: grid;
  gap: 8px;
  margin-top: 12px;
}
.bench-copy-result {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 10px;
  border: 1px solid #35505C;
  background: rgba(255,255,255,.04);
}
.bench-copy-result span {
  display: grid;
  gap: 3px;
}
.bench-copy-result small {
  color: #A6DCE2;
}
.copy-dialog {
  width: min(820px, calc(100% - 28px));
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--body-text);
  background: var(--paper);
  box-shadow: 0 28px 90px rgba(13, 23, 29, .24);
}
.copy-dialog::backdrop {
  background: rgba(13, 23, 29, .56);
  backdrop-filter: blur(4px);
}
.copy-form {
  position: relative;
  display: grid;
  gap: 14px;
  padding: 30px;
}
.copy-form h2 {
  margin: -4px 42px 0 0;
  font-size: 1.8rem;
  letter-spacing: 0;
}
.copy-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.copy-form .field-label {
  display: grid;
  gap: 7px;
}
.copy-form .field-label.wide {
  grid-column: 1 / -1;
}
.copy-form .copy-check {
  grid-column: 1 / -1;
  display: flex;
  gap: 8px;
  align-items: center;
}
.copy-form .field-label input,
.copy-form .field-label textarea,
.toolbar-field input,
.toolbar-field select {
  min-width: 0;
}
.copy-form .field-label textarea {
  resize: vertical;
}
/* "MORE DETAILS" (area 3 finding 3). Artist and album are what starting a
   record needs; everything else - sixteen fields, among them an internal
   field name - waits behind a disclosure so adding the first record does not
   read as a form. */
.copy-form-more {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.copy-form-more > summary {
  cursor: pointer;
  font-weight: 750;
  color: var(--teal);
}
.copy-form-more > .copy-form-grid {
  margin-top: 12px;
}
.copy-form .status.error {
  color: var(--red);
}

/* "FIND IT ON DISCOGS" (area 3 finding 3). The light dialog `.copy-form`
   already sets, not the Bench's dark rack - so this borrows the Bench's
   `.discogs-*` layout ideas rather than its rules, which are coloured for
   `.source-id-panel`'s own dark surface. `:not([hidden])` throughout: see
   the `.nav-link[hidden]` note above `tests/styles-tokens.test.cjs` checks
   every one of these against index.html. */
.copy-form-discogs {
  display: grid;
  gap: 8px;
  margin: -4px 0 4px;
}
.copy-form-discogs .status {
  margin: 0;
}
.copy-discogs-results:not([hidden]) {
  display: grid;
  gap: 10px;
}
.copy-discogs-list {
  display: grid;
  gap: 8px;
}
.copy-discogs-row {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 9px;
  border: 1px solid var(--line);
  background: var(--soft);
}
.copy-discogs-row img,
.copy-discogs-cover-placeholder {
  width: 48px;
  aspect-ratio: 1;
  object-fit: cover;
  background: var(--paper);
  border: 1px solid var(--line);
}
.copy-discogs-row-body {
  display: grid;
  gap: 2px;
  min-width: 0;
}
.copy-discogs-row-body strong {
  color: var(--body-text);
}
.copy-discogs-row-body span {
  color: var(--muted);
  font-size: .82rem;
}
.copy-discogs-row-body a {
  color: var(--teal);
  font-size: .8rem;
}
.copy-discogs-row-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}
.copy-discogs-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
.copy-discogs-footer p {
  margin: 0;
  flex: 1 1 260px;
  color: var(--muted);
  font-size: .78rem;
}
.copy-discogs-summary:not([hidden]) {
  display: grid;
  gap: 6px;
}

.auth-dialog {
  width: min(440px, calc(100% - 28px));
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--body-text);
  background: var(--paper);
  box-shadow: 0 28px 90px rgba(13, 23, 29, .24);
}
.auth-dialog::backdrop {
  background: rgba(13, 23, 29, .56);
  backdrop-filter: blur(4px);
}
.auth-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 13px;
  padding: 30px;
}
.auth-card h2 {
  margin: -4px 34px 0 0;
  font-size: 1.7rem;
  letter-spacing: 0;
}
.auth-copy, .provider-note {
  margin: 0;
  color: var(--muted);
  line-height: 1.5;
}
.provider-note {
  font-size: .78rem;
  text-align: center;
}
.dialog-close {
  position: absolute;
  top: 13px;
  right: 13px;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--muted);
  background: var(--paper);
  font-size: 1rem;
}
/* --on-fill is white, which on a light dialog put white on white and made the
   close control disappear at the moment it was being reached for. */
.dialog-close:hover:not(:disabled) { color: var(--body-text); }
.google-button {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
  border-color: var(--line-strong);
  /* Google's own colours, on a literal white ground rather than var(--paper).
     This is the one place in the app where light is load-bearing rather than
     mood: the mark is specified on white and #4285F4 is Google's blue, not
     ours. Reaching for --paper to get "white" worked until the rack redefined
     it, and then put #1F1F1F on #182933 - about 1.1:1, so "Continue with
     Google" was an invisible button on Home, Bench and Demo. */
  color: #1F1F1F;
  background: #FFFFFF;
}
.google-button span {
  font-weight: 900;
  color: #4285F4;
}
/* The sign-in form's four modes show and hide by data-auth-show (app.js's
   setAuthMode); the flex displays below would otherwise beat [hidden]. */
#auth-dialog [data-auth-show][hidden], #auth-dialog #auth-current-label[hidden], #auth-dialog #auth-current-password[hidden] { display: none; }
#auth-form-fields:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: 13px;
}
#auth-form-fields .field-label { margin-bottom: -7px; }
/* "Forgot your password?", "Create an account" and "Back to sign in" share a row. */
.auth-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 16px;
  margin-top: -6px;
}
.auth-links:not(:has(> :not([hidden]))) { display: none; }
.auth-hint { margin-top: -8px; text-align: left; }
.auth-legal {
  margin: 0;
  color: var(--muted);
  font-size: .78rem;
  text-align: center;
}
.auth-legal a { color: var(--teal); }
.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted-2);
  font-size: .76rem;
}
.auth-divider::before, .auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

@media (max-width: 980px) {
  .section-heading, .capture-grid, .result-hero {
    grid-template-columns: 1fr;
  }
  #collection-view > .section-heading { grid-template-columns: minmax(0, 1fr); }
  /* With the `:not([hidden])` the base rules carry, or this loses to their
     260px and 250px minimums and a phone narrower than 364px scrolls sideways. */
  .home-cases:not([hidden]) { grid-template-columns: minmax(0, 1fr); }
  .collection-toolbar {
    grid-template-columns: 1fr 1fr;
  }
  .search-field { grid-column: 1 / -1; }
  .copy-detail-hero {
    grid-template-columns: 150px minmax(0, 1fr);
  }
  .copy-detail-actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
  .detail-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .discogs-release-row {
    grid-template-columns: 48px minmax(0, 1fr);
  }
  .discogs-release-actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
  .copy-discogs-row {
    grid-template-columns: 48px minmax(0, 1fr);
  }
  .copy-discogs-row-actions {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
  }
}

@media (max-width: 700px) {
  :root { --page-column: min(1220px, calc(100% - 24px)); }
  /* The phone: two records across, the button under the welcome and as wide as
     it, and the things left to finish stacked. */
  .home-records { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 14px; }
  .home-finish-list, .home-steps-list { grid-template-columns: minmax(0, 1fr); }
  .home-view.is-dashboard .home-hero { grid-template-columns: minmax(0, 1fr); }
  .home-view.is-dashboard .home-actions { grid-column: 1; grid-row: auto; margin-top: 8px; }
  .home-view.is-dashboard .home-actions .primary-command { width: 100%; }
  .app-main {
    padding-top: 24px;
  }
  .home-hero {
    min-height: 320px;
    padding: clamp(20px, 7vw, 28px);
  }
  .intake-state-grid {
    grid-template-columns: 1fr;
  }
  /* 9vw: the longest word in the decided welcome, "GrooveBench.", is wider
     than the old headline's longest word, and at 11vw (the value tuned for
     that one) it no longer fit - the hero's min-content widened the whole
     Home view, a grid with no explicit column, and a 390px phone scrolled
     sideways by 17px, the same failure this rule was first written to fix.
     The 1.6rem floor is for a 280px screen (a folded phone), where 2rem still
     left "GrooveBench." wider than the hero. */
  .home-hero h1 { font-size: clamp(1.6rem, 9vw, 3.5rem); }
  .capture-summary, .metrics-grid, .metric-card dl, .collection-toolbar {
    grid-template-columns: 1fr;
  }
  .drop-zone {
    border-right: 0;
    border-bottom: 1px solid #314650;
    min-height: 250px;
  }
  .score-ring { margin: auto; }
  .capture-summary { text-align: left; }
  .report-actions {
    align-items: stretch;
    flex-direction: column;
  }
  .report-buttons { flex-direction: column; }
  .secondary-button { width: 100%; }
  .bench-copy-controls,
  .bench-copy-result,
  .copy-detail-hero,
  .copy-form-grid,
  .detail-grid,
  .detail-grid.compact {
    grid-template-columns: 1fr;
  }
  /* These three are `display: flex`, and were in the list above - where
     `grid-template-columns` does nothing at all. So they never stacked, and
     `.secondary-button { width: 100% }` a few rules up then sized the button
     beside the text to the full row: the content came out wider than its
     container and escaped it. At 375px that put the Discogs button's right edge
     71px past the viewport, which was the whole of the document's horizontal
     overflow - the bench scrolled sideways and the tab bar was cut off. */
  .source-id-command-row,
  .source-id-candidate-heading,
  .source-id-discogs-heading {
    flex-direction: column;
    align-items: stretch;
  }
  .copy-detail-actions,
  .dialog-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .copy-detail-title h3 {
    font-size: clamp(1.8rem, 12vw, 2.8rem);
  }
  .copy-detail-hero .copy-art {
    min-height: 220px;
  }
  .copy-form {
    padding: 24px;
  }
  .dialog-actions button,
  .source-id-command-row button,
  .bench-copy-controls .secondary-button {
    width: 100%;
  }
  .spectrogram-card { padding: 14px; }
  .spectrogram-heading {
    flex-direction: column;
    gap: 8px;
  }
  .spectrogram-readout { text-align: left; }
  .collection-meta { flex-direction: column; }

}

/* A route change puts focus on the new view's heading (shell.js), which is not
   something anyone can operate; it needs no ring. */
.app-view h1[tabindex="-1"]:focus, .app-view h2[tabindex="-1"]:focus { outline: none; }

@media (prefers-reduced-motion: reduce) {
  * {
    scroll-behavior: auto !important;
    transition: none !important;
  }
}
/* The Bench intake used to be a right-hand column: a two-column grid whose wide
   side held the rack and the results and whose narrow side held the record
   intake. Everything below is what that column cost - the results were being
   squeezed to fit beside it. The intake is a full-width rack unit now, so the
   squeezing goes with it and the results are back on their own rules.

   .results kept its top margin here because the wrapper supplied it. */
.results { margin-top: 24px; }
.bench-observations, .intake-save-area { border: 1px solid var(--line, #d7dfe2); padding: 24px; background: var(--paper); }
.bench-observations h3, .intake-save-area h3 { margin: 0 0 8px; }
.bench-observations p, .intake-save-area p, .pressing-help p { color: var(--muted); font-size: 14px; line-height: 1.6; }
#bench-notes { margin: 12px 0 0; padding-left: 20px; color: var(--muted); font-size: 14px; line-height: 1.65; }
#bench-notes li + li { margin-top: 8px; }
.intake-save-area { margin-top: 24px; }
.intake-save-area select { width: 100%; max-width: 680px; }
/* "Sign in to save to your Collection" is long for a phone: it wraps rather than widen the page. */
.intake-save-area .primary-command { max-width: 100%; white-space: normal; }
.current-capture-context { border-top: 1px solid #d7dfe2; margin-top: 20px; padding-top: 16px; }
.current-capture-context p { margin: 4px 0 10px; }
.current-capture-context audio { width: 100%; }
#intake-saved-actions { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
#intake-saved-actions[hidden], .legacy-intake-control { display: none !important; }
#intake-view-copy { color: #0b8392; }
.pressing-help { margin-top: 18px; font-size: 14px; }
.source-id-panel .pressing-help p { color: inherit; }
.source-id-panel input, .source-id-panel select { max-width: 100%; min-width: 0; }
@media (max-width: 560px) {
  .bench-observations, .intake-save-area, .source-id-panel { padding: 16px; }
  .intake-save-area .intake-actions { align-items: stretch; flex-direction: column; }
}
#capture-player audio { display: block; width: 100%; margin: 12px 0; }
#capture-player #player-analysis-note { color: #52616a; padding: 0 16px; }
#capture-player[hidden], #spectrogram-stack[hidden], #player-legend[hidden] { display: none !important; }

/* Capture comparison: a multitrack bench, without the mixing affordances.
   Gain is shown and never draggable - a fader invites nudging one capture
   louder until you prefer it, which is the bias level matching removes. */
.compare-panel { margin-top: 22px; grid-column: 1 / -1; }
.compare-setup { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 14px; }
.compare-label { font-weight: 800; font-size: .8rem; }
/* The audio source bar (bench/source-bar.css draws the bar itself) heads the panel. */
#compare-source-bar { margin: 4px 0 14px; }
/* What the Source rows say this comparison is. It reads as an instrument's
   readout rather than a control, because it is one: nothing here is answered,
   it is all derived from the rows on the captures. The teal edge is the same
   one a soloed track carries and means the same thing - this one is settled. */
.compare-derived {
  border: 1px solid var(--line); border-left: 3px solid var(--line-strong);
  border-radius: var(--radius); padding: 10px 13px; margin-bottom: 12px;
}
.compare-derived.is-attributable { border-left-color: var(--teal); }
.compare-derived p { margin: 6px 0 0; font-size: .8rem; line-height: 1.5; }
.compare-derived .compare-dates {
  font: 800 .62rem/1.4 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .1em; color: var(--muted);
}
/* What each recording was made with, side by side. The table scrolls inside its
   own box: a phone with four recordings is wider than the screen, and the page
   must not be. */
.compare-compat {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 13px; margin-bottom: 12px;
}
.compare-compat-scroll { overflow-x: auto; max-width: 100%; margin-top: 6px; }
.compare-compat table { border-collapse: collapse; font-size: .76rem; min-width: 100%; }
.compare-compat th, .compare-compat td {
  text-align: left; padding: 4px 10px 4px 0; vertical-align: top; border-bottom: 1px solid var(--line);
}
.compare-compat th { font-weight: 800; }
.compare-compat tr.differs td { font-weight: 800; }
.compare-compat td.unrecorded { color: var(--muted); font-style: italic; }
.compare-compat-notes { margin: 8px 0 0; padding-left: 18px; font-size: .8rem; line-height: 1.5; }
.compare-status-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 14px; }
.compare-status-row .panel-status { margin: 0; }
.compare-names { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.compare-names label { display: flex; align-items: center; gap: 7px; font-size: .76rem; font-weight: 750; }
.compare-names input { border: 1px solid var(--line); border-radius: var(--radius); padding: 7px 9px; width: 190px; }
.compare-names .is-reference::after { content: "Reference"; font: 800 .56rem/1 ui-monospace, monospace; letter-spacing: .1em; color: var(--teal-on-dark); }
.compare-plabel { font: 800 .6rem/1 ui-monospace, SFMono-Regular, Consolas, monospace; letter-spacing: .14em; color: var(--muted); }
/* `gap` and `flex-wrap`, because `space-between` alone gives no separation once
   there is no slack to distribute: at phone width the three labels butted
   together and the row read "MATERIAL13:20-14:00 OF 18:46 · LOOPING
   13:42-13:48DRAG TO LOOP A PASSAGE". The gap is the floor; wrapping is what
   happens when even that will not fit. */
.compare-lane-head {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 4px 14px; margin-bottom: 8px;
}
.compare-legend { margin-top: 18px; }
.compare-legend i { display: inline-block; width: 8px; height: 8px; vertical-align: -1px; }
.compare-legend i.ev-here { background: var(--red); }
.compare-legend i.ev-ref { background: var(--green); }
/* `touch-action: none` because a drag across this canvas selects a loop, and on
   a touch screen the scroll container claims the gesture otherwise: measured at
   390px, the pointer stream got two moves and then `pointercancel`, so the drag
   did nothing and the seek never fired either. `preventDefault()` on
   `pointerdown` does not stop a pan; only this does. The transport track and
   the side canvas already carried it - this one was missed. */
.compare-material canvas {
  width: 100%; height: 84px; display: block; touch-action: none;
  background: #0D171D; border: 1px solid var(--line-strong);
}
.compare-tracks { display: flex; flex-direction: column; gap: 8px; }
.compare-track {
  display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 14px; align-items: center;
  border: 1px solid var(--line-strong); border-radius: var(--radius); padding: 9px 11px;
}
.compare-track.is-soloed { border-color: var(--teal); background: var(--teal-soft); }
.compare-track.is-reference .compare-figures { color: var(--teal-on-dark); }
.compare-solo {
  flex: 0 0 auto; width: 52px; height: 52px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--soft); color: inherit; font-weight: 850; font-size: .74rem; letter-spacing: .04em;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
}
.compare-track.is-soloed .compare-solo { border-color: var(--teal); background: var(--teal); color: var(--on-fill); }
.compare-solo small { font: 800 .54rem/1 ui-monospace, monospace; opacity: .7; }
.compare-track-id { display: flex; align-items: center; gap: 11px; min-width: 0; }
.compare-track-name { font-weight: 800; font-size: .85rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.compare-figures { margin-top: 4px; font: 800 .62rem/1 ui-monospace, SFMono-Regular, Consolas, monospace; color: var(--muted); }
.compare-track canvas { width: 100%; height: 52px; display: block; background: #0D171D; border: 1px solid var(--line); }
.compare-unaligned { margin-top: 10px; border: 1px solid var(--red); border-radius: var(--radius); padding: 11px 13px; font-size: .78rem; line-height: 1.5; }
.compare-transport { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 18px; }
.compare-transport input[type="range"] { flex: 1 1 140px; min-width: 0; }
.compare-transport label { display: flex; align-items: center; gap: 7px; font-size: .8rem; font-weight: 700; }
.compare-transport select { border: 1px solid var(--line); border-radius: var(--radius); padding: 7px 9px; }
.mono-figure { font: 800 .9rem/1 ui-monospace, SFMono-Regular, Consolas, monospace; }
.compare-footnote { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); color: var(--muted); font-size: .8rem; line-height: 1.5; }
/* What the comparison's figures cannot see: a muted note, not a warning. */
.compare-skips-note { margin: 0 0 12px; color: var(--muted); font-size: .8rem; line-height: 1.5; }
@media (max-width: 860px) {
  .compare-track { grid-template-columns: 1fr; }
  .compare-track canvas { height: 40px; }
  .compare-names input { width: 100%; }
}

/* ---- Bench as an instrument surface ----------------------------------------
   The charts already draw on dark grounds - #2d3436 plots, teal and amber
   traces, a near-black spectrogram floor - so the light chrome around them was
   always the mismatch. Tokens are redefined for this view only; Collection
   stays the light catalogue the art direction asks for. Deleting this block
   reverts the whole thing. */
#bench-view {
  --danger-text: #E7A6A2;
  --amber: #E8B25C;
  --paper: #182933;
  --soft: #14212A;
  --line: #223640;
  --line-strong: #2E4550;
  --muted: #8B9DA5;
  --muted-2: #92A4AC;
  --shadow: none;
  --teal-soft: #10323A;
  --body-text: #E8ECEE;
  /* The height the pinned transport takes out of the viewport. One number:
     the dock is sized by it and the page reserves exactly it, so the bar and
     the space kept clear for it cannot drift apart. */
  --transport-dock: 110px;
  background: var(--bench);
  color: #E8ECEE;
  padding: 26px 0 calc(48px + var(--transport-dock));
}
#bench-view h1, #bench-view h2, #bench-view h3, #bench-view h4,
#bench-view strong, #bench-view b, #bench-view dd, #bench-view legend { color: #FFFFFF; }
#bench-view a { color: var(--teal-on-dark); }

/* An instrument has an edge, not a float. */
#bench-view .spectrogram-card, #bench-view .metric-card, #bench-view .chart-card,
#bench-view .method-note, #bench-view .results, #bench-view .bench-copy-panel {
  border-color: var(--line-strong);
  box-shadow: none;
}
#bench-view input[type="text"], #bench-view input[type="email"], #bench-view input[type="number"],
#bench-view input[type="date"], #bench-view input[type="search"], #bench-view select, #bench-view textarea {
  background: #0D171D;
  border-color: var(--line-strong);
  color: #E8ECEE;
}
#bench-view input::placeholder { color: #5E7077; }
#bench-view .toolbar-field span {
  font-size: .8125rem; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--muted-2);
}

/* The generic button is dark-on-dark once the surface flips, so it is restated
   rather than left to inherit into invisibility. The audio source bar is left
   out: it carries its own look (bench/source-bar.css), and an id here outranks
   its pill's chosen state, which then never shows. */
#bench-view button:not(.sb *) { border-color: var(--line-strong); background: #223640; color: #E8ECEE; }
#bench-view .primary-command { border-color: var(--teal); background: var(--teal); color: #FFFFFF; }
#bench-view .secondary-button { background: transparent; border-color: var(--teal); color: var(--teal-on-dark); }
#bench-view .text-button { background: transparent; border: 0; color: var(--teal-on-dark); }
#bench-view .grade-chip { background: #14212A; border-color: var(--line-strong); color: #E8ECEE; }
#bench-view .score-ring { border-color: var(--line-strong); }
#bench-view .metric-card header b, #bench-view .chart-heading small { color: var(--teal-on-dark); }
#bench-view .spectrogram-legend { color: var(--muted); }

/* Engraved panel labels, and one shared instrument language for the headers. */
#bench-view .metric-card header span, #bench-view .chart-heading strong,
#bench-view .spectrogram-heading strong { letter-spacing: -.01em; }
#bench-view .metric-card header b {
  font: 800 .62rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .14em;
}

/* Bench: states the token flip cannot reach on its own. */
#bench-view .bench-observations, #bench-view .intake-save-area { border-color: var(--line-strong); }
#bench-view button:disabled:not(.sb *) { opacity: 1; background: #16242C; color: #55686F; border-color: #223640; }
#bench-view .section-number, #bench-view .spectrogram-readout,
#bench-view .chart-heading small, #bench-view .source-card b { color: var(--teal-on-dark); }
#bench-view .toggle-switch { border-color: var(--line-strong); }

/* The rack.

   Every instrument on the Bench is a unit in one stack: a label strip, a state
   readout, a screen, and a hairline edge. The graticule lives on the screen
   itself rather than on a placeholder, so an empty unit is the instrument at
   rest and a full one is the same unit with a trace on it. Nothing is hidden
   and swapped for something styled differently, which is what made the earlier
   version read as bolted on.

   Rules from the design canvas: engraved labels, large monospace readouts with
   the unit kept small and separate, a flat face, no drop shadow, one accent
   used as signal rather than chrome. */
#bench-view .rack { display: grid; gap: 12px; margin: 18px 0 22px; }

#bench-view .rack-unit {
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  background: var(--paper);
  padding: 13px 15px 14px;
  box-shadow: none;
}
#bench-view .rack-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; margin-bottom: 9px;
}
/* Labels are read, so they are set to be read (UX review 8, finding 17): the
   body face at 13px, sentence case, in --muted-2. They were 10px monospace
   capitals at about 3.7:1 on the rack, which is hard going for anyone over
   forty. The unit is still engraved: weight and the quiet colour do that. */
#bench-view .panel-label {
  font-family: inherit; font-weight: 600; font-size: .8125rem; line-height: 1.3;
  letter-spacing: 0; text-transform: none; color: var(--muted-2);
}
#bench-view .rack-state {
  font-family: inherit; font-weight: 400; font-size: .8125rem; line-height: 1.3;
  letter-spacing: 0; text-transform: none; color: var(--muted);
  text-align: right; min-width: 0;
}

/* The screen. The graticule is a repeating gradient, so there is no markup per
   line and nothing to redraw on resize; a canvas drawn on top simply covers it. */
#bench-view .rack-screen {
  position: relative;
  background:
    repeating-linear-gradient(to right, #223640 0 1px, transparent 1px 12.5%),
    repeating-linear-gradient(to bottom, #223640 0 1px, transparent 1px 25%),
    #0D171D;
  border: 1px solid #1C2B33;
  overflow: hidden;
}
#bench-view .rack-screen > canvas,
#bench-view .rack-screen .spectrogram-stack:not([hidden]),
#bench-view .rack-screen .spectrogram-stack > canvas {
  display: block; width: 100%; height: 100%;
}
#bench-view .rack-screen--tall { height: 300px; }
#bench-view .rack-screen--lane { height: 120px; }
#bench-view .rack-screen--short { height: 190px; }

#bench-view .rack-foot { margin-top: 11px; display: grid; gap: 9px; }
#bench-view .rack-foot audio { width: 100%; }
#bench-view .rack-note {
  margin: 9px 0 0; font-size: .8125rem; color: var(--muted); line-height: 1.5;
}

@media (max-width: 720px) {
  #bench-view .rack-screen--tall { height: 200px; }
  #bench-view .rack-screen--short { height: 140px; }
  #bench-view .rack-screen--lane { height: 92px; }
  #bench-view .rack-state { font-size: .75rem; }
}

/* The rest of the Bench is rack gear too.

   The instruments were the easy half. A rack that sits above panels styled like
   an older page reads as bolted on, which is exactly how it looked. These rules
   put every remaining surface on the Bench into the same language rather than
   restructuring their markup: one face, one edge, engraved labels, monospace
   readouts, no shadow. */
#bench-view .settings-panel,
#bench-view .source-id-panel,
#bench-view .bench-observations,
#bench-view .metric-card,
#bench-view .intake-save-area,
#bench-view .method-note {
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  background: var(--paper);
  box-shadow: none;
}

/* Engraved labels: small, wide-tracked, quiet. The section numbers were already
   close to this; the panel headings join them instead of competing. */
#bench-view .section-number,
#bench-view .field-label,
#bench-view .compare-plabel {
  font-size: .8125rem; line-height: 1.3; font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-2);
}
/* The pill is light, so its text is dark: --muted-2 is for text on the rack. */
#bench-view .field-label.experimental-tag { color: #33454D; }
/* A card's name is a heading, not a caption: full colour, a little larger. */
#bench-view .metric-card > header > span {
  font-size: .9375rem; line-height: 1.3; font-weight: 700;
  letter-spacing: 0; text-transform: none; color: #E8ECEE;
}
/* The capitals tags on the card heads (HIGH, ENABLED, SOURCE-INCLUSIVE,
   HOMOGENEOUS / CLEAN) are the lab's words (UX review 8, finding 4). They stay
   in the page, as the card's tooltip, and out of sight. */
#bench-view .metric-card > header > b { display: none; }
#bench-view .panel-heading h3,
#bench-view .bench-observations h3 {
  font-size: 1rem;
  letter-spacing: normal;
}
/* A meter's state sits opposite its label, the way it does on a rack unit. */
#bench-view .metric-card > header > b,
#bench-view .status-pill {
  font: 400 .68rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  background: none;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 4px 7px;
}
/* Large monospace numerals, with the unit kept small and separate. */
#bench-view .metric-card > strong,
#bench-view .score-ring > strong {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-weight: 850;
  letter-spacing: -.02em;
}
#bench-view .metric-card dt,
#bench-view .capture-summary dt {
  font-family: inherit; font-size: .8125rem; font-weight: 400; line-height: 1.4;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-2);
}
#bench-view .metric-card dd,
#bench-view .capture-summary dd {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
}

/* The record intake, as a unit in the rack.

   It was a sticky right-hand column, which was a fix for the void that column
   left beside the shorter meters - a sidebar propped up by another sidebar
   behaviour. The rack has no sidebars: a bench is units stacked across the
   full width, and identity is a property of the record being measured rather
   than something running alongside the measurement. It takes the same face,
   edge and engraved label as Source and Spectrum, and the teal left edge it
   used to carry stays: it is the one optional unit on the bench, and the edge
   is what says so. */
#bench-view .source-id-panel {
  margin: 12px 0 18px;
  padding: 13px 15px 16px;
  border-left: 3px solid var(--teal);
}
/* Sub-readouts on a meter are a row of small gauges, not a paragraph. */
#bench-view .metric-card dt { font-size: .8125rem; line-height: 1.35; }
#bench-view .metric-card dd { font-size: .86rem; }

/* A switch with a visible position, per the instrument rules: you can see which
   way it is set without reading it. */
#bench-view .rack-controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }
#bench-view .rack-switch { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 2px; overflow: hidden; }
#bench-view .rack-switch button {
  font-family: inherit; font-weight: 600; font-size: .8125rem; line-height: 1;
  letter-spacing: 0; text-transform: none;
  background: #0D171D; color: var(--muted-2); border: 0; padding: 7px 11px; cursor: pointer;
}
#bench-view .rack-switch button + button { border-left: 1px solid var(--line-strong); }
#bench-view .rack-switch button:hover { color: #C5D0D5; }
#bench-view .rack-switch button.is-on { background: var(--teal-soft); color: var(--teal-on-dark); }

/* The dock: the master transport, pinned to the foot of the viewport.

   The rack is seven units tall and does not fit a 900 px screen. The drawing
   answers that not by shrinking the instruments but by fixing the one control
   that drives all of them - the play key, the read head down every unit, and
   the passage A/B hands over - to the bottom edge, so it is reachable from
   anywhere in the stack without scrolling back for it.

   The space it occupies is reserved by #bench-view's bottom padding rather
   than overlaid, because a floating bar that covers the last unit of a page
   just moves the problem to whatever is underneath it. Both read
   --transport-dock, so the bar and the gap kept clear for it are one number.

   It is a child of #bench-view, and that is what keeps it off the other
   routes: the shell hides a view with [hidden], .app-view[hidden] is display:
   none, and a fixed descendant of a display:none ancestor is not rendered.
   Home, Demo, Collection and Captures have no transport and get no bar,
   without the shell having to know this element exists. */
/* A TOOL SHOWS ITS INPUT FIRST AND ITS OUTPUT ONLY WHEN THERE IS ONE (site
   structure, Part 2 rule 3). The rack, "How it was measured", the pinned
   transport and the Keep panel start hidden and app.js's showResultPanels
   reveals them with a measurement. The ids below set their own `display`, so
   `[hidden]` alone would lose to them. With the dock hidden the page keeps no
   room for it. */
#bench-view [data-needs-result][hidden], #bench-rack[hidden], #transport-dock[hidden] { display: none !important; }
#bench-view:has(.transport-dock[hidden]) { padding-bottom: 48px; }

#bench-view .transport-dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  /* Under the sticky header, which is 20 - they cannot meet, but a bar that
     outranked the navigation would be the wrong way round if they ever did. */
  z-index: 15;
  height: var(--transport-dock);
  display: flex;
  align-items: center;
  background: var(--bench);
  border-top: 1px solid var(--line-strong);
}
/* Same column as .app-main, so the track lands on the same axis as the
   instrument screens above it instead of running edge to edge under them. */
#bench-view .transport-dock > .transport {
  width: var(--page-column);
  margin: 0 auto;
}
/* Engraved on the unit, as in the drawing: this is the master transport and it
   does not scroll. Dropped on phone widths, where the clock and the key are
   what the row has room for. */
#bench-view .transport-pin {
  margin-left: 2px; min-width: 0; flex: 1 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The transport. Rack gear, not a browser widget: a key that shows its position,
   a monospace clock, and a track carrying the read head. */
#bench-view .transport {
  display: grid;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  background: #0D171D;
}
#bench-view .transport-controls { display: flex; align-items: center; gap: 12px; }
#bench-view .transport-controls .transport-time--total { margin-left: auto; }
#bench-view .transport-key {
  width: 34px; height: 34px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: 2px;
  background: var(--paper); cursor: pointer;
}
#bench-view .transport-key:hover { border-color: var(--teal-on-dark); }
#bench-view .transport-key:active { background: var(--teal-soft); }
/* A triangle that becomes two bars, drawn in borders so there is no icon font
   and nothing to load. */
#bench-view .transport-glyph {
  width: 0; height: 0;
  border-top: 7px solid transparent; border-bottom: 7px solid transparent;
  border-left: 11px solid var(--teal-on-dark);
  margin-left: 2px;
}
#bench-view .transport.is-playing .transport-glyph {
  width: 10px; height: 13px; margin-left: 0; border: 0;
  border-left: 3.5px solid var(--teal-on-dark);
  border-right: 3.5px solid var(--teal-on-dark);
}
#bench-view .transport-time {
  font: 700 .8rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  color: #E8ECEE; font-variant-numeric: tabular-nums;
}
#bench-view .transport-time--total { color: var(--muted); }

/* The track carries a graticule like every other screen in the rack. */
#bench-view .transport-track {
  position: relative; height: 26px; cursor: pointer; touch-action: none;
  border: 1px solid #1C2B33;
  background: repeating-linear-gradient(to right, #223640 0 1px, transparent 1px 10%), #0A1216;
}
#bench-view .transport-track:focus-visible { outline: 1px solid var(--teal-on-dark); outline-offset: 2px; }
#bench-view .transport-elapsed {
  position: absolute; inset: 0 auto 0 0; width: 0;
  background: linear-gradient(to right, rgba(11,131,146,.12), rgba(11,131,146,.34));
  pointer-events: none;
}
/* The read head: the stylus position, the same fine line as the spectrogram
   playhead directly above it. */
#bench-view .transport-head {
  position: absolute; top: -3px; bottom: -3px; left: 0; width: 1px;
  background: #FFFFFF; box-shadow: 0 0 5px rgba(255,255,255,.55);
  pointer-events: none;
}
#bench-view .transport-head::before {
  content: ""; position: absolute; left: -3.5px; top: -1px;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 6px solid #FFFFFF;
}
@media (max-width: 560px) {
  #bench-view { --transport-dock: 116px; }
  #bench-view .transport { gap: 9px; padding: 9px; }
  #bench-view .transport-time { font-size: .72rem; }
  /* A thumb, not a pointer. */
  #bench-view .transport-key { width: 44px; height: 44px; }
  #bench-view .transport-pin { display: none; }
}

/* A short viewport is the case the pin costs more than it saves.

   At 500 px of height the bar is a fifth of the screen, permanently, and what
   it buys - not scrolling back for the play key - is worth less than the fifth
   of the rack it would hide. Below that it unpins and goes back into the flow
   as the last unit of the stack, which is where the drawing has it in document
   order anyway; the reserve goes to zero with it, because there is nothing
   overlaying the page any more. Width is not the trigger: the phone artboard
   keeps the bar pinned at 390 px wide, and it is right to - a tall narrow
   screen has the height to spare. */
@media (max-height: 560px) {
  /* The footer gives back the clearance it kept for the pinned bar. */
  body:has(#bench-view:not([hidden])) .site-footer { padding-bottom: 24px; }
  #bench-view { --transport-dock: 0px; }
  #bench-view .transport-dock {
    position: static;
    height: auto;
    display: block;
    margin-top: 22px;
    border-top: 0;
    background: none;
  }
  #bench-view .transport-dock > .transport { width: auto; }
  #bench-view .transport-pin { display: none; }
}

/* The side overview: the whole capture, with the loaded passage shown on it. */
#bench-view .compare-side { margin: 0 0 14px; }
#bench-view .compare-side-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 7px;
}
#bench-view .compare-side-canvas, #bench-view #compare-side-canvas {
  display: block; width: 100%; height: 64px;
  border: 1px solid #1C2B33; background: #0A1216;
  cursor: grab; touch-action: none;
}
#bench-view #compare-side-canvas:active { cursor: grabbing; }
#bench-view #compare-side-canvas.is-fixed { cursor: default; opacity: .8; }

/* Source, as a table.

   One row per capture: the file on the left, then the variables that describe
   how it was made. They live on the capture because that is what lets A/B work
   out what changed between two of them instead of asking - the model behind
   that (gear/model.js) predates this table by a long way and had no inputs.

   The grid is declared once and shared by the header and every row, so a column
   cannot drift between them. */
#bench-view .source-table {
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--soft); padding: 13px 15px;
}
#bench-view .source-table.dragging { border-color: var(--teal); background: var(--teal-soft); }
#bench-view .source-head,
#bench-view .source-row {
  display: grid; grid-template-columns: minmax(0,1.5fr) minmax(0,1.5fr) minmax(0,1fr) 175px;
  gap: 0 14px; align-items: center;
}
#bench-view .source-col {
  font-family: inherit; font-weight: 600; font-size: .8125rem; line-height: 1.2;
  letter-spacing: 0; text-transform: none; color: var(--muted-2); padding-bottom: 8px;
}
#bench-view .source-row { border-top: 1px solid var(--line); padding: 10px 0; }
#bench-view .source-cell { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
/* The library picker borrows the Source table's two row classes, and the
   `<dialog>` is a sibling of `#bench-view` rather than a child of it - so every
   row in the picker drew at the body's 16px Inter, the file name and the detail
   line under it identical, with no hierarchy at all. The dialog is added to the
   selector rather than given a second copy of the declarations: one spelling,
   the way `bench/source-table.js` owns what a condition is. */
#bench-view .source-name,
.library-dialog .source-name {
  font: 700 .875rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#bench-view .source-detail,
.library-dialog .source-detail {
  /* A caption, so the body face at 13 px (UX review 8, finding 17); the file's
     name above it keeps the monospace. */
  font-family: inherit; font-size: .8125rem; line-height: 1.35;
  letter-spacing: 0; color: var(--muted-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#bench-view .source-value {
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start; text-align: left;
  background: none; border: 0; padding: 0; color: inherit; font: inherit; cursor: pointer; min-width: 0; width: 100%;
}
#bench-view .source-value .source-name { font-family: inherit; font-weight: 600; font-size: .875rem; }
#bench-view .source-value:hover .source-name { color: var(--teal-on-dark); }
#bench-view .source-value--empty {
  border: 1px dashed var(--line-strong); border-radius: var(--radius);
  padding: 6px 9px; color: var(--muted); font-size: .8125rem;
  /* Not full width: stretched across the column it reads as an empty text
     field, and the one thing it must not look like is somewhere to type. */
  width: auto; align-self: flex-start;
}
/* The gear of the chosen rig, read-only (Jacob, 29 Sep: the rig replaces the
   typed chain): a label and a name per stage, in the chain's order. */
#bench-view .source-chain-read { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
#bench-view .source-chain-read-stage { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
#bench-view .source-chain-read-stage .source-detail { flex: none; width: 5.2rem; }
#bench-view .source-chain-read-stage .source-name { font-weight: 600; min-width: 0; }
/* A cable the rig names is the link between the two pieces it joins (7 Oct,
   Jacob), drawn between them in a lighter line, never as a stage of its own. */
#bench-view .source-chain-read-stage--link {
  margin-left: 6px; padding-left: 10px; border-left: 2px dashed var(--line-strong);
  font-size: .78rem; color: var(--muted);
}
#bench-view .source-chain-read-stage--link .source-detail { width: auto; }
#bench-view .source-chain-read-stage--link .source-name { font-weight: 500; overflow-wrap: anywhere; }
/* The same link inside the rig editor's grid: it spans the row and reads as a
   joint between the field above and the one below. */
#bench-view .source-chain-field--link {
  grid-column: 1 / -1; margin-left: 6px; padding-left: 10px; border-left: 2px dashed var(--line-strong);
}
#bench-view .source-chain-field--link .field-label { font-weight: 500; }
#bench-view .source-select {
  background: var(--paper); color: inherit; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 5px 7px; font-size: .8125rem; max-width: 100%;
}
#bench-view .source-foot {
  display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  border-top: 1px solid var(--line); padding-top: 11px; margin-top: 2px;
}
#bench-view .source-foot-spacer { flex-grow: 1; }
/* Said above the buttons that choose a recording, on a line of its own: it is
   about what to choose, so it sits by "Choose a recording" and not in the
   section's lede. */
#bench-view .source-format-note {
  flex-basis: 100%; margin: 0; color: var(--muted-2); font-size: .8125rem; line-height: 1.45;
}
/* A second way to choose or keep something, so it wears the outlined secondary
   style like every other button of its rank, not a dashed "+" box (UX review 8,
   finding 6). */
#bench-view .source-add {
  border: 1px solid var(--teal); border-radius: var(--radius); background: transparent;
  padding: 7px 12px; color: var(--teal-on-dark); font: inherit; font-size: .8125rem; font-weight: 700; cursor: pointer;
}
#bench-view .source-add:hover { background: var(--teal); color: var(--on-fill); }
#bench-view .source-field { display: flex; align-items: center; gap: 8px; }
#bench-view .switch-row--inline { display: flex; align-items: center; gap: 8px; border: 0; padding: 0; }
#bench-view .source-library-why {
  margin: 11px 0 0; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 12px; font-size: .8125rem; line-height: 1.55; color: var(--muted);
}
/* The library, in the Bench.

   Both the picker's control and the keep panel live inside the Source table,
   because that is what they are about: a stored capture is a source row that
   arrived by a different door. Neither has a disabled state in here - a page
   with no library removes them (library/ui.js), so there is no greyed control
   to style. */
/* The keep toggle sits in the save area, not in Source, because the decision
   it carries is part of filing the record. It is a checkbox and a sentence, and
   the size estimate hangs off the sentence rather than beside it so the line
   wraps as one thought on a phone. */
#bench-view .library-keep-with-save:not([hidden]) {
  display: flex; align-items: baseline; gap: 8px;
  margin: 0; cursor: pointer; line-height: 1.45;
}
#bench-view .library-keep-with-save input { margin: 0; flex: none; }
#bench-view .library-keep-with-save small { display: inline; margin-left: 4px; }
/* Optional notes: a quiet disclosure beside Save, closed until opened. */
#bench-view .capture-notes { margin: 0; }
#bench-view .capture-notes > summary { cursor: pointer; color: var(--muted); font-size: .9375rem; }
#bench-view .capture-notes[open] { display: grid; gap: 8px; }
#bench-view .capture-notes > summary { margin-bottom: 0; }
/* The one line under the tick, indented to sit under its sentence. */
#bench-view .library-keep-why:not([hidden]) { margin: 2px 0 0 24px; color: var(--muted); font-size: .875rem; line-height: 1.45; }
#bench-view .library-keep { margin-top: 11px; }
#bench-view .library-keep-panel:not([hidden]) {
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 12px 14px; background: var(--paper); display: grid; gap: 10px;
}
#bench-view .library-keep-panel .source-detail { white-space: normal; }
#bench-view .library-keep-actions { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
/* WHAT TO KEEP. A fieldset, because the two radios are one question, and a
   `grid` rather than the browser's default so the window row sits under the
   option it belongs to instead of beside it. `border: 0` because the panel
   already draws a box and a box inside a box reads as two panels. */
#bench-view .library-keep-what:not([hidden]) {
  display: grid; gap: 6px; border: 0; margin: 0; padding: 0; min-width: 0;
}
#bench-view .library-keep-what legend { padding: 0; }
#bench-view .library-keep-what label { display: flex; align-items: baseline; gap: 2px 7px; flex-wrap: wrap; }
#bench-view .library-keep-what label small { flex-basis: 100%; margin-left: 24px; }
/* The two fields on one line with their words, wrapping together on a phone
   rather than leaving "to" stranded at the end of a row. */
#bench-view .library-keep-window:not([hidden]) {
  display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; padding-left: 22px;
}
#bench-view .library-keep-window input { max-width: 6.5em; }
/* THE CLIP PICKER. The drawing spans the panel; the buttons sit under it.
   Desktop first: on a phone the two fields are the choice and this is not
   drawn (docs/briefs/clip-picker.md). */
#bench-view .library-keep-picker:not([hidden]) { display: grid; gap: 7px; padding-left: 22px; min-width: 0; }
#bench-view .clip-picker:not([hidden]) { display: grid; gap: 7px; min-width: 0; }
#bench-view .clip-picker-canvas {
  display: block; width: 100%; height: 72px; border: 1px solid var(--line); border-radius: var(--radius);
  cursor: col-resize; touch-action: none;
}
#bench-view .clip-picker-canvas:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
#bench-view .clip-picker-controls { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
#bench-view .clip-picker-snap { display: flex; align-items: center; gap: 5px; }
#bench-view .clip-picker-readout, #bench-view .clip-picker-limit, #bench-view .clip-picker-phone { margin: 0; }
#bench-view .clip-picker-limit.at-cap { color: var(--amber); }
#bench-view .clip-picker-phone { display: none; }
/* Match to an existing clip: a labelled list and the sentence it answers with,
   under the picker; shown on a phone too, since it only sets the two fields. */
#bench-view .library-keep-match:not([hidden]) { display: grid; gap: 6px; padding-left: 22px; min-width: 0; }
#bench-view .library-keep-match select { max-width: 100%; }
#bench-view .library-keep-match p { margin: 0; }
@media (max-width: 640px) {
  #bench-view .clip-picker { display: none !important; }
  #bench-view .clip-picker-phone { display: block; }
}
/* A bar with a number beside it, not a spinner: this runs for minutes on a real
   side, and the one question it has to answer is whether it is still moving. */
#bench-view .library-progress:not([hidden]) { display: grid; gap: 6px; }
#bench-view .library-progress-track {
  height: 6px; border: 1px solid var(--line); border-radius: 3px; background: var(--soft); overflow: hidden;
}
#bench-view .library-progress-track > i {
  display: block; height: 100%; width: 0; background: var(--teal); transition: width .2s linear;
}

/* The picker is drawn dark because it belongs to the Bench - it is a Source
   row arriving, and it sits in front of the rack. It is a top-level dialog
   rather than one inside #bench-view, because a modal inside a hidden section
   does not render, so it redefines the rack's palette here the same way
   #bench-view does rather than inheriting the page's light one. */
.library-dialog {
  --danger-text: #E7A6A2;
  --amber: #E8B25C;
  --paper: #182933;
  --soft: #14212A;
  --line: #223640;
  --line-strong: #2E4550;
  --muted: #8B9DA5;
  --body-text: #E8ECEE;
  width: min(900px, calc(100% - 28px));
  /* A PHONE IN LANDSCAPE IS ABOUT 390px TALL.

     The dialog had no height bound at all. A record with several stored
     captures makes a card taller than that viewport, and a `dialog` that
     overflows its viewport does not scroll by itself - it renders past the
     edge with nothing to bring it back, which on a short screen means the
     visible area can hold none of the card. Bounded and scrollable, so the
     list is reachable on the screen the owner actually had in his hand. */
  max-height: calc(100dvh - 24px);
  overflow: auto;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  color: var(--body-text);
  background: var(--paper);
  box-shadow: 0 28px 90px rgba(13, 23, 29, .44);
}
.library-dialog h2, .library-dialog strong { color: #FFFFFF; }
/* The backdrop is a colour, and the blur is asked for separately and only
   where it is supported. `backdrop-filter` on `::backdrop` is the part mobile
   Safari has historically painted as opaque black over everything, taking the
   dialog with it - and a blur is decoration, so it is not worth a screen
   nobody can read. The colour alone is the whole of what it has to do. */
.library-dialog::backdrop { background: rgba(13, 23, 29, .56); }
@supports (backdrop-filter: blur(4px)) and (not (-webkit-touch-callout: none)) {
  .library-dialog::backdrop { backdrop-filter: blur(4px); }
}
.library-card { position: relative; display: grid; gap: 12px; padding: 30px; }
.library-card h2 { margin: -4px 42px 0 0; font-size: 1.6rem; }
.library-scope { margin: 0; font-size: .82rem; color: var(--muted); }
/* The same grid for the header and every row, so a column cannot drift between
   them - the Source table's rule, for the same reason. */
.library-head,
.library-row {
  display: grid; grid-template-columns: 24px minmax(0,1.5fr) minmax(0,1.4fr) minmax(0,.9fr) 84px 74px;
  gap: 0 14px; align-items: center;
}
.library-head .source-col { padding-bottom: 6px; }
/* THE GUARD THAT MAKES `hidden` WORK ON THESE.

   `[hidden] { display: none }` is a user-agent rule of the lowest possible
   specificity, so the grid above beats it and the element stays on screen no
   matter what the attribute says - the failure written up at `.home-cases` and
   got wrong twice since. Both of these are put away while the other is up. */
.library-head[hidden], .library-records[hidden] { display: none; }
.library-list { display: grid; }
/* The record chooser. Rows rather than the capture grid, because a record is a
   name and a count, and borrowing five capture columns to say that would leave
   three of them empty on every line. */
.library-records { display: grid; }
.library-record-row {
  display: grid; gap: 2px 14px; width: 100%; text-align: left;
  border: 0; border-top: 1px solid var(--line); border-radius: 0;
  padding: 12px 0; background: transparent; color: inherit; cursor: pointer;
}
.library-record-row:hover { background: var(--soft); }
.library-record-name { font-size: .94rem; font-weight: 600; color: #FFFFFF; }
/* One line per record, not one column: it holds the pressing, the count, the
   sides and a date, which does not fit a phone on one line and is worth more
   whole than ellipsised. */
.library-record-row .source-detail { white-space: normal; overflow: visible; }
.library-back { justify-self: start; }
/* Removing one capture from the comparison, and the record page's list of the
   audio this account has kept. */
.compare-drop {
  flex: none; margin-left: 6px; border: 0; background: transparent;
  padding: 0 4px; font-size: 1rem; line-height: 1; color: var(--muted); cursor: pointer;
}
.compare-drop:hover { background: transparent; color: var(--danger-text, #E7A6A2); }
#compare-reset[hidden] { display: none; }
.copy-stored .stored-row {
  display: grid; grid-template-columns: 24px minmax(0, 1fr) minmax(0, .9fr) 84px 74px;
  gap: 0 14px; align-items: center;
  border-top: 1px solid var(--line); padding: 10px 0; cursor: pointer;
}
.copy-stored .stored-cell { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.copy-stored .source-name {
  font: 700 .82rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.copy-stored .source-detail {
  font: 400 .64rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .04em; color: var(--muted);
}
@media (max-width: 720px) {
  .copy-stored .stored-row { grid-template-columns: 24px minmax(0, 1fr); gap: 6px 12px; }
  .copy-stored .stored-row > *:not(input) { grid-column: 2; }
}
.library-back[hidden] { display: none; }
.library-row { border-top: 1px solid var(--line); padding: 11px 0; cursor: pointer; }
.library-row:hover { background: var(--soft); }
.library-cell { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.library-value { font-size: .82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The sentence the picker exists to be able to say, so it reads as a finding
   rather than as another row. */
.library-derived {
  margin: 0; border-top: 1px solid var(--line); padding-top: 11px;
  font-size: .82rem; line-height: 1.55; color: var(--teal-on-dark);
}

@media (max-width: 720px) {
  .library-head { display: none; }
  .library-row { grid-template-columns: 24px minmax(0, 1fr); gap: 7px 12px; }
  .library-row > *:not(input) { grid-column: 2; }
}

#bench-view .source-chain-editor {
  margin-top: 12px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 13px 14px; background: var(--paper); display: grid; gap: 11px;
}
#bench-view .source-chain-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 11px;
}
#bench-view .source-chain-field { display: grid; gap: 5px; min-width: 0; }
#bench-view .source-chain-field input {
  background: var(--soft); color: inherit; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 7px 9px; font-size: .82rem; min-width: 0;
}
#bench-view .source-chain-editor .secondary-button { justify-self: start; }
#bench-view .source-chain-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
/* The rig editor is the panel that forks a rig, so it does not look like the one
   that describes a capture. The whole design rests on him knowing which he is
   typing into, and two identical panels would put that on his memory. */
#bench-view .source-chain-editor--rig { border-color: var(--teal); }
#bench-view .source-rig-name { display: inline-flex; align-items: center; gap: 6px; }
#bench-view .source-rig-name input {
  background: var(--soft); color: inherit; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 5px 8px; font-size: .78rem; width: 11rem;
}

/* One line above the table, and only when there is a rig to name. It sits above
   the header rather than in a cell because it describes the apparatus rather
   than this file, and because a line that appears and disappears inside the grid
   would move the columns. */
#bench-view .source-rig {
  display: flex; flex-wrap: wrap; align-items: center; gap: 9px; padding-bottom: 10px;
}
#bench-view .source-rig[hidden] { display: none; }
#bench-view .source-rig .source-name { white-space: normal; }
#bench-view .source-rig-overrides { flex: 1 1 12rem; min-width: 0; }

/* How a stage was set: closed until he opens it, and a stage with nothing in it
   shows one quiet word. A chain is five boxes and done unless he wants more. */
#bench-view .source-chain-settings { display: grid; gap: 7px; justify-items: start; }
#bench-view .source-settings-toggle {
  background: none; border: 0; padding: 0; cursor: pointer; color: var(--muted);
  font-family: inherit; font-size: .8125rem; font-weight: 400; line-height: 1.3;
  letter-spacing: 0; text-transform: none; text-decoration: underline;
}
#bench-view .source-settings-toggle:hover { color: var(--teal-on-dark); }
#bench-view .source-settings-editor { display: grid; gap: 7px; width: 100%; }
#bench-view .source-settings-rows { display: grid; gap: 6px; }
#bench-view .source-setting-row {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 5px; align-items: center;
}
#bench-view .source-setting-row input { font-size: .76rem; padding: 5px 7px; }
#bench-view .source-setting-remove {
  background: none; border: 0; padding: 0 4px; cursor: pointer; color: var(--muted);
  font-size: .9rem; line-height: 1;
}
#bench-view .source-setting-remove:hover { color: var(--teal-on-dark); }
#bench-view .source-settings-offered { display: flex; flex-wrap: wrap; gap: 5px; }
#bench-view .source-setting-starter,
#bench-view .source-setting-add {
  background: none; border: 1px dashed var(--line-strong); border-radius: var(--radius);
  padding: 3px 7px; cursor: pointer; color: var(--muted);
  font: 400 .68rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
}
#bench-view .source-setting-starter:hover,
#bench-view .source-setting-add:hover { color: var(--teal-on-dark); border-color: var(--teal-on-dark); }
#bench-view .source-setting-add { justify-self: start; }

/* The tags, in his own words: chips with a box after them
   (`capture/tag-input.js`), so a tag this browser has never seen is exactly as
   easy to write as one it has seen five hundred times; the lists that help are
   under the table, where a cell that grew when you clicked it cannot move the
   rows below it. */
#bench-view .source-tags-field {
  background: var(--paper); color: inherit; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 4px 6px; font-size: .78rem; width: 100%; min-width: 0;
}
#bench-view .tag-input input.tag-input-field {
  background: transparent; border: 0; padding: 3px 2px; color: inherit; font: inherit;
}
#bench-view .tag-input input.tag-input-field::placeholder { color: var(--muted); }
#bench-view .tag-input-chip { border-color: var(--line-strong); }
#bench-view .tag-input-remove { background: none; border: 0; color: var(--muted); }
#bench-view .tag-input-remove:hover:not(:disabled) { background: none; color: var(--red-on-dark); }
#bench-view .source-condition-editor { gap: 9px; }
#bench-view .source-tag-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 9px; }
#bench-view .source-tag-chip {
  display: inline-flex; align-items: baseline; gap: 3px;
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 2px 4px 2px 7px; font-size: .72rem;
}

/* What he owns for this role. Nothing at all until the garage has something in
   it, so a first run is the text box it always was. */
#bench-view .source-garage { display: grid; gap: 6px; justify-items: start; }
#bench-view .source-garage-line { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
#bench-view .source-garage-line:empty { display: none; }
#bench-view .source-garage-label,
#bench-view .source-garage-held {
  color: var(--muted);
  font-family: inherit; font-size: .8125rem; font-weight: 400; line-height: 1.3;
  letter-spacing: 0; text-transform: none; text-decoration: underline;
}
#bench-view .source-garage-rename {
  background: none; border: 0; padding: 0; cursor: pointer; color: var(--muted);
  font: 400 .62rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em; text-transform: uppercase; text-decoration: underline;
}
#bench-view .source-garage-rename:hover { color: var(--teal-on-dark); }
#bench-view .source-garage .source-rig-name { flex-wrap: wrap; gap: 5px; }
#bench-view .source-garage .source-rig-name input { width: 9rem; }
/* THE CATALOGUE DISAGREES WITH WHICH BOX THIS WAS TYPED IN. A sentence with an
   action, so it takes a row of its own rather than trailing off the end of the
   chips: `flex-basis: 100%` inside the line's wrap, which is what puts it under
   them instead of beside them. A span in a flex row, not a table cell - the
   `display: flex` that cost the Collection shelf its columns is only a hazard on
   a <td>. */
#bench-view .source-garage-misfiled {
  flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding-top: 2px;
}
#bench-view .source-garage-misfiled-said {
  color: var(--muted); font-size: .76rem; line-height: 1.35;
}
#bench-view .source-commands {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px;
}
#bench-view .source-commands .status { margin: 0; }
/* The audio source bar (bench/source-bar.css draws the bar itself) sits above
   the source table with the table's own spacing. */
#bench-view #measure-source-bar { margin-bottom: 14px; }
/* THE RECORDER (bench/recorder.js): Ready, Recording and Review recording, the
   three screens Jacob approved on 8 Oct. They sit under the source bar for the
   Live source. Colors are the Bench's own tokens; the three that are not tokens
   are the red of clipping (an input problem), the waveform and the green of a
   met check, set once on `.rec`. Every size answers to the width of the box, so
   at a phone's width the strip and the two columns stack and nothing pushes the
   page sideways. */
#bench-view .measure-recorder { margin: 0 0 14px; min-width: 0; }
#bench-view .measure-recorder:empty { display: none; }
#bench-view .rec {
  --rec-red: #E2685E; --rec-wave: #4FB3C1; --rec-ok: var(--green-on-dark); --rec-mono: ui-monospace, SFMono-Regular, Consolas, monospace;
  background: var(--paper); border: 1px solid var(--line-strong); border-radius: 6px; color: var(--body-text);
  display: flex; flex-direction: column; min-width: 0; overflow: visible; font-size: 14px;
}
#bench-view .rec[hidden], #bench-view .rec [hidden] { display: none !important; }
#bench-view .rec button, #bench-view .rec select, #bench-view .rec input { font: inherit; }
#bench-view .rec :focus-visible { outline: 2px solid var(--teal-on-dark); outline-offset: 2px; }
#bench-view .rec-context { margin: 0; padding: 10px 32px 0; text-align: right; font-size: .8125rem; color: var(--muted); overflow-wrap: anywhere; }
#bench-view .rec-lbl { font-family: var(--rec-mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
#bench-view .rec-mono { font-family: var(--rec-mono); }
#bench-view .rec-dim { color: var(--muted); }
#bench-view .rec-sub { font-size: .75rem; color: var(--muted); }
#bench-view .rec .rec-link { color: var(--teal-on-dark); background: none; border: 0; padding: 0; text-decoration: underline; cursor: pointer; font-size: .75rem; }
#bench-view .rec-spacer { flex: 1 1 auto; }
#bench-view .rec-unit { color: var(--muted); font-size: .75rem; font-weight: 400; }
#bench-view .rec-caption { font-size: .75rem; color: var(--muted); line-height: 1.45; }
#bench-view .rec-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; }
#bench-view .rec-ch { font-family: var(--rec-mono); font-size: .8125rem; color: var(--muted); }
#bench-view .rec-screen { display: flex; flex-direction: column; min-width: 0; }

/* The strip across the top of Ready. */
#bench-view .rec-strip { display: grid; grid-template-columns: 1.4fr 1.6fr 1.4fr .8fr; border-bottom: 1px solid var(--line-strong); }
#bench-view .rec-field { display: flex; flex-direction: column; gap: 6px; padding: 14px 20px; border-right: 1px solid var(--line); min-width: 0; }
#bench-view .rec-field:last-child { border-right: 0; }
#bench-view .rec-select {
  appearance: none; -webkit-appearance: none; width: 100%; min-width: 0; padding: 4px 18px 4px 0; border: 0; border-radius: 0; background-color: transparent; color: var(--body-text);
  font-size: .875rem; cursor: pointer; text-overflow: ellipsis;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 9px) 55%, calc(100% - 4px) 55%; background-size: 5px 5px; background-repeat: no-repeat;
}
#bench-view .rec-select:disabled { cursor: default; color: var(--muted); }
#bench-view .rec-select--quiet { color: var(--muted); }
#bench-view .rec-select--inline { width: auto; font-size: .75rem; color: var(--muted); padding-right: 14px; }
#bench-view .rec-select option { background: var(--soft); color: var(--body-text); }

/* Ready: the level, the last ten seconds, and the five things to check. */
#bench-view .rec-cols { display: flex; min-width: 0; }
#bench-view .rec-col { flex: 1 1 0; min-width: 0; padding: 22px 32px; display: flex; flex-direction: column; gap: 20px; }
#bench-view .rec-col--main { border-right: 1px solid var(--line); gap: 18px; }
#bench-view .rec-checks { flex: 0 0 360px; padding: 22px 28px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
#bench-view .rec-meters { display: flex; flex-direction: column; gap: 10px; }
#bench-view .rec-meter-row { display: grid; grid-template-columns: 28px minmax(0, 1fr) 118px; gap: 12px; align-items: center; }
#bench-view .rec-meter-row--small { grid-template-columns: 18px minmax(0, 1fr) 56px; gap: 10px; }
#bench-view .rec-meter-row--scale { align-items: start; }
#bench-view .rec-meter { position: relative; height: 22px; background: var(--ink); border: 1px solid var(--line-strong); border-radius: 2px; overflow: hidden; }
#bench-view .rec-meter-row--small .rec-meter { height: 16px; }
#bench-view .rec-zone { position: absolute; top: 0; bottom: 0; background: rgba(111, 207, 151, .13); border-left: 1px dashed rgba(111, 207, 151, .5); border-right: 1px dashed rgba(111, 207, 151, .5); }
#bench-view .rec-fill { position: absolute; top: 3px; bottom: 3px; left: 0; width: 0; background: var(--teal); border-radius: 1px; transition: width .12s linear; }
#bench-view .rec-hold { position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px; background: var(--body-text); }
#bench-view .rec-figure { font-family: var(--rec-mono); font-size: .9375rem; text-align: right; font-variant-numeric: tabular-nums; }
#bench-view .rec-meter-row--small .rec-figure { font-size: .8125rem; }
#bench-view .rec-scale { position: relative; height: 16px; font-family: var(--rec-mono); font-size: 11px; color: var(--muted); }
#bench-view .rec-scale span { position: absolute; top: 0; }
#bench-view .rec-status { display: flex; gap: 14px; align-items: flex-start; background: var(--soft); border: 1px solid var(--line); border-radius: 4px; padding: 16px 18px; }
#bench-view .rec-status-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
#bench-view .rec-status-line { font-size: .9375rem; font-weight: 600; }
#bench-view .rec-helper { font-size: .8125rem; color: var(--muted); line-height: 1.5; }
#bench-view .rec-dot { flex: 0 0 20px; height: 20px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; border: 1px solid var(--line-strong); color: var(--muted); }
#bench-view .rec-status[data-tone="green"] .rec-dot, #bench-view .rec-check[data-tone="ok"] .rec-dot { background: rgba(111, 207, 151, .18); border-color: transparent; color: var(--rec-ok); }
#bench-view .rec-status[data-tone="amber"] .rec-dot { background: rgba(232, 178, 92, .18); border-color: transparent; color: var(--amber); }
#bench-view .rec-status[data-tone="red"] .rec-dot, #bench-view .rec-check[data-tone="bad"] .rec-dot { background: rgba(226, 104, 94, .18); border-color: transparent; color: var(--rec-red); }
#bench-view .rec-status:not([data-tone="quiet"]) { }
#bench-view .rec-block { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
#bench-view .rec-lanes { background: var(--ink); border: 1px solid var(--line); border-radius: 4px; display: flex; flex-direction: column; justify-content: center; gap: 4px; padding: 6px 0; position: relative; }
#bench-view .rec-lanes--last { height: 120px; }
#bench-view .rec-lanes .rec-canvas { display: block; width: 100%; height: 40px; color: var(--rec-wave); }
#bench-view .rec-lanes--last .rec-canvas { height: 52px; }
#bench-view .rec-lanes .rec-ch--top, #bench-view .rec-lanes .rec-ch--bottom { position: absolute; left: 8px; z-index: 1; }
#bench-view .rec-lanes .rec-ch--top { top: 8px; }
#bench-view .rec-lanes .rec-ch--bottom { bottom: 8px; }
#bench-view .rec-checks-list { display: flex; flex-direction: column; }
#bench-view .rec-check { display: flex; gap: 12px; align-items: flex-start; padding: 10px 0; border-bottom: 1px solid var(--line); line-height: 1.4; }
#bench-view .rec-check:last-child { border-bottom: 0; }
#bench-view .rec-check-text { display: flex; flex-direction: column; min-width: 0; }

/* The footer: the button, the clock and the switches. */
#bench-view .rec-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 14px 28px; padding: 18px 32px; border-top: 1px solid var(--line-strong); background: var(--soft); border-radius: 0 0 6px 6px; margin-top: auto; }
#bench-view .rec .rec-record { display: flex; align-items: center; gap: 12px; height: 56px; padding: 0 28px 0 20px; border-radius: 28px; background: var(--bench-3); border: 1px solid var(--rec-red); color: var(--body-text); font-size: 1rem; font-weight: 700; cursor: pointer; }
#bench-view .rec .rec-record:disabled { opacity: .5; cursor: default; }
#bench-view .rec .rec-record-dot { width: 18px; height: 18px; border-radius: 9px; background: var(--rec-red); }
#bench-view .rec-clock { font-family: var(--rec-mono); font-size: 2.125rem; font-weight: 800; letter-spacing: .02em; font-variant-numeric: tabular-nums; }
#bench-view .rec-clock--big { font-size: 2.75rem; }
#bench-view .rec-switch { position: relative; display: flex; align-items: center; gap: 10px; cursor: pointer; }
#bench-view .rec-switch-input { position: absolute; opacity: 0; width: 36px; height: 20px; margin: 0; cursor: pointer; }
#bench-view .rec-switch-track { flex: 0 0 36px; width: 36px; height: 20px; border-radius: 10px; background: var(--line-strong); position: relative; }
#bench-view .rec-switch-track::after { content: ""; position: absolute; left: 3px; top: 3px; width: 14px; height: 14px; border-radius: 7px; background: var(--body-text); }
#bench-view .rec-switch-input:checked + .rec-switch-track { background: var(--teal); }
#bench-view .rec-switch-input:checked + .rec-switch-track::after { left: auto; right: 3px; }
#bench-view .rec-switch-input:focus-visible + .rec-switch-track { outline: 2px solid var(--teal-on-dark); outline-offset: 2px; }
#bench-view .rec-footer-note { font-size: .8125rem; color: var(--muted); }
#bench-view .rec .rec-stop { display: flex; align-items: center; gap: 12px; height: 56px; padding: 0 30px 0 22px; border-radius: 28px; background: var(--teal); border: 1px solid var(--teal); color: #fff; font-size: 1rem; font-weight: 700; cursor: pointer; }
#bench-view .rec .rec-stop-square { width: 16px; height: 16px; background: #fff; border-radius: 2px; }

/* Recording. */
#bench-view .rec-head { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 24px; padding: 20px 32px; border-bottom: 1px solid var(--line-strong); }
#bench-view .rec-title { display: flex; align-items: center; gap: 10px; font-size: .9375rem; font-weight: 700; }
#bench-view .rec-live-dot { width: 12px; height: 12px; border-radius: 6px; background: var(--rec-red); }
#bench-view .rec-h { margin: 0; font-size: 1.125rem; }
#bench-view .rec-meta { font-size: .875rem; color: var(--muted); }
#bench-view .rec-stat { display: flex; flex-direction: column; gap: 4px; padding: 0 20px; border-left: 1px solid var(--line); }
#bench-view .rec-stat-value { font-size: 1rem; font-variant-numeric: tabular-nums; }
#bench-view .rec-stat-value[data-clipping="true"] { color: var(--rec-red); }
#bench-view .rec-notice { margin: 22px 32px 0; display: flex; gap: 16px; align-items: center; border: 2px solid var(--rec-red); background: rgba(226, 104, 94, .10); border-radius: 6px; padding: 18px 22px; }
#bench-view .rec-notice-dot { width: 14px; height: 14px; border-radius: 7px; background: var(--rec-red); flex: 0 0 14px; }
#bench-view .rec-notice-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
#bench-view .rec-notice-head { font-size: 1.25rem; font-weight: 700; }
#bench-view .rec-notice-body { font-size: 1rem; line-height: 1.45; }
#bench-view .rec-block--side, #bench-view .rec-block--review { padding: 26px 32px 0; }
#bench-view .rec-block--review { padding-top: 34px; }
#bench-view .rec-wave { position: relative; margin-top: 24px; border: 1px solid var(--line); border-radius: 4px; }
#bench-view .rec-block--review .rec-wave { margin-top: 0; }
#bench-view .rec-lane { position: relative; height: 72px; background: var(--ink); border-bottom: 1px solid var(--line); }
#bench-view .rec-lane:last-of-type { border-bottom: 0; }
#bench-view .rec-lane--tall { height: 88px; }
#bench-view .rec-lane .rec-ch { position: absolute; left: 8px; top: 6px; z-index: 2; }
#bench-view .rec-lane .rec-canvas { display: block; width: 100%; height: 100%; color: var(--rec-wave); }
#bench-view .rec-marks { position: absolute; inset: 0; pointer-events: none; }
#bench-view .rec-mark { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px dashed var(--muted); }
#bench-view .rec-flag { position: absolute; top: -22px; transform: translateX(-50%); font-family: var(--rec-mono); font-size: 11px; white-space: nowrap; padding: 2px 6px; border-radius: 2px; color: var(--muted); }
#bench-view .rec-mark--drop { border-left: 1px solid var(--teal-on-dark); }
#bench-view .rec-mark--drop .rec-flag { background: var(--bench-3); color: var(--teal-on-dark); }
#bench-view .rec-mark--clip { border-left: 2px solid var(--rec-red); }
#bench-view .rec-mark--clip .rec-flag { top: auto; bottom: -22px; background: rgba(226, 104, 94, .15); color: var(--rec-red); }
#bench-view .rec-playhead { position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px; left: 0; background: var(--body-text); pointer-events: none; }
#bench-view .rec-flag--play { background: var(--body-text); color: var(--ink); }
#bench-view .rec-hatch { position: absolute; top: 0; bottom: 0; right: 0; left: 0; background: repeating-linear-gradient(90deg, transparent 0 11px, rgba(46, 69, 80, .35) 11px 12px); pointer-events: none; }
#bench-view .rec-ruler { position: relative; height: 18px; margin-top: 6px; }
#bench-view .rec-tick { position: absolute; top: 0; font-family: var(--rec-mono); font-size: 11px; color: var(--muted); transform: translateX(-50%); }
#bench-view .rec-block--side .rec-ruler { margin-bottom: 0; }
#bench-view .rec-cols--low { padding: 22px 32px 26px; gap: 28px; }
#bench-view .rec-cols--low > .rec-col { padding: 0; gap: 8px; }
#bench-view .rec-col--level { flex: 0 0 420px; gap: 10px; }

/* Review. */
#bench-view .rec-zoom { display: flex; border: 1px solid var(--line-strong); border-radius: 999px; padding: 3px; }
#bench-view .rec .rec-pill { font-size: .8125rem; color: var(--muted); background: transparent; border: 0; border-radius: 999px; height: 30px; padding: 0 14px; cursor: pointer; }
#bench-view .rec .rec-pill[aria-pressed="true"] { background: var(--bench-3); color: var(--body-text); }
#bench-view .rec-dim-block { position: absolute; top: 0; bottom: 0; background: rgba(13, 23, 29, .72); pointer-events: none; }
#bench-view .rec-dim-block--start { left: 0; width: 0; }
#bench-view .rec .rec-handle { position: absolute; top: -6px; bottom: -6px; left: 0; width: 24px; margin-left: -12px; padding: 0; border: 0; background: none; cursor: ew-resize; touch-action: none; z-index: 1; display: flex; align-items: center; justify-content: center; }
#bench-view .rec .rec-handle::before { content: ""; position: absolute; top: 0; bottom: 0; left: 6px; right: 6px; background: var(--teal); border-radius: 3px; }
#bench-view .rec .rec-handle.is-front { z-index: 2; }
#bench-view .rec .rec-handle[data-offscreen] { opacity: .45; }
#bench-view .rec .rec-handle:focus-visible { outline: 2px solid #fff; outline-offset: 0; }
#bench-view .rec-grip { position: relative; width: 2px; height: 20px; background: var(--body-text); opacity: .8; border-radius: 1px; }
#bench-view .rec .rec-play-row { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; padding: 16px 32px; }
#bench-view .rec .rec-play { width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; background: var(--bench-3); border: 1px solid var(--line-strong); border-radius: 4px; color: var(--body-text); cursor: pointer; }
#bench-view .rec .rec-play svg { fill: currentColor; }
#bench-view .rec .rec-play-time { font-size: .9375rem; font-variant-numeric: tabular-nums; }
#bench-view .rec-trimmed { font-size: .8125rem; }
#bench-view .rec-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; padding: 4px 32px 22px; }
#bench-view .rec-tile { background: var(--soft); border: 1px solid var(--line); border-radius: 4px; padding: 14px 16px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
#bench-view .rec-tile[data-red="true"] { border-color: var(--rec-red); }
#bench-view .rec-tile[data-red="true"] .rec-tile-value { color: var(--rec-red); }
#bench-view .rec-tile-value { font-size: 1.375rem; font-weight: 800; }
#bench-view .rec-review > .rec-notice { margin: 0 32px 22px; }
#bench-view .rec .rec-button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 44px; padding: 0 16px; border-radius: 4px; background: var(--bench-3); border: 1px solid var(--line-strong); color: var(--body-text); font-size: .875rem; cursor: pointer; }
#bench-view .rec .rec-button--ghost { background: transparent; }
#bench-view .rec .rec-button:disabled { opacity: .5; cursor: default; }
#bench-view .rec .rec-button--primary { height: 52px; padding: 0 28px; background: var(--teal); border-color: var(--teal); color: #fff; font-size: 1rem; font-weight: 700; }
#bench-view .rec-audio { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* Live source: the recorder replaces the rig line and the speed under the bar, and the
   general advice for making a recording elsewhere (the Recorded source's format line included). The Recorded source keeps them. */
#bench-view[data-measure-source="live"] #source-rig,
#bench-view[data-measure-source="live"] .source-foot .source-field,
#bench-view[data-measure-source="live"] #source-format-note,
#bench-view[data-measure-source="live"] #check-before-recording,
#bench-view[data-measure-source="live"] #how-to-record { display: none; }

@media (max-width: 900px) {
  #bench-view .rec-strip { grid-template-columns: 1fr; }
  #bench-view .rec-field { border-right: 0; border-bottom: 1px solid var(--line); padding: 12px 16px; }
  #bench-view .rec-field:last-child { border-bottom: 0; }
  #bench-view .rec-cols { flex-direction: column; }
  #bench-view .rec-col, #bench-view .rec-cols--low > .rec-col { padding: 18px 16px; }
  #bench-view .rec-cols--low { padding: 18px 16px; gap: 18px; }
  #bench-view .rec-cols--low > .rec-col { padding: 0; }
  #bench-view .rec-col--main { border-right: 0; border-bottom: 1px solid var(--line); }
  #bench-view .rec-checks { flex: 0 0 auto; padding: 18px 16px; }
  #bench-view .rec-col--level { flex: 1 1 auto; }
  #bench-view .rec-head, #bench-view .rec-footer, #bench-view .rec-play-row { padding-left: 16px; padding-right: 16px; }
  #bench-view .rec-block--side, #bench-view .rec-block--review { padding-left: 16px; padding-right: 16px; }
  #bench-view .rec-notice { margin-left: 16px; margin-right: 16px; }
  #bench-view .rec-review > .rec-notice { margin-left: 16px; margin-right: 16px; }
  #bench-view .rec-tiles { padding-left: 16px; padding-right: 16px; grid-template-columns: 1fr; }
  #bench-view .rec-clock--big { font-size: 2rem; }
  #bench-view .rec-stat { border-left: 0; padding: 0; }
  #bench-view .rec-meter-row { grid-template-columns: 22px minmax(0, 1fr) 92px; gap: 8px; }
  #bench-view .rec-footer { gap: 12px 18px; }
  #bench-view .rec-flag { font-size: 10px; padding: 1px 4px; }
  #bench-view .rec-scale span:nth-child(4), #bench-view .rec-scale span:nth-child(7) { display: none; }
}
/* A side recorded here is kept nowhere else: the warning and the button that
   saves it. The warning is in the amber the page uses for "look at this", and
   the button is the page's primary one, so it is the thing the eye lands on. */
#bench-view .measure-recorded { margin: 12px 0 0; flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
#bench-view .measure-recorded[hidden] { display: none; }
#bench-view .measure-recorded > p { margin: 0; }
#bench-view .measure-recorded > #measure-recorded-note { flex-basis: 100%; }
#bench-view .measure-recorded > #measure-recorded-note:empty { display: none; }
#bench-view .measure-recorded-warning { color: var(--amber); font-weight: 700; font-size: .9rem; line-height: 1.35; }
#bench-view .measure-recorded-warning.is-saved { color: var(--muted); font-weight: 400; }
#bench-view #measure-recorded-save { cursor: pointer; }

/* At phone width the columns stop being columns. A row becomes a stack with
   the labels repeated per field, because a five-column grid at 390 px is four
   truncated columns and a photo. */
@media (max-width: 720px) {
  #bench-view .source-head { display: none; }
  #bench-view .source-row { grid-template-columns: minmax(0, 1fr); gap: 9px 12px; }
  #bench-view .source-cell--capture { grid-column: 1; }
  #bench-view .source-row > .source-cell:not(.source-cell--capture) { grid-column: 1 / -1; }
  #bench-view .source-commands { flex-direction: column; align-items: stretch; }
}

/* Difference lanes, inside Spectrum.

   They used to sit in the A/B unit, one canvas per capture row. But a lane
   plots dB-against-the-reference over time, and time is the axis this unit
   already owns - so drawn down there they were a second, unlabelled copy of
   the same x-axis, 236 px away from the one they agreed with. Up here they
   share the spectrogram's axis and its read head by construction.

   The left inset matches PLOT_INSET in app.js so a lane's t=0 sits exactly
   under the spectrogram's t=0. That number is duplicated deliberately: the
   canvas is drawn in JS and the label column is laid out in CSS, and they
   have to agree. */
#bench-view .difference-lanes:not([hidden]) { display: flex; flex-direction: column; gap: 5px; margin-top: 8px; }
/* A lane is a screen, with the same box as every other screen in the rack, so
   its canvas is the same width as the spectrogram's. The axis inset lives
   inside the drawing (PLOT_INSET in app.js), not in this file: matching a
   canvas's plot area with CSS padding means two places have to agree about one
   number, and they drifted by a pixel the first time it was tried. */
#bench-view .difference-lane {
  position: relative; border: 1px solid #1C2B33; background: #0D171D; overflow: hidden; height: 40px;
}
/* Two nested borders, matching .rack-screen wrapping .spectrogram-stack. The
   inner one is not decoration: the spectrogram canvas sits two borders inside
   its screen, so a lane canvas sitting one border inside its own would start a
   pixel to the left and the shared axis would be a pixel out. */
#bench-view .difference-lane > canvas {
  display: block; width: 100%; height: 100%; border: 1px solid #223640; background: transparent;
}
#bench-view .difference-lanes-note {
  margin: 8px 0 0; font: 400 .7rem/1.5 ui-monospace, SFMono-Regular, Consolas, monospace;
  color: var(--muted); letter-spacing: .02em;
}
@media (max-width: 860px) {
  #bench-view .difference-lane { height: 32px; }
}

/* The read head: one cursor down the whole rack. Same line, same colour, same
   moment on every instrument in the stack and on the transport below them. */
#bench-view .rack-screen { }
#bench-view .rack-readhead {
  position: absolute; top: 0; bottom: 0; left: 0; width: 1px;
  background: rgba(255,255,255,.95);
  box-shadow: 0 0 6px rgba(255,255,255,.45);
  pointer-events: none; z-index: 2;
}
#bench-view .rack-readhead::before {
  content: ""; position: absolute; left: -3.5px; top: 0;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid rgba(255,255,255,.95);
}

/* The rack takes the whole page with it.

   The palette is redefined on the body rather than patched per element, so the
   header and anything else on the page inherit the same dark tokens the rack
   uses. Naming the light tokens here would have painted a near-white nav pill
   onto a dark header: --teal-soft is #E2F3F5 at root and #10323A on the Bench.

   Home wears this as well as the Bench, which is why the class is no longer
   named after one route. Home is the front of the instrument: drawn light it
   read as a generic dashboard standing in front of a dark, specific product,
   and the two looked like different applications. The Collection stays light -
   the art direction asks for a catalogue there, and browsing is not
   measurement. */
body.is-rack {
  --danger-text: #E7A6A2;
  --amber: #E8B25C;
  --paper: #182933;
  --soft: #14212A;
  --line: #223640;
  --line-strong: #2E4550;
  --muted: #8B9DA5;
  --muted-2: #92A4AC;
  --shadow: none;
  --teal-soft: #10323A;
  --body-text: #E8ECEE;
  --on-fill: #E8ECEE;
  background: var(--bench);
  color: var(--body-text);
}
body.is-rack .app-main { background: var(--bench); }
/* The header's own dark rack (Home, Bench, Collection, the account menu) is
   `shell/frame.css`'s job now, not this file's - it carries its own colours
   from the brief rather than reading `body.is-rack`'s tokens, so the frame
   looks the same wherever it is loaded. */

/* ---------------------------------------------------------------- Captures

   The window onto the granted folder. Drawn in the page's light palette rather
   than the Bench's dark one: this is filing, not an instrument, and it sits
   beside Collection in what it is for. */
.captures-view { display: grid; gap: 18px; }
.captures-folder {
  padding: 18px;
  border: 1px solid var(--line);
  background: var(--soft);
  display: grid;
  gap: 10px;
}
.capture-folder-state {
  font-weight: 850;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: .78rem;
  color: var(--ink);
  margin: 0;
}
.captures-folder-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.captures-panel:not([hidden]) {
  padding: 18px;
  border: 1px solid var(--line);
  background: var(--paper);
  display: grid;
  gap: 12px;
}
.captures-panel-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.captures-panel-head h3 { margin: 0; font-size: 1rem; }
.captures-panel-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }

.capture-inbox-list { display: grid; gap: 12px; }
.capture-inbox-item {
  display: grid;
  gap: 8px;
  padding: 14px;
  border: 1px solid var(--line);
  background: var(--soft);
}
.capture-inbox-item strong { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* What the file says about itself, which is the whole answer to three sides
   exported as audio-01, -02 and -03. Two columns so the labels line up and the
   eye can run down the values comparing one file against the next. */
.capture-facts {
  display: grid;
  grid-template-columns: minmax(120px, auto) 1fr;
  gap: 4px 14px;
  margin: 0;
  font-size: .86rem;
}
.capture-facts dt { color: var(--muted); }
.capture-facts dd { margin: 0; color: var(--body-text); }
.capture-facts dd small { color: var(--muted-2); }

.capture-refusal { color: var(--red); margin: 0; font-size: .88rem; }
.capture-warning { color: var(--red); font-size: .84rem; }

.capture-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
}
.capture-form-wide { grid-column: 1 / -1; }
/* The path it is about to take, shown before he commits to it. Monospaced
   because it is a path, and a path read as prose is a path nobody checks. */
.capture-destination {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .84rem;
  color: var(--teal);
  margin: 0;
  word-break: break-all;
}

/* What the folder already holds, offered before anything is typed - a datalist
   only opens once somebody has started, and the spellings already in use are
   exactly what he needs to see first. */
.capture-tags-in-use:not([hidden]) {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 0;
}

/* A heading is derived from the tag's own text - `clean: wet cleaned` sits under
   "clean" - so the box around a group is drawn, not stored. An ungrouped tag has
   no heading and is otherwise identical, because it is not a lesser tag. */
.capture-tag-group { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; }
.capture-tag-group-name {
  color: var(--muted);
  font-size: .72rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.capture-tag-group-name::after { content: ":"; }

/* Examples he can throw away. Quieter than the tags actually in use, because
   what the folder holds is the real answer and this is only a prompt. */
.capture-tag-starters { opacity: .85; }
.capture-tag-dismiss { color: var(--muted); padding-inline: 2px; }
.capture-tag-dismiss:hover { color: var(--red); }
/* Things to look at, and audio with no sidecar is always first in it. */
.captures-problems { border-color: var(--red); }

/* A record's captures, in the Collection, under the copies they were made from.
   Drawn as the analysis history beside it is drawn, because it is the same kind
   of thing - what has happened to this record - rather than a list of files. */
.copy-captures { display: grid; gap: 12px; }
.capture-copy { display: grid; gap: 8px; }
.capture-copy h5 {
  margin: 0;
  font-size: .78rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.capture-entry {
  padding: 14px;
  border: 1px solid var(--line);
  background: var(--soft);
  display: grid;
  gap: 8px;
}
.capture-entry-heading {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: baseline;
}
/* The owner's own words, in his own spelling, on their own line: a capture may
   carry a dozen and they must not push the side and the condition off the end. */
.capture-entry .capture-tags { margin: 0; color: var(--muted); font-size: .8rem; }
/* Correcting a filed capture is an ordinary edit and looks like one. Nothing
   here is styled as a warning, because nothing about it is one. */
.capture-entry-editing { border-color: var(--teal); }
.capture-chain-field { display: grid; gap: 4px; }
.capture-setting-row {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: 6px;
  align-items: center;
}
.capture-entry-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }


/* The loop controls sit in the material lane's head, beside the range they
   describe. The hint is the thing that was missing: a canvas that accepts a
   drag and never says so is a canvas nobody drags. */
.compare-hint { opacity: .55; letter-spacing: .08em; }
.compare-loop-clear {
  margin-left: auto;
  padding: 2px 10px;
  font-size: 11px;
  line-height: 1.6;
}
.compare-loop-clear[hidden] { display: none; }

/* A record read through what was played. collection/captures-model.js builds
   the view; this is what it looks like. One side is a group, one capture is a
   row inside it, and the kept audio keeps the row shape it had in the old
   "Kept audio" section so that selecting two of them still looks like the same
   act it was before. */
.shelf-side { margin-top: 18px; }
.shelf-side h5 {
  font-size: .74rem;
  font-weight: 850;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
}
.shelf-event {
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.shelf-side .shelf-event:last-child { border-bottom: 0; }
.shelf-event-heading {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 4px;
}
.shelf-event-heading .source-name { font-weight: 850; }
.shelf-event p { margin-bottom: 0; }
.shelf-event .stored-row { margin-top: 8px; }

/* What a copy has been photographed of. The images are private and their URLs
   live about a minute, so a tile holds its own space and says what it is doing
   rather than collapsing between renewals - a grid that reflows every time a
   signature lands is worse than one that waits. */
.photo-group { margin-top: 16px; }
.photo-group h5 {
  font-size: .74rem;
  font-weight: 850;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
/* Thumbnails, not a wall. The first version asked for 150px minimum and one
   fraction each, so on a wide screen every photograph grew to fill its share -
   a record with four photographs got four enormous squares and the rest of the
   page went below the fold. Fixed-width tiles that do not stretch, so ten
   photographs and two look like the same kind of thing. */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, 132px);
  gap: 10px;
}
.photo-tile {
  margin: 0;
  border: 1px solid var(--line);
  background: var(--soft);
  display: grid;
  grid-template-rows: auto auto;
}
.photo-tile img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
  grid-row: 1;
}
.photo-waiting {
  grid-row: 1;
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  color: var(--muted);
  font-size: .78rem;
}
/* Both children sit in row 1, so the tile keeps its height whichever is shown. */
.photo-tile img[hidden] { display: none; }
.photo-caption {
  grid-row: 2;
  display: grid;
  gap: 2px;
  padding: 8px 10px;
  border-top: 1px solid var(--line);
}
.photo-door {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-top: 16px;
}
@media (max-width: 700px) {
  /* Two across on a phone rather than one: a record's photographs are read as a
     set, and one enormous tile per row makes the set invisible. */
  .photo-grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
  .photo-door { flex-direction: column; align-items: stretch; }
}

/* A surface photograph shown inside the capture it is evidence about. Smaller
   than the Photographs section's own grid: here it is a detail of a play, not
   the subject of the screen. */
.shelf-photos { margin-top: 10px; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }
.shelf-photos .photo-caption { padding: 6px 8px; }

/* THE COLLECTION AS TITLES, WITH WHAT IS UNDER THEM.

   Not one table with indented rows: a title has no RPM and a capture has no
   catalogue number, so each level draws its own columns and an expansion opens
   a table inside a cell. That is also why the widths are left to the browser
   rather than pinned - three different column sets cannot share one grid. */
.shelf-toggle-cell { width: 34px; padding-right: 0 !important; }
.shelf-disclosure {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  color: var(--body-text);
  font-weight: 850;
  line-height: 1;
  padding: 0;
}
/* THREE LEVELS THAT LOOK LIKE THREE LEVELS.

   Opened together, the first version was grids inside grids with nothing saying
   where one ended and the next began. Depth is now carried by three things at
   once, because any one of them alone is too quiet: a RAIL down the left of
   each nesting, a step in BACKGROUND from the title's fill through the records
   to the captures, and a step down in type size. */
.shelf-title-row > td {
  background: var(--soft);
  border-top: 2px solid var(--line-strong);
  border-bottom: 0;
  padding-top: 14px;
  padding-bottom: 14px;
}
.shelf-title-row > td:first-child { border-left: 3px solid var(--ink); }
/* The grade range and what it spans, stacked rather than run together: they
   were reading as "94.1 / NMacross 2 graded copies". */
.shelf-title-row .grade-chip + .source-detail { display: block; margin-top: 3px; }
.shelf-name-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: center;
}
.shelf-title-cell strong { font-size: 1rem; min-width: 0; }

/* Artist and album are two columns now, so the artist wants the same weight as
   any other cell - it was a caption under the album and is a column heading's
   worth of information in its own right. */
.shelf-artist-cell {
  min-width: 0;
  /* At least as bold as the album beside it. The artist is not a caption for
     the album; on a shelf it is the first thing you look for. */
  font-weight: 800;
  font-size: 1rem;
}

/* SORTING IS THE HEADING. It has to look pressable without turning the head
   row into a row of buttons: no border, no fill, the heading's own type, and
   the arrow holding its space so the columns do not shift when the sort
   moves from one to another. */
.shelf-sort {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}
.shelf-sort:hover { color: var(--teal); }
.shelf-sort.is-sorted { color: var(--teal); }
.shelf-sort-mark { display: inline-block; min-width: 0.7em; font-size: 0.85em; }
.shelf-thumb {
  width: 40px;
  height: 40px;
  object-fit: cover;
  border: 1px solid var(--line);
  flex: none;
}
/* The records inside a title: inset, on the page colour, behind a rail that
   runs the height of the group so the eye can see where the title's contents
   start and stop. */
.shelf-children > td {
  /* NO HORIZONTAL INSET. It was 18px, which - with the 3px rail - pushed every
     nested column 21px left of the one above it, so a year at one level never
     sat over a year at the next. Nesting is still plain from the rail, the
     change of background and the level's own header row; 3px of rail is a
     difference the eye does not read as a misalignment, and 21px is. */
  padding: 0 !important;
  background: var(--paper);
  border-bottom: 2px solid var(--line-strong);
  border-left: 3px solid var(--ink);
}
.shelf-inner { font-size: .82rem; }
.shelf-inner > thead th {
  background: transparent;
  border-bottom: 1px solid var(--line-strong);
  padding-top: 12px;
}
.shelf-inner > tbody > tr > td { border-bottom: 1px solid var(--line); }
/* THE CAPTURES ARE ROWS OF THE RECORD'S OWN TABLE.

   They used to be a nested list of spans, so a grade chip landed wherever the
   text before it ended - three chips under one record at three positions, and
   no headings over any of them. They are rows now, so they take the same column
   widths as the two levels above by construction rather than by two rules
   agreeing. Quieter, inset by background and rail rather than by padding. */
.shelf-capture-row > td {
  background: var(--soft);
  border-bottom: 0;
}
.shelf-capture-row > td:first-child { border-left: 3px solid var(--teal); }
/* THE PLAYS' HEADER ROW: the same type as any column header (the table's own
   `th` rule gives it), on the plays' background, ruled beneath so it reads as
   the head of what follows and not as another side heading. Its labels use
   `.shelf-capture-inner`'s tracks, so each sits over its field. */
.shelf-capture-head > th {
  background: var(--soft);
  border-bottom: 1px solid var(--line-strong);
  padding-top: 8px;
  padding-bottom: 6px;
  font-weight: 700;
}
.shelf-capture-head > th:first-child { border-left: 3px solid var(--teal); }
.shelf-capture-head .shelf-capture-inner { align-items: end; }
/* The cell stays a cell. `display: flex` on a <td> removes it from the table
   layout, which took the whole capture row out of the column grid.

   AND THE FIELDS INSIDE IT ARE TRACKS, NOT A FLOW. This was a flex row, so
   every field sat wherever the one before it ended: a play with "wet cleaned"
   pushed its format 118px right of the play without one, and a shorter chain
   pulled it left again. Three plays under one record, three different
   verticals - the same complaint as the original jog, one level further in,
   and the geometry check did not see it because it was asserting that the
   GRADE column agreed across the three levels and never that a field agreed
   with itself one row down.

   A grid fixes it by construction: a track is where it is whether or not the
   row has anything to put in it. `auto` last, so a long chain grows into the
   space rather than shifting what follows. */
.shelf-capture-inner {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 15rem) 8rem minmax(0, 1fr);
  gap: 4px 10px;
  align-items: baseline;
}
/* The heading and the side rows carry one label, which belongs at the start
   rather than stretched over four tracks. */
.shelf-capture-side-row .shelf-capture-inner,
.is-quiet .shelf-capture-inner { display: block; }
.shelf-capture-when { white-space: nowrap; }
/* The rig name, and the stages behind it. The name is a button because the
   chain has to be reachable without a pointer; the `title` makes it free with
   one. */
.shelf-capture-rig { display: inline-flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.shelf-capture-rig-name { font-weight: 700; }
.shelf-capture-stages[hidden] { display: none; }
.shelf-capture-format { font-variant-numeric: tabular-nums; }
/* A note exists and is one hover away. The row says so rather than printing a
   paragraph into a line. */
.shelf-capture-note {
  border-bottom: 1px dotted currentColor;
  cursor: help;
}
/* A fact we do not have, drawn as a fact we do not have. */
.source-detail.is-unknown { font-style: italic; opacity: .85; }
.shelf-capture-grade { white-space: nowrap; }
.shelf-capture-side { font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.shelf-capture-row.is-quiet > td { color: var(--muted); }
/* The captures inside a record: one step further in, one step quieter, and no
   table chrome at all - by this depth the question is "what has been done to
   this record", not "line these up in columns". */
/* The innermost level gets a rail of a DIFFERENT COLOUR, not just a thinner
   one. The backgrounds alternate as they nest - fill, page, fill - which reads
   on its own but leaves the third level looking like the first at a glance. */
.shelf-inner .shelf-children > td {
  border-left: 3px solid var(--teal);
  border-bottom: 0;
  background: var(--soft);
  padding-left: 0 !important;
}

/* ONE WIDTH PER COLUMN, WHEREVER IT APPEARS. `collection.js` tags every cell
   with `col-<key>`, so a column keeps its width at whichever level it is
   drawn. The two that mean the same thing at both levels - the grade and the
   year - are given the same width and the same position, so they line up.

   The first column is left to the browser on purpose: it takes up the slack,
   which is what keeps the trailing columns on the same vertical when one level
   has more columns than another. */
.col-copies { width: 96px; }
.col-condition { width: 204px; }
.col-measured { width: 112px; }
.col-year { width: 84px; }
.col-original_year { width: 104px; }
.col-country, .col-format { width: 104px; }
.col-catalog_number { width: 132px; }
.col-added, .col-acquired { width: 112px; }
.col-clicks, .col-scratches, .col-balance { width: 112px; }
.col-noise { width: 128px; }
.col-rpm { width: 84px; }
.col-tags { width: 160px; }
.collection-table .table-actions { width: 150px; }

/* Details and Edit were running together into one word. */
.table-actions { white-space: nowrap; }
/* AND SO WERE Add AND Details, on Add gear's rows at 390 px - QA read
   "AddDetails". The Collection's answer was an explicit `.action-divider`
   element, which works where one is added and does nothing where none is; two
   buttons appended next to each other have no whitespace text node between them,
   so there is nothing to collapse and nothing to see.

   A MARGIN, NOT A FLEX CONTAINER. `display: flex` on a <td> is the construction
   that took the Collection shelf's capture row out of its column grid on
   2026-09-25, and `.table-actions` IS a <td>. `button + button` changes no layout
   mode, so it is safe in the table and in the phone card alike. */
.table-actions > button + button,
.table-actions > a + button,
.table-actions > button + a { margin-left: 10px; }
.table-actions .action-divider {
  display: inline-block;
  padding: 0 8px;
  color: var(--muted-2);
}
.shelf-captures { padding: 10px 12px; display: grid; gap: 10px; font-size: .95em; }
.shelf-capture-side { display: grid; gap: 4px; }
.shelf-capture-side > .source-name {
  font-size: .7rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.shelf-capture-line {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  padding-left: 12px;
}

/* THE COLUMNS MENU AND THE FILTER (Jacob, 2 Oct; mockups "Columns menu" and
   "Advanced filter"). Both are quiet: paper, a hairline, the page's own type. */
.secondary-button.is-open {
  background: var(--teal-soft);
  box-shadow: inset 0 0 0 1px var(--teal);
}
.secondary-button.is-open:hover:not(:disabled) { background: var(--teal); }

/* A zero-height host so the menu floats over the table on a wide screen; on a
   phone (below) it stacks in the page instead of hanging off the right edge. */
.collection-popover-host { position: relative; height: 0; z-index: 30; }
.collection-popover {
  position: absolute;
  top: -8px;
  right: 16px;
  width: 340px;
  max-width: calc(100vw - 32px);
  max-height: min(72vh, 680px);
  overflow: auto;
  box-sizing: border-box;
  padding: 16px;
  display: grid;
  gap: 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper);
  box-shadow: 0 12px 32px rgba(13, 23, 29, .18);
}
.collection-popover[hidden], .collection-filter-panel[hidden], .filter-chips[hidden] { display: none; }
.popover-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.popover-head h3 { margin: 0; font-size: .95rem; }
.popover-head .text-button { padding: 0; font-size: .85rem; font-weight: 600; }
.popover-hint { margin: 0; color: var(--muted); font-size: .85rem; }
.column-list { display: grid; gap: 14px; }
.column-group { display: grid; gap: 2px; }
.column-group-name {
  padding-bottom: 4px;
  color: var(--muted-2);
  font: 800 .66rem/1.35 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.column-row {
  display: flex;
  align-items: center;
  gap: 2px;
  min-height: 36px;
  padding: 0 6px 0 0;
  border-radius: var(--radius);
}
.column-row.is-on { background: var(--soft); }
.column-row.is-dragging { background: var(--teal-soft); box-shadow: 0 0 0 1px var(--teal); }
/* The grip is a button so the keyboard can reach it, drawn as two dots of
   type. `touch-action: none` is what lets a finger drag it instead of
   scrolling the menu; an unticked column keeps the space and shows nothing. */
.column-grip, .column-grip:hover:not(:disabled) {
  width: 26px;
  height: 34px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--muted-2);
  font-size: .8rem;
  letter-spacing: -2px;
  cursor: grab;
  touch-action: none;
}
.column-grip:hover:not(:disabled) { color: var(--teal); }
.column-grip:disabled { visibility: hidden; }
.column-row.is-dragging .column-grip { cursor: grabbing; }
.column-choice {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-height: 34px;
  font-size: .9rem;
  cursor: pointer;
}
.column-choice input { width: 16px; height: 16px; padding: 0; accent-color: var(--teal); }

.collection-filter-panel {
  display: grid;
  gap: 10px;
  margin: 0 0 12px;
  padding: 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper);
}
.filter-rows { display: grid; gap: 10px; }
.filter-row {
  display: grid;
  grid-template-columns: minmax(150px, 260px) minmax(130px, 200px) minmax(0, 1fr) 44px;
  gap: 10px;
  align-items: center;
}
.filter-row select, .filter-row input { min-width: 0; }
.filter-values { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.filter-values .filter-value { width: 160px; }
.filter-and, .filter-unit { color: var(--muted); font-size: .85rem; }
.filter-unit { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .78rem; }
.filter-remove, .filter-remove:hover:not(:disabled) {
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--muted);
  font-size: 1.1rem;
  font-weight: 400;
}
.filter-remove:hover:not(:disabled) { border-color: var(--red); color: var(--red); }
.filter-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  padding-top: 4px;
}
.filter-chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 12px; }
.filter-chip-list { display: contents; }
.filter-chips-label {
  color: var(--muted-2);
  font: 800 .66rem/1.35 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 0 6px 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--soft);
  font-size: .85rem;
}
.filter-chip-remove, .filter-chip-remove:hover:not(:disabled) {
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1;
}
.filter-chip-remove:hover:not(:disabled) { color: var(--red); }

@media (max-width: 700px) {
  /* The old table was twenty columns forced to 1320px inside a 324px window -
     four screens of sideways dragging with the artist scrolling out of sight.
     Fewer columns per level is most of the fix and the pinned minimum is gone,
     so what is left is the natural width of five columns of real words.

     That still comes out wider than a phone, and this narrows it rather than
     pretending otherwise: tighter cells, a smaller thumbnail, and headings that
     stop paying for letter-spacing. Some sideways scrolling inside the table
     remains, which is ordinary for a table on a phone - and the gallery, with
     its covers, is the view that actually suits one. */
  .collection-table { font-size: .78rem; }
  .collection-table th, .collection-table td { padding: 7px 6px; }
  .collection-table th { letter-spacing: 0; font-size: .68rem; }
  .shelf-thumb { width: 30px; height: 30px; }
  .shelf-name-inner { gap: 3px 7px; }
  .shelf-inner { font-size: .76rem; }
  .shelf-children > td { padding-left: 14px !important; }
  .shelf-toggle-cell { width: 28px; }
  .shelf-disclosure { width: 20px; height: 20px; }
  /* Stacked: the Columns menu sits in the page above the table rather than
     over it, and the filter's rows become a field, its remove button, then the
     comparison and the values each on a line of their own. */
  .collection-popover-host { height: auto; margin-bottom: 12px; }
  .collection-popover { position: static; width: auto; max-width: none; max-height: none; }
  .filter-row {
    grid-template-columns: minmax(0, 1fr) 44px;
    grid-template-areas: "field remove" "op op" "values values";
  }
  .filter-field { grid-area: field; }
  .filter-op { grid-area: op; }
  .filter-values { grid-area: values; }
  .filter-remove { grid-area: remove; }
  .filter-values .filter-value { flex: 1 1 120px; width: auto; }
  .filter-actions .primary-command, .filter-actions .secondary-button { flex: 1 1 auto; }
}

/* Deleting is offered where the thing is, and looks like what it is: the
   word in the warning colour, not a button competing with the ones that
   make things. */
.danger-text { color: var(--red); }
.danger-text:hover:not(:disabled) { color: var(--red); text-decoration: underline; }
.shelf-event-actions { margin-top: 8px; display: flex; align-items: flex-start; gap: 10px; }
/* Delete sits at the far end of the row, away from Edit (area 3 finding 6). */
.shelf-event-actions .shelf-event-delete { margin-left: auto; }
.photo-caption .danger-text { justify-self: start; font-size: .76rem; }

/* "MEASUREMENTS OVER TIME" (area 3 finding 1). One play's own dl, reusing
   `.detail-grid.compact` for the shape the rest of the record page already
   uses, laid out tighter for a row inside a list rather than a page section.
   The score's own row sits last and is visually the same weight as any other
   measurement - a number among numbers, not a headline. */
.shelf-measurements-grid {
  margin: 6px 0 0;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}
.shelf-measurements-grid dt { font-size: .68rem; }
.shelf-measurements-grid dd { font-size: .86rem; }
.shelf-measurement-delta { display: block; font-weight: 400; }
.shelf-score-row { margin-top: 4px; grid-template-columns: minmax(140px, 1fr); }

/* THE KEPT AUDIO ROW, INSIDE A CAPTURE.

   All of the layout for `.stored-row` was scoped to `.copy-stored` - the old
   "Kept audio" section - so the same row drawn inside a capture inherited none
   of it and ran together as one line: the file name, its size, its rate, its
   depth, its length and the report link with nothing between them. Shared here
   rather than duplicated, because two spellings of one row is two rows as far
   as anybody reading both is concerned. */
.shelf-event .stored-row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  gap: 4px 12px;
  align-items: center;
  padding: 8px 0 0;
  cursor: pointer;
}
.shelf-event .stored-cell { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.shelf-event .stored-row .source-name {
  font: 700 .8rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.shelf-event .stored-row .source-detail {
  font: 400 .66rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .04em;
}
/* The report link is a sibling of the row, not part of it, and was reading as
   the end of the same sentence. */
.shelf-event > .text-button { margin-top: 6px; }
.shelf-event-notes {
  margin: 6px 0 0;
  padding-left: 10px;
  border-left: 2px solid var(--line-strong);
  color: var(--body-text);
  font-size: .86rem;
}

/* Correcting a capture. A form where the row was, rather than a dialog: what is
   being corrected is right there and should not be covered up by the thing
   correcting it. */
.capture-editor {
  display: grid;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--line-strong);
  background: var(--soft);
}
.capture-editor .field-label { display: grid; gap: 4px; font-size: .78rem; }
.capture-editor-played { display: flex; flex-wrap: wrap; gap: 8px; }
.capture-editor-played input { width: auto; flex: 1 1 9rem; }
.capture-editor input, .capture-editor textarea {
  width: 100%;
  font: inherit;
}
.capture-editor-chain {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 8px 12px;
  border: 1px solid var(--line);
  padding: 10px 12px;
  margin: 0;
}
.capture-editor-chain legend {
  font-size: .7rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 6px;
}
.capture-editor-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
@media (max-width: 700px) {
  .capture-editor-chain { grid-template-columns: 1fr; }
  .capture-editor-actions { flex-direction: column; align-items: stretch; }
}

/* IMPORTING A COLLECTION THAT ALREADY EXISTS.
   Three steps in one dialog. The mapping screen is a list and not a grid on
   purpose: eighteen fields against a column list is a two-column reading task,
   and on a phone a grid of selects is unusable. */
/* `.copy-dialog` sets `padding: 0` because `.copy-form` inside it supplies its
   own. This dialog has no form, so it has to say both - and say how tall it may
   get, because eighteen mapped fields are taller than a laptop and a dialog
   that cannot scroll is a dialog whose Import button cannot be reached. */
.import-dialog {
  width: min(720px, calc(100% - 28px));
  max-height: min(86vh, 900px);
  overflow-y: auto;
  padding: 30px;
}
.import-step > h3 { margin: 0 0 0.35rem; font-size: 1rem; }
.import-mapping { display: flex; flex-direction: column; gap: 0.4rem; margin: 0.6rem 0 0.9rem; }
.import-map-row {
  display: grid; grid-template-columns: minmax(8rem, 12rem) 1fr; gap: 0.75rem;
  align-items: center; padding: 0.35rem 0.5rem; border-radius: 6px;
  background: rgba(255, 255, 255, 0.03);
}
.import-map-field { font-size: 0.82rem; letter-spacing: 0.01em; }
.import-required,
.import-suggested { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.65; }
.import-suggested { color: var(--teal-on-dark); opacity: 0.8; }
.import-map-select { width: 100%; min-height: 2.2rem; }
.import-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: flex-end; margin-top: 0.75rem; }
.import-figures { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 0.5rem 0 0.75rem; }
.import-figure {
  display: flex; flex-direction: column; gap: 0.15rem; padding: 0.55rem 0.8rem;
  border-radius: 8px; background: rgba(255, 255, 255, 0.04); min-width: 8.5rem;
}
.import-figure strong { font-size: 1.5rem; line-height: 1.1; }
.import-figure span { font-size: 0.78rem; opacity: 0.8; }
.import-sample { list-style: none; margin: 0.35rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.import-sample li { display: flex; flex-direction: column; gap: 0.1rem; font-size: 0.85rem; }
.import-plan .panel-status { margin: 0.3rem 0; }

@media (max-width: 640px) {
  .import-map-row { grid-template-columns: 1fr; gap: 0.25rem; }
}

/* The sheets in a workbook, as a column of choices rather than a <select>.
   There are rarely more than four, they are the only thing on the step, and a
   name like `Settings` beside `Collection` is a decision worth reading rather
   than scrolling past in a dropdown. */
.import-sheets { display: flex; flex-direction: column; gap: 0.4rem; margin: 0.6rem 0 0.9rem; }
.import-sheet { text-align: left; justify-content: flex-start; }

/* The one piece of advice in the importer that is about the SPREADSHEET rather
   than about this screen, so it is set apart from the instructions around it. */
.import-advice {
  margin: 0.9rem 0 0.2rem;
  padding: 0.75rem 0.9rem;
  border-radius: 8px;
  border-left: 3px solid var(--teal);
  background: rgba(255, 255, 255, 0.04);
}
.import-advice h4 { margin: 0 0 0.35rem; font-size: 0.9rem; }
.import-advice p { margin: 0 0 0.45rem; font-size: 0.85rem; line-height: 1.45; }
.import-advice p:last-child { margin-bottom: 0; }
.import-id-note { border-left: 3px solid rgba(255, 255, 255, 0.18); padding-left: 0.65rem; }

/* A row the importer thinks is a record you already have, corrected. Unticked
   by default: ignoring the block costs an extra copy, which is visible and one
   click to delete, and ticking it wrong leaves a record missing. */
.import-corrections { margin: 0.75rem 0; padding: 0.7rem 0.85rem; border-radius: 8px;
  border-left: 3px solid var(--teal); background: rgba(255, 255, 255, 0.04); }
.import-corrections h4 { margin: 0 0 0.25rem; font-size: 0.9rem; }
/* The "all of them" escape, for a file that was pasted onto itself: one action
   rather than eighty ticks. Separated from the rows above it so it does not
   read as another row. */
.import-correction-all { margin-top: 0.5rem; padding-top: 0.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08); }
.import-correction {
  display: grid; grid-template-columns: 22px 1fr; gap: 0.5rem; align-items: start;
  padding: 0.4rem 0; border-top: 1px solid rgba(255, 255, 255, 0.07);
}
.import-correction input { margin-top: 0.2rem; min-width: 18px; min-height: 18px; }
.import-correction-text { display: flex; flex-direction: column; gap: 0.1rem; font-size: 0.85rem; }

/* MEASURE, OR YOUR OWN SETUP: the sides are switched by a class on the view
   rather than by writing `hidden` onto the Bench's children - four of them
   are hidden for their own reasons, and clearing the attribute to come back
   would have shown all four at once. `#bench-frame` (`shell/frame.js`'s
   strip and tabs, Part B2) is exempted the same way `.bench-setup-tools` is:
   it belongs to neither side, and shows on both. */
.bench-setup-tools { display: none; }
#bench-view.is-setup > *:not(#bench-frame):not(.bench-setup-tools) { display: none; }
/* Room between the Bench's tabs and whatever side is open under them, so a
   page's own heading does not sit against the tab line. */
#bench-frame { margin-bottom: clamp(18px, 3vw, 32px); }
/* The gear side is a column now - the four tools, then the shelf of rigs - so
   the grid moved onto the cards rather than sitting on their container. */
#bench-view.is-setup .bench-setup-tools { display: grid; gap: 28px; }
/* ONE RIG, IN FULL. The rig page is the gear side showing one rig, so it hides
   the rest of that side rather than being a new area - `architecture.md` warns
   against adding areas, and a rig is gear.

   By a CLASS, like everything else on this view: `bench/on-the-bench.js` explains
   why at length, and the short of it is that clearing `hidden` off these children
   would show four panels that hid themselves for their own reasons. */
#bench-view.is-rig-page .bench-setup-tools > *:not(#rig-page) { display: none; }
/* THE CATALOGUE AND A MODEL, each the gear side showing one thing - the same
   mechanism and the same reason as the rig page above. §3 replaces a DIALOG with
   this: the modal had a scrolling list inside a scrolling box, so browsing 235
   models meant two scroll bars and neither of them was the page. */
#bench-view.is-catalogue-page .bench-setup-tools > *:not(#catalogue-page) { display: none; }
#bench-view.is-model-page .bench-setup-tools > *:not(#model-page) { display: none; }
#catalogue-page[hidden], #model-page[hidden] { display: none; }
.catalogue-page, .model-page { display: grid; gap: 16px; }
.catalogue-page-search input {
  width: 100%;
  max-width: 28rem;
}
.catalogue-page-missing { justify-self: start; }
.catalogue-cell-model { font-weight: 700; }
.catalogue-cell-maker { color: var(--muted); }
/* Figures line up so two can be compared down a column, which is most of why a
   table is the right shape for a catalogue. */
.catalogue-cell-figure { font-variant-numeric: tabular-nums; white-space: nowrap; }
.catalogue-cell-actions { white-space: nowrap; }

/* ONE MODEL. Every specification with a link to its source. */
.model-page-actions { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
.model-page-yours {
  display: grid;
  gap: 6px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  background: var(--soft);
  justify-self: start;
  min-width: min(100%, 20rem);
}
.model-page-yours[hidden] { display: none; }
.model-page-specs { display: grid; gap: 18px; }
.model-record { display: grid; gap: 8px; }
.model-record-head { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.model-record-file {
  font: 700 .68rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  color: var(--muted);
}
.model-record-note { margin: 0; color: var(--muted); font-size: .82rem; }
.model-spec-list { display: grid; gap: 2px; }
/* The name in a fixed column and the value beside it, so a page of thirty
   specifications reads as a list of facts rather than as prose. */
.model-spec {
  display: grid;
  grid-template-columns: minmax(9rem, 14rem) minmax(0, 1fr);
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}
.model-spec-name {
  font: 700 .7rem/1.3 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
.model-spec-body { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.model-spec-value { font-weight: 600; font-variant-numeric: tabular-nums; }
/* A fact we went and looked for and the maker does not state. Drawn quietly and
   said plainly - it is a finding, not a blank. */
.model-spec-absent { color: var(--muted); font-style: italic; }
.model-spec-whose { font-size: .78rem; color: var(--muted); }
/* Anything not the manufacturer's is set apart, never drawn alike: a third
   party's number in the same type as one from the manual is a number nobody
   chose wearing a citation, and a catalogue looks authoritative by
   construction. */
.model-spec-whose.is-compiled {
  color: var(--red);
  border: 1px solid currentColor;
  padding: 0 6px;
  border-radius: 2px;
}
.model-spec-checked { font-size: .74rem; color: var(--muted-2, var(--muted)); }
.model-spec-note { margin: 2px 0 0; flex-basis: 100%; color: var(--muted); font-size: .8rem; }
.model-source-line { margin: 0; color: var(--muted); font-size: .8rem; }
/* Set apart, and only ever shown to an account `is_grading_lab_admin` answers
   true for - see `gear/model-page.js`'s `checkAdmin`. */
.model-admin-notes {
  display: grid; gap: 4px; margin-top: 8px; padding: 10px 12px;
  border: 1px dashed var(--line); border-radius: 4px;
}
.model-links { display: flex; gap: 12px; flex-wrap: wrap; }

@media (max-width: 700px) {
  /* The name above the value, because 9rem of label beside a value leaves no
     room for the value on a phone. */
  .model-spec { grid-template-columns: 1fr; gap: 2px; }
}

#rig-page[hidden] { display: none; }
.rig-page { display: grid; gap: 18px; }
.rig-page-back { justify-self: start; }
.rig-page-head { display: grid; gap: 4px; }
.rig-page-head h2 { margin: 0; font-size: 1.15rem; }
/* Rename sits under the name and becomes the field in place; a refusal is said
   beside the field it is about. */
.rig-rename-start { justify-self: start; font-size: .8rem; }
form.rig-rename { display: flex; flex-wrap: wrap; align-items: end; gap: 8px; }
form.rig-rename .rig-edit-field { flex: 1 1 14rem; min-width: 0; }
form.rig-rename input { width: 100%; box-sizing: border-box; }
.rig-rename-refusal { flex-basis: 100%; margin: 0; color: var(--danger-text); font-size: .86rem; }
.rig-rename-refusal:empty { display: none; }
.rig-page-state {
  margin: 0;
  font: 700 .7rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}
.rig-page-note { margin: 0; color: var(--muted); font-size: .86rem; }
.rig-page-note:empty { display: none; }
/* The chain leads and the calibration sits beside it, because the chain is what
   the page is about and the reading is about the chain. One column on a phone. */
.rig-page-body {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
.rig-chain { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
/* One step per row, each naming what it is. No controls on a step - that was the
   "Swap" Jacob rejected, and offering it on a draft would teach a gesture the
   next version refuses. */
.rig-chain-step {
  display: grid;
  gap: 2px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: var(--paper);
}
.rig-chain-role {
  font: 700 .64rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}
.rig-chain-name { font-weight: 700; }
.rig-chain-settings { color: var(--muted); font-size: .8rem; }
/* A cable is the link between two steps, not a step (7 Oct, Jacob): smaller,
   muted, with a line down the left and an arrow, and no box of its own. */
.rig-chain-link {
  display: grid;
  gap: 2px;
  margin-left: 14px;
  padding: 0 0 0 12px;
  border-left: 2px dashed var(--line-strong);
  color: var(--muted);
  font-size: .82rem;
  overflow-wrap: anywhere;
}
.rig-chain-link-text::before { content: "\2193\00a0"; }
.rig-page-aside { display: grid; gap: 12px; }
.rig-page-calibration {
  display: grid;
  gap: 6px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  background: var(--soft);
}
.rig-page-aside-title {
  margin: 0;
  font: 800 .66rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.rig-page-aside-line { margin: 0; font-size: .86rem; }
.rig-page-empty { margin: 0; color: var(--muted); }
.rig-page-actions { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
/* A control the database has locked, drawn as locked. Its title carries the
   sentence 029 gave, so hovering says WHY rather than leaving somebody to guess
   that the button is broken. */
.rig-page-actions button:disabled { opacity: .45; cursor: not-allowed; }
.rig-page-editor[hidden] { display: none; }
.rig-edit-form {
  display: grid;
  gap: 10px;
  padding: 14px 16px;
  border: 1px solid var(--line-strong);
  background: var(--soft);
}
/* What this form is about to do, said before it is done: forking and replacing
   look identical on screen and are not the same act. */
.rig-edit-what { margin: 0; color: var(--muted); font-size: .86rem; }
/* Under the rig's buttons: which of the two ways forward is which (Jacob,
   28 Sep). A full row of its own in the flex line above it. */
.rig-actions-help { flex: 1 0 100%; margin: 0; color: var(--muted); font-size: .84rem; max-width: 72ch; }
.rig-edit-field { display: grid; gap: 4px; }
.rig-edit-label {
  font: 700 .66rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}
/* A rig being made: the one-choice picker for a kind, with "+ Add gear" beside it. */
.rig-edit-pick { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.rig-edit-pick select { flex: 1 1 14rem; min-width: 0; }
/* A cable a rig can name sits in line between the two pieces it joins, as a
   lighter link row (7 Oct, Jacob), not in a group of its own. */
.rig-edit-link { margin-left: 14px; padding-left: 12px; border-left: 2px dashed var(--line-strong); }
.rig-edit-link .rig-edit-label { font-weight: 600; }
.rig-edit-joins { color: var(--muted); font-size: .76rem; overflow-wrap: anywhere; }
/* The free-form "Setting: Value" rows under a piece in the editor (7 Oct, Jacob). */
.rig-edit-settings { display: grid; gap: 6px; margin-top: -6px; }
.rig-edit-setting-rows { display: grid; gap: 6px; }
.rig-edit-setting { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.rig-edit-setting input { flex: 1 1 9rem; min-width: 0; }
.rig-edit-setting-add { justify-self: start; font-size: .82rem; }
.rig-edit-setting-remove { font-size: .82rem; }
.rig-edit-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
/* Why Save did nothing, said beside the button that was pressed. */
.rig-edit-status { margin: 0; flex: 1 1 16rem; min-width: 0; color: var(--danger-text); font-size: .86rem; }
.rig-edit-status:empty { display: none; }
.rig-edit-hint, .rig-chain-hint { margin: 0; color: var(--muted); font-size: .86rem; }
.rig-edit-hint:empty { display: none; }
.rig-edit-combo-line { display: flex; gap: 8px; align-items: center; font-size: .9rem; }
.rig-edit-combo:empty { display: none; }
.rig-restore { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-top: 8px; }
.rig-restore-line { margin: 0; flex: 1 1 20rem; font-size: .9rem; }
.rig-page-versions { display: grid; gap: 10px; }
/* `[hidden]` is a user-agent rule of the lowest possible priority, so the
   `display: grid` above wins over it without this - the same trap
   `#rig-page[hidden]` a few lines up already pays for. A new rig has no
   history to show a Versions panel about (UX re-review 1, finding 4). */
.rig-page-versions[hidden] { display: none; }
.rig-page-versions h3 {
  margin: 0;
  font: 800 .68rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
/* What changed from the version before, which is the question somebody actually
   has about a list of versions. */
.rig-version-changed { margin: 0; color: var(--muted); font-size: .82rem; }
/* A correction ("This was always so"): the version corrected says when and what,
   the one it was corrected onto says which it corrects. */
.rig-version-corrected, .rig-version-corrects { margin: 0; color: var(--muted); font-size: .82rem; font-style: italic; }
/* The choice every edit that makes a new version asks. */
.rig-edit-kind, #bench-view .source-chain-kind { display: grid; gap: 6px; border: 0; padding: 0; margin: 0; min-width: 0; }
.rig-edit-kind-choice, #bench-view .source-chain-kind-choice { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
.rig-edit-kind-hint { flex-basis: 100%; margin-left: 24px; color: var(--muted); font-size: .84rem; }
.rig-edit-kind-note { min-width: 0; max-width: 32rem; }
.rig-card-calibration { margin: 0; color: var(--muted); font-size: .84rem; }

@media (max-width: 700px) {
  .rig-page-body { grid-template-columns: 1fr; }
}

.setup-tool-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}
.setup-tool {
  display: grid;
  gap: 6px;
  padding: 22px;
  border: 1px solid var(--line);
  background: var(--paper);
  text-decoration: none;
  color: var(--body-text);
}
.setup-tool:hover { border-color: var(--line-strong); background: var(--soft); }
.setup-tool-name { font-weight: 800; }
.setup-tool-line { color: var(--muted); font-size: 14px; }

/* YOUR RIGS. Read, and the three things that are not editing: put one on the
   bench, retire one, bring one back. The editor stays on the capture side. */
/* THE PARTS BIN. One level down from the rig shelf, because a rig is a named
   assembly of these. Sorted by role in the order the capture form asks, so the
   shelf reads the way a chain does; the table itself is further down. */
.gear-shelf { display: grid; gap: 14px; }
.gear-shelf-add[hidden] { display: none; }
.gear-shelf-add { justify-self: start; }
/* The top row of Your gear: the way back to the Bench and the page's name on
   the left, "Add gear" on the right. It wraps at phone width rather than
   squeezing either. */
.gear-top { display: flex; align-items: center; justify-content: space-between; gap: 12px 16px; flex-wrap: wrap; }
.gear-top-title { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.gear-top-title h2 { margin: 0; font-size: 1.35rem; }
.gear-crumb-row { margin-bottom: -14px; }
.gear-crumb { color: var(--teal); font-weight: 700; text-decoration: none; }
.gear-crumb:hover { text-decoration: underline; }

/* THE CATALOGUE. A reference read while adding gear, so it is a dialog rather
   than a destination. */
.catalogue-dialog .copy-form { display: grid; gap: 12px; max-width: 46rem; }
.catalogue-categories { display: flex; flex-wrap: wrap; gap: 8px; }
.catalogue-categories .is-on { border-color: var(--teal); color: var(--teal); }
.catalogue-results {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 8px;
  max-height: 22rem; overflow: auto;
}
.catalogue-row { padding: 10px 12px; border: 1px solid var(--line); background: var(--paper); }
.catalogue-row-head { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
.catalogue-row-title { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.catalogue-row-actions { margin-left: auto; }
.catalogue-kind {
  font: 700 .64rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
}
.catalogue-empty { padding: 14px 12px; color: var(--muted); }
.catalogue-figure { margin: 6px 0 0; display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; font-size: .86rem; }
.catalogue-figure-value { font-variant-numeric: tabular-nums; }
/* WHOSE FIGURE IT IS, never drawn alike. The maker's is quiet; anything
   compiled is set apart, because a third party's number in the same type as one
   from the manual is a number nobody chose wearing a citation. */
.catalogue-figure-whose { font-size: .78rem; color: var(--muted); }
.catalogue-figure-whose.is-compiled {
  color: var(--red); border: 1px solid currentColor; padding: 0 6px; border-radius: 2px;
}
.catalogue-links { margin: 4px 0 0; display: flex; gap: 10px; flex-wrap: wrap; }
.catalogue-add { display: grid; gap: 10px; border-top: 1px solid var(--line); padding-top: 12px; }
.catalogue-add[hidden] { display: none; }

/* A MODEL WE LOOKED UP, waiting on an answer. */
.gear-notices { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.gear-notices[hidden] { display: none; }
.gear-notice { padding: 14px 16px; border: 1px solid var(--teal); background: var(--teal-soft); display: grid; gap: 8px; }
.gear-notice-title { margin: 0; font-size: .95rem; }
.gear-notice-changes { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: .86rem; }
.gear-notice-changes li { display: flex; gap: 10px; flex-wrap: wrap; align-items: baseline; }
.gear-notice-field { font-weight: 700; min-width: 8rem; }
.gear-notice-checked { font-weight: 600; }
.gear-notice-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.gear-shelf[hidden] { display: none; }
/* THE PARTS BIN IS A TABLE (docs/briefs/gear-side-redesign.md, Jacob 26 Sep).

   It was cards grouped under role headings: one item per card, a name and two
   buttons, and about 90px of height each. Twelve pieces of gear was most of a
   screen and still answered nothing you would ask of a list - which of these is
   on a rig, which has been used, what the maker says about it. Those are
   COLUMNS, and a column is why a table exists.

   The chips replace the role HEADINGS. A heading per role costs a line of
   uppercase and a gap whether or not you care about that role; a Type column
   plus a chip says the same thing in less height AND lets somebody ask for one
   kind, which a heading cannot. */
.gear-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.gear-chips[hidden] { display: none; }
.gear-removed { margin: 4px 0 0; font-size: .84rem; }
.gear-removed[hidden] { display: none; }
.gear-table-scroll { overflow: auto; }
.gear-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .84rem;
  /* CONTENT-SIZED, unlike the Collection's table, and the difference is
     deliberate. That one is three nested tables that must agree on their
     columns, so its widths are pinned and `table-layout: fixed` makes them
     hold. This is ONE table, its columns come and go with the data, and a fixed
     layout over a column set that changes would need a width per column per
     combination - a rule per case, which is a rule per case to get wrong. */
  table-layout: auto;
}
.gear-table[hidden] { display: none; }
.gear-table th, .gear-table td {
  padding: 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.gear-table th {
  color: var(--muted);
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.gear-row.is-removed { opacity: .72; }
/* The model leads and the manufacturer sits under it: the model is what
   somebody scans a list for, and "Audio-Technica AT-VM95ML" scanned for the
   second word means reading past the first every time. */
/* The STACK is styled, not the cell. `display: flex` on a <td> takes it out of
   the table's column algorithm - see the Collection shelf, 2026-09-25 - so the
   cell stays a cell and a div inside it does the stacking. */
.gear-name-stack { display: flex; flex-direction: column; gap: 2px; }
.gear-cell-manufacturer { color: var(--muted); font-size: .78rem; }
/* A gear name that leads somewhere: only where the item came from the catalogue
   and so has a model page. It carries the weight the plain name has, plus the
   underline that says it goes somewhere - a name that navigated without looking
   like it does is a name people press by accident. */
.gear-cell-link {
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  font-weight: 700;
  color: inherit;
  text-align: left;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 2px;
  cursor: pointer;
}
.gear-cell-link:hover { color: var(--teal); }
.gear-cell-plays { font-variant-numeric: tabular-nums; }
/* Which rigs an item is on. Chips rather than a comma list because each one is
   a separate thing that will be a link to that rig's page in the next slice. */
.gear-rig-chip {
  display: inline-block;
  margin: 0 6px 2px 0;
  padding: 1px 7px;
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  font-size: .76rem;
  white-space: nowrap;
}
/* The open form is a row of the same table, spanning it. Under the row it
   edits, so the thing being renamed is still on screen while it is renamed. */
.gear-editor-row > td { background: var(--soft); border-bottom: 2px solid var(--line-strong); }
.gear-edit-form { display: grid; gap: 8px; }
.gear-edit-field { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.gear-edit-field input { flex: 1 1 8rem; min-width: 0; }
/* YOUR COPY of a piece of gear (migration 031): bought, serial, stylus fitted,
   which stylus. A `<details>` because all four are optional and usually empty,
   so a row must not grow four fields for somebody who came to fix a note. */
.gear-edit-copy > summary {
  cursor: pointer; color: var(--muted);
  font: 400 .72rem/1.4 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 0;
}
.gear-edit-copy > summary:hover { color: var(--teal-on-dark); }
/* Each field carries its own label, because four boxes in a row are four
   mysteries - the same reason the phone cards label every value. The label sits
   ABOVE its input so a narrow column wraps the pair together rather than
   stranding a label at the end of one line and its box at the start of the next. */
.gear-edit-label { display: grid; gap: 2px; flex: 1 1 9rem; min-width: 0; }
.gear-edit-label .field-label { font-size: .68rem; }
.gear-edit-copy-fields { align-items: start; }
.gear-edit-hint { color: var(--muted); font-size: .84rem; }

/* ON A PHONE, ONE CARD PER ROW - and this differs from the Collection table on
   purpose. That one accepts sideways scrolling because the GALLERY is the view
   that suits a phone and it is one tap away; the parts bin has no second view,
   so a phone is the only way somebody sees it and it has to work there.

   Each cell prints its column name beside its value, from the `data-label` that
   `gear/garage-shelf.js` puts on every cell as it builds it. That is why the
   label travels with the cell rather than living only in the heading: six
   unlabelled lines in a card are six mysteries, and a card layout that reads
   the heading row would be reading a row that is no longer next to it. */
@media (max-width: 700px) {
  .gear-table, .gear-table tbody, .gear-table tr, .gear-table td { display: block; }
  .gear-table thead { display: none; }
  .gear-table-scroll { overflow: visible; }
  .gear-row {
    border: 1px solid var(--line);
    background: var(--paper);
    padding: 10px 12px;
    margin-bottom: 8px;
  }
  .gear-table td { border-bottom: 0; padding: 2px 0; }
  /* The name is the card's title, so it keeps its size and loses its label. */
  .gear-cell-name { padding-bottom: 6px; }
  .gear-name-stack { gap: 1px; }
  .gear-table td[data-label]:not(.gear-cell-name)::before {
    content: attr(data-label);
    display: inline-block;
    min-width: 6.5rem;
    /* THE GAP HAS TO BE PADDING, NOT A TRAILING SPACE. This was
       `content: attr(data-label) " "`, and a trailing space at the end of an
       inline-block is trimmed - so the only thing separating the label from the
       value was `min-width` being wider than the label. It is, for the parts
       bin's short heads (Type, On rig, Plays), and it is not for Add gear's:
       QA read "MANUFACTURERAudio-Technica" and "TRACKING FORCE1.8-2.2 g" at
       390 px. Padding survives a label that overflows its own minimum. */
    padding-right: 10px;
    color: var(--muted);
    font-size: .72rem;
    letter-spacing: .06em;
    text-transform: uppercase;
  }
  /* A cell that says nothing prints no label. `gear/garage-shelf.js` marks it
     as it builds it - asked of the cell's text, which is the honest question,
     rather than left to a selector to infer from an empty <span>. */
  .gear-table td.is-blank { display: none; }
  .gear-cell-actions { padding-top: 8px !important; }
  .gear-editor-row > td { border: 1px solid var(--line-strong); padding: 10px 12px; margin-bottom: 8px; }
  .gear-edit-field input { flex: 1 1 100%; }
}

.rig-shelf { display: grid; gap: 14px; }
.rig-shelf[hidden] { display: none; }
.rig-shelf-heading { display: grid; gap: 4px; }
.rig-shelf-heading h2 { margin: 0; font-size: 1.05rem; }
.rig-shelf-note { margin: 0; color: var(--muted); font-size: .84rem; }
.rig-shelf-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
/* THE RIG BOX, TIGHTENED (Jacob, 8 Oct: "It's taller than it needs to be"). Less
   padding and gap, the actions on the title's row, and the chain as a wrapped
   row of chips. Everything the card showed is still shown. `min-width: 0` on the
   card and its rows lets a long model name wrap inside the box at 280px rather
   than push the page sideways. */
.rig-card {
  display: grid;
  gap: 4px;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: var(--paper);
}
.rig-card.is-current { border-color: var(--teal); }
/* The default is a different claim from "on the bench" and is badged
   differently: one is where this browser left off, the other is what the
   account says to start from, on any machine. */
.rig-badge.is-default { background: var(--teal); color: var(--on-fill); }
.rig-card.is-retired { opacity: .72; }
.rig-card-head { display: flex; gap: 2px 12px; align-items: baseline; flex-wrap: wrap; justify-content: space-between; }
.rig-card-title { display: flex; gap: 4px 8px; align-items: baseline; flex-wrap: wrap; min-width: 0; }
.rig-card-actions { margin-left: auto; display: flex; gap: 2px 12px; flex-wrap: wrap; justify-content: flex-end; }
.rig-card-actions .text-button { padding: 2px 6px; font-size: .88rem; }
.rig-card-notes { margin: 0; color: var(--muted); font-size: .86rem; }
/* The chain: chips in a wrapped row with the arrows between them. The arrow's own
   text carries the spaces, so the card still reads "A -> B" to anything that reads
   its text; a cable is one of the stages, drawn lighter and in italics. */
.rig-card-chain { margin: 0; color: var(--muted); font-size: .86rem; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 2px; min-width: 0; }
.rig-chip { padding: 0 6px; border: 1px solid var(--line); border-radius: 2px; overflow-wrap: anywhere; min-width: 0; }
.rig-chip.is-cable { border-style: dashed; font-style: italic; }
.rig-chain-arrow { color: var(--muted-2); }
.rig-card-more { justify-self: start; }
.rig-version-number {
  font: 800 .68rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .08em;
  color: var(--muted-2);
}
.rig-badge {
  font: 800 .6rem/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 3px 7px;
  background: var(--teal-soft);
  color: var(--teal-on-dark);
}
.rig-badge.is-quiet { background: transparent; color: var(--muted-2); box-shadow: inset 0 0 0 1px var(--line); }
.rig-version-list {
  list-style: none;
  margin: 4px 0 0;
  padding: 0 0 0 14px;
  display: grid;
  gap: 10px;
  border-left: 3px solid var(--line-strong);
}
.rig-version-head { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.rig-version-when { color: var(--muted-2); font-size: .78rem; }
.rig-version-chain, .rig-version-notes { margin: 0; color: var(--muted); font-size: .82rem; }

/* Signed out there is no gear to add or edit (Jacob, 29 Sep): the shelves, the
   rig page, the catalogue and the Source row say so with one line and the
   sign-in button, from gear/carry-over.js. */
.gear-signin, .source-signin { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0; }
.gear-signin-slot { margin: 6px 0; }

/* Tag entry, shared by the Bench, the copy page's play editor and the photo
   page (`capture/tag-input.js`). Chips first, the box after them, and the whole
   thing takes focus as one field. */
.tag-input {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  min-width: 0; text-transform: none; letter-spacing: 0; font-weight: 400;
}
.tag-input:focus-within { outline: 2px solid var(--teal); outline-offset: 2px; }
.tag-input-chips { display: contents; }
.tag-input-chip {
  display: inline-flex; align-items: baseline; gap: 3px;
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 1px 3px 1px 7px; font-size: .78rem; max-width: 100%;
}
.tag-input-remove {
  background: none; border: 0; padding: 0 3px; cursor: pointer;
  color: var(--muted); font: inherit; line-height: 1;
}
.tag-input-remove:hover:not(:disabled) { background: none; border: 0; color: var(--red); }
.tag-input .tag-input-field {
  flex: 1 1 7rem; width: auto; min-width: 6rem; padding: 3px 2px;
  border: 0; background: transparent; font: inherit; color: inherit;
}
.tag-input .tag-input-field:focus-visible { outline: none; }
.tag-input-note { flex-basis: 100%; color: var(--muted); font-size: .72rem; }
.tag-input-note:empty { display: none; }

/* "Copy the details" beside a measuring error (app.js offerMeasuringDetails). */
.measure-error-help:not([hidden]) { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin: 4px 0 0; }
.measure-error-help span { color: var(--muted); font-size: .85rem; }

/* "The same copy as before, or another one?" in the Keep panel: radios, one per
   owned copy of the record and "Another copy". Shown only when a copy is owned
   (source-id/ui.js). */
.intake-copy-question { border: 0; margin: 14px 0; padding: 0; min-width: 0; }
.intake-copy-question legend { padding: 0; margin-bottom: 6px; font-weight: 600; }
.intake-copy-choices { display: grid; gap: 4px; }
.intake-copy-choice { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.intake-copy-choice input { margin: 0; }

/* "What is this playing on?" (gear/ask-gear.js): one small dialog, two fields
   and "More". It borrows the copy dialog's surface. */
.ask-gear { width: min(30rem, calc(100% - 28px)); }
.ask-gear .copy-form h2 { font-size: 1.4rem; }
.ask-gear-why { margin: 0; color: var(--muted); font-size: 14px; }
.ask-gear-fields { display: grid; gap: 12px; }
.ask-gear-more { margin-top: 2px; }
.ask-gear-more > .ask-gear-fields { margin-top: 10px; }
.ask-gear-status { min-height: 1.2em; margin: 0; }

/* The mobile notice (site-structure brief, App Build item 16): the same line
   and look as Set up's (calibration/calibrate.css), shown at the frame's narrow
   breakpoint (700 px) above Measure, and the sentence a hardware-only control
   says in its place when tapped there (app.js). Everything else stays exactly as
   on a computer. */
.mobile-notice { display: none; margin: .6rem 0 .8rem; padding: .6rem .8rem; border: 1px solid var(--line); border-radius: var(--radius); color: var(--body-text); font-size: 14px; line-height: 1.45; }
.mobile-notice a { color: var(--teal-on-dark); }
.needs-interface-note { margin: .4rem 0 0; font-size: 13px; color: var(--amber); }
@media (max-width: 700px) {
  .mobile-notice { display: block; }
}

/* THE MEASURE VIEW BEFORE AND AFTER A RECORDING IS CHOSEN (UX review 8,
   findings 1 and 8). app.js syncRecordingStage sets `data-recording-chosen` on
   the view while a file is on the bench or a play is restored. Until then the
   view shows the choosing only: "Which record is this?" waits for a recording,
   and "No recording yet? How to make one" goes once there is one. `!important`
   because source-id/ui.js clears the panel's own `hidden` every time it draws. */
#bench-view:not([data-recording-chosen]) [data-needs-recording],
#bench-view[data-recording-chosen] [data-before-recording] { display: none !important; }
/* The Measure heading, then one plain sentence under it at a readable width
   (UX review 8, finding 2); it sat in a narrow column to the right with the
   heading dropped to its bottom. The fingerprint line is fine print. */
.workbench > .section-heading { grid-template-columns: minmax(0, 1fr); gap: 10px; align-items: start; }
.workbench > .section-heading h2 { margin-top: 0; }
.section-help-block { max-width: 46rem; display: grid; gap: 6px; }
.section-help-block .section-help { color: var(--body-text, var(--muted)); font-size: 1.0625rem; line-height: 1.5; }
/* What the tool needs, said first and quietly (outside UX review, item 7). */
.section-help-block .section-needs { margin: 0; color: var(--muted); font-size: .9375rem; line-height: 1.45; }
/* Signed out only: what an account adds, above the source (item 8). */
.teaser-before { display: none; margin: 0 0 14px; max-width: 46rem; color: var(--muted); font-size: .875rem; line-height: 1.45; }
[data-signed-out-teaser] .teaser-before { display: block; }
.section-fine { margin: 0; color: var(--muted-2); font-size: .8125rem; line-height: 1.45; }

/* Before a recording the Source table is not a table: its head and its empty
   row are hidden above, so the box around what is left (the helper line, the
   saved recordings, the speed) goes too (UX review 8, findings 1 and 15). */
#bench-view:not([data-recording-chosen]) .source-table { border: 0; background: none; padding: 0; }
#bench-view:not([data-recording-chosen]) .source-foot { border-top: 0; padding-top: 0; margin-top: 0; }
#bench-view:not([data-recording-chosen]) .source-foot-spacer { display: none; }
/* The status line takes no room while it has nothing to say. */
#bench-view .source-commands .status:empty { display: none; }

/* "Check before you record": five short lines above the how-to fold, under the
   same before-a-recording-is-chosen rule. A plain block, not a fold. */
.check-before-recording { margin: 14px 0 6px; color: var(--muted); max-width: 640px; }
.check-before-recording h3 { margin: 0; font-size: .9rem; font-weight: 700; color: var(--body-text); }
.check-before-recording ul { margin: 6px 0 0; padding-left: 1.4em; font-size: .9rem; line-height: 1.55; }
.check-before-recording li + li { margin-top: 3px; }
.check-before-recording a { color: var(--teal-on-dark, var(--teal)); text-underline-offset: 2px; }
.how-to-record { margin: 14px 0; color: var(--muted); }
.how-to-record summary { cursor: pointer; font-weight: 700; font-size: .9rem; color: var(--teal-on-dark, var(--body-text)); }
.how-to-record ol { margin: 10px 0 0; padding-left: 1.4em; max-width: 640px; font-size: .9rem; line-height: 1.55; }
.how-to-record li + li { margin-top: 4px; }

/* "Every measurement": one closed fold for everything that was measured. */
.every-measurement { margin-top: 16px; }
.every-measurement > summary { cursor: pointer; font-weight: 800; padding: 6px 0; }
.every-measurement[open] > summary { margin-bottom: 8px; }

/* THE FOUNDING-MEMBERS LINE (account/plan.js draws it; account/plan-gates.js says
   where). One quiet sentence, never a pop-up, with its link in teal. The slots it
   is drawn into are empty and take no room until a Free account meets a limit. */
.plan-invite-slot:empty { display: none; }
.plan-invite { margin: 10px 0 0; color: var(--muted); font-size: 14px; line-height: 1.5; }
.plan-invite a, .plan-invite button {
  color: var(--teal);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.plan-invite a:hover, .plan-invite button:hover:not(:disabled) { color: var(--body-text); background: none; }
/* On the Bench the ground is dark, and the teal that reads on paper does not. */
#bench-view .plan-invite a, #bench-view .plan-invite button { color: var(--teal-on-dark); }

/* SIGNED OUT ON MEASURE: THE HEADLINE ONLY (account/teaser.js). The score, clicks per
   minute, surface noise and the verdict stay in full; the charts, the full
   measurements, the report buttons and the channel balance are there but faded
   and out of reach until there is an account. Faded, not removed: signing in
   lifts it without measuring again. */
.teaser-line { display: none; }
[data-signed-out-teaser] .teaser-line:not([hidden]) {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  margin: 18px 0;
  padding: 14px 18px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--teal);
  background: var(--teal-soft);
  color: var(--body-text);
  font-weight: 600;
}
[data-signed-out-teaser] .teaser-gated {
  opacity: .32;
  pointer-events: none;
  user-select: none;
  filter: grayscale(.4);
}

/* Connect Discogs (collection/discogs.js, account/view.js). Drawn only when
   config/discogs-connect.js is switched on. */
.import-sources { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.6rem 0 0.9rem; }
.import-discogs-row { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 0.85rem; padding: 0.2rem 0; }
.import-discogs-row input { margin-top: 0.2rem; min-width: 18px; min-height: 18px; }
.import-discogs-row .source-detail { display: block; opacity: 0.75; }
.discogs-notice { color: var(--teal-on-dark); }
.discogs-notice .text-button { padding: 0; border: 0; background: none; color: inherit; text-decoration: underline; cursor: pointer; }
.account-discogs-skip { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; margin: 0.25rem 0; }
.discogs-skip-choice { display: flex; align-items: flex-start; gap: 0.5rem; margin: 0.6rem 0; font-size: 0.9rem; }
.discogs-skip-choice input { margin-top: 0.2rem; min-width: 18px; min-height: 18px; }
#account-discogs[hidden] { display: none; }
/* "Also on this rig" under a rig's chain, and the "+ Add something else" rows in its editor (7 Oct, Jacob). */
.rig-chain-also { margin: 8px 0 0; color: var(--muted); font-size: .86rem; }
.rig-edit-extras { display: grid; gap: 10px; }
.rig-edit-extra-rows { display: grid; gap: 12px; }
.rig-edit-extra { display: grid; gap: 6px; padding-left: 12px; border-left: 2px solid var(--line-strong); }
.rig-edit-extra-head { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.rig-edit-extra-head input { flex: 2 1 12rem; min-width: 0; }
.rig-edit-extra-head select { flex: 1 1 14rem; min-width: 0; }
.rig-edit-extra-add, .rig-edit-extra-suggest { justify-self: start; }
.rig-edit-extra-suggest[hidden] { display: none; }
