/* app.css — the one stylesheet.
 *
 * Phone first. Everything below the 768px breakpoint is the default; the
 * breakpoint adds desktop, never the other way round. ADR-006.
 *
 * Rules that are acceptance criteria, not taste:
 *   - nothing overflows at 360px
 *   - no affordance appears only on hover
 *   - anything tappable is at least 44px tall
 */

/* Tokens ------------------------------------------------------------------ */

:root {
  /* Type. One scale, four steps. */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* The editorial half of the identity. Every family here ships with an
   * operating system: BUILD-SPEC §2 and briefs/M10 forbid an external font, and
   * a self-hosted one would be bytes on every page load for a wordmark. */
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, "Times New Roman", serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  /* Read at arm's length, in a workshop, on a phone. Nothing under 14px, and
   * the body sits at 17px rather than 16. briefs/M10. */
  --text-sm: 0.875rem;
  --text-base: 1.0625rem;
  --text-lg: 1.3125rem;
  --text-xl: 1.75rem;
  --text-2xl: clamp(2.25rem, 9vw, 3.5rem);
  --line: 1.55;

  /* Spacing. Multiples of 4px, named by use rather than size. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;

  /* Colour. Warm paper and near-black ink, one accent, one red for destructive
   * things. Every pair below has been measured rather than eyeballed:
   *   ink        15.8 : 1   ink-soft  7.8 : 1   ink-faint 4.8 : 1
   *   accent     10.2 : 1   danger    7.8 : 1   accent-ink on accent 11.2 : 1
   * against paper. `line-strong` carries every control border at 3.1 : 1, which
   * is what WCAG asks of a component boundary — the hairline is decoration and
   * is never the only thing marking a control. briefs/M10 acceptance 8. */
  --paper: #f6f4ef;
  --surface: #fffdf8;
  --ink: #191b17;
  --ink-soft: #4a4d45;
  --ink-faint: #6a6d64;
  --line-colour: #ddd8cd;
  --line-strong: #8d8a80;
  --accent: #14432f;
  --accent-ink: #ffffff;
  --danger: #8a2b1e;

  /* The lightbox and the sold watermark put ink on a dark ground rather than on
     paper, so they need their own pair. Stated here with everything else,
     because a colour set in a rule is a second palette starting. */
  --shroud: rgba(12, 13, 11, 0.92);
  --shroud-ink: #f2efe8;
  --shroud-control: rgba(255, 255, 255, 0.14);
  --shroud-control-lit: rgba(255, 255, 255, 0.28);
  --watermark-ground: rgba(25, 27, 23, 0.34);
  --watermark-ink: #ffffff;
  --watermark-shadow: rgba(0, 0, 0, 0.55);

  /* Set by the density on <body>, with a dense default so a component is never
     unstyled if a page forgets to say which it is. ADR-009 decision 5. */
  --pad: 0.75rem;
  --flow: 0.75rem;
  --cell-pad: 0.5rem;
  --title: 1.75rem;

  --radius: 6px;
  --tap: 44px;            /* minimum touch target, ADR-006 */
  --measure: 42rem;       /* readable line length */
  --page: 68rem;
}

/* Reset ------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--text-base);
  line-height: var(--line);
  color: var(--ink);
  background: var(--paper);
  /* At 360px nothing may scroll sideways except an explicitly scrollable table. */
  overflow-x: hidden;
}

/* The editorial half of the identity: headings and names are set in the display
 * serif, everything that is read as data stays in the interface face. */
h1, h2, h3 { line-height: 1.2; margin: 0 0 var(--space-3); font-weight: 600; }
h1 { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 500; letter-spacing: -0.01em; }
h2 { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 500; }
h3 { font-size: var(--text-base); }
p { margin: 0 0 var(--space-4); max-width: var(--measure); }

a { color: var(--accent); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Layout ------------------------------------------------------------------ */

.site-header {
  background: var(--surface);
  border-bottom: 1px solid var(--line-colour);
}

.site-header__bar {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.site-title {
  /* Tappable, so it is a full-size target like everything else in the header. */
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-left: auto;
  align-items: center;
}

/* Nav items are always visible and always full-size targets: no hover reveal. */
.site-nav a, .site-nav button {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--space-3);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--ink-soft);
  font-size: var(--text-sm);
}

.site-nav a[aria-current="page"] { color: var(--ink); background: var(--paper); }

.site-nav form { margin: 0; }

main {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--space-6) var(--space-4) var(--space-8);
}

.stack > * + * { margin-top: var(--space-4); }

.card {
  background: var(--surface);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
  padding: var(--space-4);
}

.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); font-size: var(--text-sm); }
.mono { font-family: var(--font-mono); }

/* Forms ------------------------------------------------------------------- */
/* Single column on a phone. Native inputs throughout, so the phone shows the
 * right keyboard and the right picker. */

form { margin: 0; }

.field { display: block; margin-bottom: var(--space-4); max-width: var(--measure); }

.field > label {
  display: block;
  margin-bottom: var(--space-1);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

input, select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  /* A control's own boundary, at 3:1 — a hairline is not enough to mark the
   * edge of something you are meant to type into. */
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}

/* 16px minimum, or iOS zooms the page on focus and the layout breaks. */
input, select, textarea { font-size: max(1rem, var(--text-base)); }

textarea { min-height: calc(var(--tap) * 2); resize: vertical; }

.button, button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Flex items swallow the whitespace between them, so a button with a label
   * and a trailing detail needs the gap put back explicitly. */
  gap: var(--space-2);
  min-height: var(--tap);
  padding: 0 var(--space-4);
  font: inherit;
  font-weight: 500;
  color: var(--accent-ink);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
}

.button--secondary, button.button--secondary {
  color: var(--ink);
  background: var(--surface);
  border-color: var(--line-strong);
}

.button--danger, button.button--danger {
  color: var(--danger);
  background: var(--surface);
  border-color: var(--danger);
}

/* Full width on a phone; natural width once there is room. */
.button, button { width: 100%; }
.button-row { display: flex; flex-direction: column; gap: var(--space-2); }

/* Messages ---------------------------------------------------------------- */

.flash {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line-colour);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
}

.flash--error { border-left-color: var(--danger); }

/* Tables ------------------------------------------------------------------ */
/* The one place sideways scrolling is allowed, and only inside the wrapper. */

.data-table__scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
th, td { padding: var(--space-2) var(--space-3); text-align: left; border-bottom: 1px solid var(--line-colour); }
th { font-weight: 600; color: var(--ink-soft); white-space: nowrap; }
td.number, th.number { text-align: right; font-family: var(--font-mono); }

/* Rows become cards on a phone: the priority columns only, stacked. */
.rows { list-style: none; margin: 0; padding: 0; }
.rows > li {
  background: var(--surface);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
  padding: var(--space-3);
}
.rows > li + li { margin-top: var(--space-2); }

/* The two presentations ---------------------------------------------------- */
/* One data model, two layouts, switched here and nowhere else. ADR-006. */

.desk-only { display: none; }
.phone-only { display: block; }

/* Filters, totals, panels -------------------------------------------------- */

.filters {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
}
.filters .field { margin-bottom: 0; max-width: none; }
.filters__foot { display: flex; flex-direction: column; gap: var(--space-2); }

.total {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-top: 1px solid var(--line-colour);
}
.total__label { color: var(--ink-soft); font-size: var(--text-sm); }
.total__value { margin-left: auto; font-variant-numeric: tabular-nums; }

/* A figure that opens the rows behind it is a control, so it is a control-sized
 * target — the plain figures beside it are text and stay as they are.
 * briefs/M11 acceptance 7, ADR-006. */
a.total__value, .rows > li > a, a.card-line__value {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}
.total--big .total__value { font-size: var(--text-lg); font-weight: 600; }
.total__note { flex-basis: 100%; text-align: right; }

.totals { background: var(--surface); border: 1px solid var(--line-colour); border-radius: var(--radius); padding: var(--space-4); }

.panels { display: flex; flex-direction: column; gap: var(--space-4); }

.pagination { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-4); }

/* A reversed row is struck through and still there. Append-only means the
 * mistake stays visible; only its effect on the total goes away. */
.reversed, .reversed .mono { text-decoration: line-through; color: var(--ink-faint); }

.chip--quiet {
  display: inline-block;
  padding: 0 var(--space-2);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
  font-size: var(--text-sm);
  color: var(--ink-soft);
  white-space: nowrap;
}
.chip--danger { border-color: var(--danger); color: var(--danger); }

.field__error { display: block; margin-top: var(--space-1); color: var(--danger); font-size: var(--text-sm); }

.row__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.row__actions form { flex: 1 1 auto; }

.row__line { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline; }
.row__value { margin-left: auto; font-variant-numeric: tabular-nums; }

/* The inline entry row. On a phone it is a stacked form; on a desk it becomes a
 * row of the grid, so eight costs go in without leaving the table. */
.entry { background: var(--surface); border: 1px solid var(--line-colour); border-radius: var(--radius); padding: var(--space-4); }
.entry h3 { margin-bottom: var(--space-3); }

/* The audit log ------------------------------------------------------------ */
/* What changed, and what it said before. Nothing here is coloured by what the
 * change did: a delete reads the same as an edit. BUILD-SPEC §1. */

.audit__head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
}
.audit__action { font-weight: 600; }
.audit__at { margin-left: auto; font-family: var(--font-mono); }

.changes { margin: var(--space-2) 0 0; }
.change {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  padding: var(--space-1) 0;
  border-top: 1px solid var(--line-colour);
}
.change dt { color: var(--ink-soft); font-size: var(--text-sm); flex: 0 0 100%; }
.change dd { margin: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline; }
.change__before { color: var(--ink-faint); text-decoration: line-through; }
.change__arrow { color: var(--ink-faint); }
.change__after { color: var(--ink); }

/* Sections of a record ----------------------------------------------------- */
/* Gone on 19 August 2026, with the tabs that never worked. A record is
   segmented by `.segments` — tabs on a desk, accordion on a phone, from one set
   of markup — which is ADR-009 decision 2 and lives at the end of this file.
   `.tabs` styled a nav that B8 removed and nothing had rendered since. */

/* The landing page -------------------------------------------------------- */
/* The only page an unauthenticated request reaches, and the only one with no
 * header: it is the mark, a sentence, and the way in. No vehicle data of any
 * kind reaches this page — see src/routes/public/landing.js. briefs/M10. */

.landing {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-8);
  max-width: 34rem;
  margin: 0 auto;
  padding: var(--space-8) var(--space-4);
}

.mark { display: block; width: 3.5rem; height: 3.5rem; margin-bottom: var(--space-6); }

.wordmark {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin: 0;
  color: var(--ink);
}

/* A rule under the wordmark, in the accent, at the weight of a printed one. */
.wordmark + .rule {
  width: 4rem;
  height: 2px;
  margin: var(--space-4) 0 var(--space-6);
  background: var(--accent);
  border: 0;
}

.landing__statement {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  color: var(--ink-soft);
  max-width: 30rem;
}

/* Under the form, not marooned at the bottom of the viewport: the page is one
 * centred block, so it reads the same on a tall phone and a short one. */
.landing__footer {
  margin: 0;
  color: var(--ink-faint);
  font-size: var(--text-sm);
}

/* The collection ---------------------------------------------------------- */
/* One column on a phone, per briefs/M09 acceptance 9. */

.tiles { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }

.tile__link {
  display: block;
  background: var(--surface);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
}

.tile__image {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  background: var(--paper);
}

/* A car with no photograph the visitor may see still gets a tile the same size,
 * so the grid does not jump about. */
.tile__image--none { border-bottom: 1px solid var(--line-colour); }

.tile__body { display: block; padding: var(--space-3) var(--space-4) var(--space-4); }
.tile__name { display: block; font-family: var(--font-display); font-size: var(--text-lg); }
.tile__line { display: block; color: var(--ink-soft); font-size: var(--text-sm); }

/* The visitor photo strip -------------------------------------------------- */
/* Swiped sideways on a phone, one photograph at a time, with no script. The
 * container is explicitly scrollable, which is the one place sideways movement
 * is allowed. Named apart from the admin `.gallery`, which is a photo manager
 * and not a strip. briefs/M09 acceptance 9. */

.photo-strip {
  display: flex;
  gap: var(--space-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--space-2);
}

.photo-strip__item {
  margin: 0;
  flex: 0 0 100%;
  scroll-snap-align: center;
}

.photo-strip__item img {
  display: block;
  width: 100%;
  border-radius: var(--radius);
  background: var(--surface);
}

.photo-strip__item figcaption { margin-top: var(--space-2); }

/* The admin photo manager. One photograph per row, each with its controls —
 * it is a list of things to act on, not a gallery to look through. */
.gallery { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.gallery__item + .gallery__item { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--line-colour); }
.gallery__item img { display: block; width: 100%; border-radius: var(--radius); }
.gallery__caption { margin-top: var(--space-3); }

.lede { font-family: var(--font-display); font-size: var(--text-lg); color: var(--ink-soft); }

/* The one figure a visitor sees. Set like a price in a catalogue, not like a
 * total in a ledger — no rule above it, no label beside it. */
.price {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  margin-bottom: var(--space-2);
}

.tile__price {
  display: block;
  margin-top: var(--space-1);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.prose p { max-width: var(--measure); }

/* Specifications ---------------------------------------------------------- */

.specs { margin: 0; display: grid; gap: 0; }
.spec {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
  padding: var(--space-2) 0;
  border-top: 1px solid var(--line-colour);
}
.spec dt { color: var(--ink-soft); font-size: var(--text-sm); }
.spec dd { margin: 0 0 0 auto; }

/* Switches ---------------------------------------------------------------- */
/* The whole row is the target, so nothing depends on hitting a 16px box. */

.switches { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.switches > li + li { border-top: 1px solid var(--line-colour); }

.switch {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap);
  cursor: pointer;
}
/* The box is 24px; the row that toggles it is 44px, because the label wraps the
 * input and the whole row is therefore the target. ADR-006. */
.switch input[type="checkbox"] {
  width: 1.5rem;
  min-height: 1.5rem;
  height: 1.5rem;
  flex: 0 0 auto;
  accent-color: var(--accent);
}

/* Desktop ----------------------------------------------------------------- */

@media (min-width: 768px) {
  .button, button { width: auto; }
  .actions { flex-direction: row; align-items: center; }

  main { padding: var(--space-8) var(--space-6); }

  .form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 var(--space-4);
    max-width: var(--page);
  }
  .field--wide { grid-column: 1 / -1; }

  .desk-only { display: block; }
  .phone-only { display: none; }

  .filters { flex-direction: row; flex-wrap: wrap; align-items: flex-end; }
  .filters .field { flex: 1 1 10rem; }
  .filters__foot { flex-direction: row; }

  .panels { flex-direction: row; align-items: flex-start; }
  .panels > * { flex: 1 1 0; min-width: 0; }

  .pagination { flex-direction: row; align-items: center; justify-content: space-between; }

  /* The entry row, laid out as a row. Tab moves across it. */
  .entry--grid { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; }
  .entry--grid .field { margin-bottom: 0; flex: 1 1 8rem; max-width: none; }
  .entry--grid .field--amount { flex: 0 1 9rem; }
  .entry--grid .field--date { flex: 0 1 10rem; }
  /* A category name is long enough to be clipped at the shared basis. */
  .entry--grid .field--category { flex: 1 1 12rem; }
  .entry--grid .entry__submit { flex: 0 0 auto; }

  .row__actions form { flex: 0 0 auto; }

  /* The collection becomes a grid, and the gallery a row of three. */
  .tiles { grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); }
  .photo-strip__item { flex: 0 0 calc((100% - var(--space-3) * 2) / 3); }
  .gallery img { max-width: 22rem; }

  .specs { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-6); }

  .change dt { flex: 0 0 10rem; }
}

/* Print and reduced motion ------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* Vehicle fields, B7 --------------------------------------------------------
   The spec block, the collection card and the editable lists. */

/* A group of form fields or switches. A fieldset with a legend, because that is
   what the browser already knows how to announce. */
.group {
  border: 1px solid var(--line-colour);
  border-radius: 6px;
  padding: 0.75rem;
  margin: 0 0 1rem;
}
.group > legend {
  padding: 0 0.4rem;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink-faint);
}

/* The spec block: Identity, Mechanical, Provenance. One column on a phone. */
.spec { display: grid; gap: 1rem; }
.spec__title {
  margin: 0 0 0.35rem;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}
.spec__list { margin: 0; }
.spec__row {
  display: flex;
  gap: 0.75rem;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--line-colour);
}
.spec__row:last-child { border-bottom: 0; }
.spec__row dt { margin: 0; color: var(--ink-faint); }
.spec__row dd { margin: 0; text-align: right; }
.spec__footer { margin-top: 1rem; }

/* The editable lists. Each row is a rename box plus its actions, and at 360px
   the actions wrap under the box rather than squeezing it to nothing. */
.rows { list-style: none; margin: 0 0 0.75rem; padding: 0; }
.row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--line-colour);
}
.inline-form { display: flex; gap: 0.5rem; align-items: flex-end; }
.inline-form--grow { flex: 1 1 12rem; }
.inline-form .field { margin: 0; flex: 1 1 auto; }
.row__actions { display: flex; gap: 0.35rem; margin-left: auto; }
button[disabled], .button[disabled] { opacity: 0.35; pointer-events: none; }

/* The collection card. A fixed 3:2 frame so one portrait photograph does not
   make its card twice the height of the others. */
.tile__frame {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--paper);
  border-radius: 4px 4px 0 0;
}
.tile__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* No photograph a visitor may see: the car's own name, set quietly. Never a
   broken image and never a collapsed card. */
.tile__image--none {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  text-align: center;
  font-size: 0.9rem;
  color: var(--ink-faint);
  background: repeating-linear-gradient(
    45deg, var(--paper), var(--paper) 10px,
    var(--surface) 10px, var(--surface) 20px);
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (min-width: 768px) {
  /* As many spec groups side by side as the container has room for — not as many
     as the window has. In the record's narrow right column that is one, and a
     fixed three overflowed it. */
  .spec { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1rem 2rem; }
  .spec__row dt { flex: 0 0 9rem; text-align: left; }
}

/* A link inside a line of log text still has to be tappable. ADR-006 asks for
   44px, and an anchor sitting in a sentence is 19px tall by default. Padding it
   out keeps the sentence reading as a sentence and the target reachable with a
   thumb. */
.audit p a,
.audit__head a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--space-1);
}

/* B8 — the eight-section record, the grid, the filters and the Add action ----
   Every colour here is a token. A raw hex outside the token block is a second
   palette starting, and a test says so. */

/* The record --------------------------------------------------------------- */

.record { display: grid; gap: var(--space-4); }

.record__header {
  display: grid;
  gap: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--line-colour);
}
.record__cover { max-width: 22rem; }
.record__title h1 { margin: 0 0 var(--space-2); }
.record__chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0 0 var(--space-2); }

.spec__list--inline {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-3);
  margin: var(--space-3) 0;
}
.spec__list--inline dt { color: var(--ink-faint); font-size: var(--text-sm); margin: 0; }
.spec__list--inline dd { margin: 0; font-weight: 600; }

/* The section bar and the two-column record are gone, 19 August 2026.
   A record is segmented by `.segments` now — ADR-009 decisions 2 and 3. The bar
   linked to `#section-<key>`, which scrolled to a `<details>` and did not open
   it, so on a phone every one of those links landed on a collapsed row showing
   nothing. That was "tabs do not work". */

/* The essentials block: fragments, not labels. */
.essentials {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
  display: grid;
  gap: var(--space-1);
}
.essentials li { position: relative; padding-left: var(--space-4); }
.essentials li::before {
  content: "\00b7";
  position: absolute;
  left: var(--space-2);
  color: var(--ink-faint);
}

/* The grid ----------------------------------------------------------------- */

.tile__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.tile__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border-top: 1px solid var(--line-colour);
}
.tile__pick { display: inline-flex; align-items: center; min-height: var(--tap); min-width: var(--tap); }
.hidden-form { display: contents; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0.15rem var(--space-2);
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid var(--line-colour);
  font-size: var(--text-sm);
  color: var(--ink-soft);
  white-space: nowrap;
}
/* A chip states a fact. None of these means good or bad — a sold car is not a
   success and a hidden one is not a problem. CLAUDE.md section 1. */
.chip--sold { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.chip--selling, .chip--reserved { border-color: var(--line-strong); }
.chip--quiet { color: var(--ink-faint); }
.chip--count { font-variant-numeric: tabular-nums; }

/* A wrapped row of chips. Used by the listing queue to show which recorded
   fields a drafted description drew on — the join, made visible. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: var(--space-3) 0;
  padding: 0;
}
.chip-row .chip { white-space: normal; }

/* Filters ------------------------------------------------------------------ */

.filters {
  background: var(--surface);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
  padding: var(--space-3);
}
.filters__head { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: flex-end; }
.filters__search { flex: 1 1 12rem; }
.filters__search input, .filters__sort select { width: 100%; min-height: var(--tap); }
.filters__sort { flex: 0 1 14rem; }
.filters__go { min-height: var(--tap); }

.filters__toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap);
  cursor: pointer;
  color: var(--ink-soft);
}
.filters__body {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-3);
  padding: var(--space-3) 0;
}
.filters__group { border: 0; padding: 0; margin: 0; min-width: 0; }
.filters__group legend { padding: 0; font-size: var(--text-sm); color: var(--ink-faint); font-weight: 600; }
.filters__range { display: flex; gap: var(--space-2); }
.filters__range input { width: 100%; min-height: var(--tap); }
.filters__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line-colour);
}
.filters__foot button { min-height: var(--tap); }

.switches--tight { max-height: 16rem; overflow-y: auto; }
.switches--tight .switch { min-height: var(--tap); }

.bulk__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
}
.bulk__bar .field { margin: 0; }
.bulk__bar button { min-height: var(--tap); }
.bulk__bar p { flex: 1 0 100%; margin: 0; }

/* The Add action, and the attention counts --------------------------------- */

.menu--add { position: fixed; right: var(--space-4); bottom: var(--space-4); z-index: 40; }
.menu--add .menu__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 3.5rem;
  padding: 0 var(--space-6);
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.menu__button::-webkit-details-marker { display: none; }
.menu--add .menu__list {
  position: absolute;
  right: 0;
  bottom: 4rem;
  width: 15rem;
  list-style: none;
  margin: 0;
  padding: var(--space-2);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}
.menu__list a {
  display: flex;
  flex-direction: column;
  min-height: var(--tap);
  justify-content: center;
  padding: var(--space-2);
  border-radius: var(--radius);
  text-decoration: none;
}
.menu__list a:hover, .menu__list a:focus { background: var(--paper); }

.menu--attention { position: relative; }
.menu--attention .menu__button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap);
  padding: 0 var(--space-2);
  cursor: pointer;
  list-style: none;
}
.menu__button::-webkit-details-marker { display: none; }
.menu--attention .menu__list {
  position: absolute;
  right: 0;
  top: 100%;
  z-index: 30;
  width: 18rem;
  list-style: none;
  margin: 0;
  padding: var(--space-2);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}
.menu--attention .menu__list a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: var(--tap);
  padding: var(--space-2);
  text-decoration: none;
}

.gallery-group__title {
  margin: var(--space-4) 0 var(--space-2);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

.row { display: block; }
.card .card { border: 1px solid var(--line-colour); padding: var(--space-3); margin: var(--space-2) 0; }
.group--inner { margin-top: var(--space-3); }

@media (min-width: 900px) {
  .record__header { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); align-items: start; }

  .add { position: static; display: inline-block; }
  .add__menu { bottom: auto; top: 3rem; }
}

/* Anything that opens or navigates is 44px, wherever it sits. ADR-006 has no
   prose exemption: a link inside a sentence is still something a thumb has to
   find.

   Padded rather than made inline-flex, because a flex link cannot wrap — and one
   that cannot wrap runs off the side of a 360px screen, which is a worse bug
   than the one being fixed. The negative margin keeps the line height it had. */
.essentials a,
.publishing a,
.spec a,
.flash a,
.muted a,
.faint a,
.segments__panel > p a {
  /* 0.8rem left these at 42px, measured in Chrome at 360px by the browser check
     on 18 August 2026. ADR-006 says 44 and means it. */
  padding: 0.9rem 0.25rem;
  margin: -0.9rem 0;
}

.entry__head,
summary.faint {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--space-1);
}
.entry__head { cursor: pointer; }
.entry__head h3 { margin: 0; }

/* B13 — editing at scale, the lightbox, and the sold mark ------------------
   The bottleneck was never one screen: it was that every screen edits one
   thing. What follows dresses four answers to that — a cell you edit where it
   sits, a selection you act on, a spreadsheet grid, and a photograph you can
   actually look at. */

/* An editable cell ---------------------------------------------------------- */
/* A button, because it is one: reachable by keyboard, 44px on a phone, and it
   says what it does on focus rather than only on hover. The dotted underline is
   the only thing marking it apart from text, which is deliberate — a page of
   forty boxes is a form, and this is meant to read as the record. */

.cell {
  display: inline-block;
  width: auto;
  min-height: var(--tap);
  padding: var(--space-2) var(--space-1);
  margin: 0;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: text;
  border-bottom: 1px dotted var(--line-strong);
}
.cell:hover, .cell:focus-visible { background: var(--surface); border-bottom-color: var(--ink); }
.cell.is-blank { color: var(--ink-faint); font-style: italic; }
.cell.is-saved { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.cell.is-refused { box-shadow: inset 0 -2px 0 var(--danger); }

.cell__edit { display: inline-block; min-width: 8rem; }
.cell__edit input, .cell__edit select, .cell__edit textarea {
  width: 100%;
  min-height: var(--tap);
  font-size: max(16px, var(--text-base));
}
.cell__error {
  display: block;
  margin-top: var(--space-1);
  color: var(--danger);
  font-size: var(--text-sm);
}

/* A label-and-cell list, used under a photograph. */
.cells { margin: var(--space-2) 0 0; }
.cells__row { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline; }
.cells__row dt { flex: 0 0 8rem; color: var(--ink-faint); font-size: var(--text-sm); }
.cells__row dd { margin: 0; flex: 1 1 10rem; }

/* Selecting rows ------------------------------------------------------------ */

.pick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-width: var(--tap);
  cursor: pointer;
}
.pick input[type="checkbox"] { width: 1.35rem; height: 1.35rem; }
.pick-cell { width: var(--tap); }
.pick-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
}
.is-picked { background: color-mix(in srgb, var(--accent) 7%, transparent); }
tr.is-picked > td, tr.is-picked > th { background: color-mix(in srgb, var(--accent) 7%, transparent); }

/* The bar above a selection ------------------------------------------------- */
/* It is `hidden` until something is ticked, which the script removes. With no
   script it is simply always there, which is the honest fallback: the actions
   still work, they just do not appear only when they apply. */

.bulk__bar[hidden] { display: none; }
.bulk__count { margin: 0 0 var(--space-2); }
.bulk__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; }
.bulk__action { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.bulk__action select, .bulk__action input { min-height: var(--tap); }
.bulk__action button { min-height: var(--tap); width: auto; }
.bulk__label { color: var(--ink-faint); font-size: var(--text-sm); }
.bulk__action--danger { margin-left: auto; }

.rows--plain { list-style: none; margin: 0; padding: 0; }
.rows--plain > li { border: 0; background: none; padding: var(--space-1) 0; }

/* The gallery, once it can be selected from ---------------------------------- */

.gallery__head { display: flex; gap: var(--space-2); align-items: flex-start; }
.gallery__open { display: block; flex: 1 1 auto; min-width: 0; }
.gallery__open img { display: block; width: 100%; border-radius: var(--radius); }
.photo-strip__open { display: block; }

/* The grid ------------------------------------------------------------------ */
/* Desktop only, and the phone-only note beside it says so rather than leaving a
   blank. ADR-006 asks that every screen work on a phone; the phone screen for
   this job is the record, and this is a second way in for a desk. */

.grid-scroll { max-width: 100%; }
.grid { border-collapse: collapse; font-size: var(--text-sm); }
.grid th, .grid td { border: 1px solid var(--line-colour); padding: 0 var(--space-1); }
.grid thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
  text-align: left;
  white-space: nowrap;
}
.grid__name {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
  white-space: nowrap;
  text-align: left;
}
.grid .cell { min-height: 2.25rem; padding: var(--space-1); border-bottom: 0; width: 100%; }
.grid .cell:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.picker { position: relative; display: inline-block; }
.picker > summary { list-style: none; cursor: pointer; }
.picker > summary::-webkit-details-marker { display: none; }
.picker__body {
  position: absolute;
  z-index: 30;
  left: 0;
  top: 100%;
  width: 18rem;
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}

.paste[hidden] { display: none; }
.paste .changes { list-style: none; margin: 0; padding: 0; max-height: 18rem; overflow-y: auto; }
.paste .changes li { padding: var(--space-1) 0; border-bottom: 1px solid var(--line-colour); }

/* Sold ---------------------------------------------------------------------- */
/* The one red word on either screen. It states a fact — the system does not
   score anything — and it is the fact a buyer needs before they read the rest. */

.sold-mark {
  color: var(--danger);
  font-weight: 600;
  font-family: var(--font);
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Over the cover, not instead of it: a sold car keeps its photograph and its
   place in the grid. */
.tile__frame { position: relative; }
.tile__watermark {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font);
  font-size: clamp(1.5rem, 7vw, 2.5rem);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--watermark-ink);
  background: var(--watermark-ground);
  text-shadow: 0 1px 3px var(--watermark-shadow);
  border-radius: var(--radius) var(--radius) 0 0;
  pointer-events: none;
}

/* The lightbox --------------------------------------------------------------- */
/* Standard, familiar, boring. No zoom, no thumbnails, no animation. */

body.is-boxed { overflow: hidden; }

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: var(--shroud);
}
.lightbox__image {
  max-width: 100%;
  max-height: calc(100vh - 8rem);
  object-fit: contain;
}
.lightbox__caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--space-4);
  margin: 0;
  text-align: center;
  color: var(--shroud-ink);
  font-size: var(--text-sm);
}
.lightbox button {
  position: absolute;
  width: var(--tap);
  min-height: var(--tap);
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--shroud-control);
  color: var(--watermark-ink);
  font-size: var(--text-xl);
  line-height: 1;
  cursor: pointer;
}
.lightbox button:hover, .lightbox button:focus-visible { background: var(--shroud-control-lit); }
.lightbox__previous { left: var(--space-2); top: 50%; transform: translateY(-50%); }
.lightbox__next { right: var(--space-2); top: 50%; transform: translateY(-50%); }
.lightbox__close { right: var(--space-2); top: var(--space-2); }

.desk-inline { display: none; }

@media (min-width: 768px) {
  .desk-inline { display: inline-flex; }
  .cells__row dt { flex: 0 0 9rem; }
}

/* ==========================================================================
   THE COMPONENT SYSTEM — ADR-009, 19 August 2026
   ==========================================================================

   Everything above this line predates the standard and is being migrated to it.
   Everything below is the standard: one page template, one way to segment a
   record, one of each component, two densities, and tokens throughout.

   Nothing here sets a colour, a size or a space as a literal. Every value is a
   token declared in :root, which is what lets the density switch work at all —
   a density is a set of token values, not a second stylesheet.

   src/views/ui.js is the only place these classes are emitted from, and
   tests/ui-standard.test.js fails the build when a view uses a class that is in
   neither the library nor the shrinking legacy list. */

/* 5 · The two densities ---------------------------------------------------- */
/* An admin screen is a working surface: forty rows, tight rhythm, as much on
   screen as legibility allows. A visitor screen is a catalogue: air, a longer
   measure, one thing at a time. There is nothing between them and nothing
   improvised — a screen is one or the other, set once on the body. */

.density-dense {
  --pad: var(--space-3);
  --flow: var(--space-3);
  --cell-pad: var(--space-2);
  --title: var(--text-xl);
}

.density-airy {
  --pad: var(--space-6);
  --flow: var(--space-6);
  --cell-pad: var(--space-3);
  --title: var(--text-2xl);
}

/* 1 · The page template ---------------------------------------------------- */
/* Header bar, page title with its primary action, then content. Every screen,
   admin or visitor, with no variant and no opt-out. */

.page { display: block; }

.page__head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-bottom: var(--pad);
  border-bottom: 1px solid var(--line-colour);
}
.page__title { margin: 0; font-size: var(--title); }
.page__actions { display: flex; flex-direction: column; gap: var(--space-2); }
.page__lede {
  margin: var(--space-3) 0 0;
  max-width: var(--measure);
  color: var(--ink-soft);
}
.page__body { margin-top: var(--flow); }
.page__body > * + * { margin-top: var(--flow); }

/* 4 · Buttons -------------------------------------------------------------- */
/* Three ranks and no fourth. Primary is the one thing this screen is for,
   secondary is everything else you might do, danger destroys something. Full
   width and 44px on a phone; natural width on a desk. ADR-006. */

.button--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.button--secondary {
  background: var(--surface);
  border-color: var(--line-strong);
  color: var(--ink);
}
.button--danger {
  background: var(--surface);
  border-color: var(--danger);
  color: var(--danger);
}

.button-row { display: flex; flex-direction: column; gap: var(--space-2); }

/* 4 · Flash messages ------------------------------------------------------- */
/* One line at the top of the content saying what just happened. Never a toast
   that vanishes before it is read, and never in the corner of a phone screen
   where a thumb covers it. */

.flash {
  margin: var(--flow) 0 0;
  padding: var(--space-3);
  border-left: 3px solid var(--accent);
  background: var(--surface);
  border-radius: var(--radius);
}
.flash--ok { border-left-color: var(--accent); }

/* A value shown once and never again. Large enough to copy without a mistake. */
.secret {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  user-select: all;
  word-break: break-all;
}
.flash--error { border-left-color: var(--danger); }

/* 4 · Chips ---------------------------------------------------------------- */
/* A small word on a coloured ground, stating one fact and passing no judgement.
   `accent` is emphasis, not approval. CLAUDE.md §1. */

.chip--accent { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.chip--danger { border-color: var(--danger); color: var(--danger); }
.chip-row { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-2) 0; }

/* 4 · Cards ---------------------------------------------------------------- */
/* A bounded block. It does not change shape at the breakpoint — a card is
   already the phone shape — it only gets more room. */

.card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.card__title { margin: 0; font-size: var(--text-lg); }
.card__body > * + * { margin-top: var(--space-3); }
.card__foot {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line-colour);
}

/* 4 · Empty states --------------------------------------------------------- */
/* Never a blank area and never the word "None". It says what is not there, why
   that might be, and offers the one action that would change it. */

.empty-state {
  padding: var(--space-8) var(--pad);
  text-align: center;
  border: 1px dashed var(--line-colour);
  border-radius: var(--radius);
  background: var(--surface);
}
.empty-state__title { margin: 0; font-family: var(--font-display); font-size: var(--text-lg); }
.empty-state__hint {
  margin: var(--space-2) auto 0;
  max-width: var(--measure);
  color: var(--ink-faint);
  font-size: var(--text-sm);
}
.empty-state__action { margin-top: var(--space-4); }

/* 4 · Tables --------------------------------------------------------------- */
/* One table component, with row selection and inline editing built in, and two
   presentations of the same rows: a real table on a desk, stacked cards on a
   phone. The caller supplies both shapes, because only the caller knows which
   four fields matter on a phone. ADR-006. */

.data-table__scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.data-table { width: 100%; border-collapse: collapse; }
.data-table th,
.data-table td {
  padding: var(--cell-pad);
  border-bottom: 1px solid var(--line-colour);
  text-align: left;
  vertical-align: top;
}
.data-table thead th {
  position: sticky;
  top: 0;
  background: var(--surface);
  font-size: var(--text-sm);
  color: var(--ink-soft);
  white-space: nowrap;
}
.data-table__caption { text-align: left; color: var(--ink-faint); font-size: var(--text-sm); }
.data-table__number { text-align: right; font-variant-numeric: tabular-nums; }
.data-table__pick { width: var(--tap); }

.data-table__cards { list-style: none; margin: 0; padding: 0; }
.data-table__card {
  padding: var(--pad);
  background: var(--surface);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
}
.data-table__card + .data-table__card { margin-top: var(--space-2); }

/* 4 · Pagination ----------------------------------------------------------- */
/* The count first, because on most screens that is the whole question. Never
   numbered pages: with 39 cars they are noise, and with 3,900 a filter is still
   the better way to find one. */

.pagination {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--flow);
}
.pagination__count { color: var(--ink-faint); font-size: var(--text-sm); }
.pagination__links { display: flex; flex-direction: column; gap: var(--space-2); }

/* 4 · Overlays and bottom sheets ------------------------------------------- */
/* One thing, two shapes. On a desk a panel anchored under the control that
   opened it; on a phone a sheet along the bottom edge, where a thumb is. A
   <details>, so it opens and closes with no script, and data-dismiss so the one
   script there is closes it when you click away or press escape. */

.sheet { position: relative; }
.sheet__toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap);
  padding: 0 var(--space-2);
  cursor: pointer;
  color: var(--ink-soft);
  list-style: none;
}
.sheet__toggle::-webkit-details-marker { display: none; }

.sheet__panel {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  max-height: 80svh;
  overflow-y: auto;
  padding: var(--space-4);
  background: var(--surface);
  border-top: 1px solid var(--line-strong);
  border-radius: var(--radius) var(--radius) 0 0;
}
.sheet__body > * + * { margin-top: var(--space-3); }

/* 2 · Segmenting a record -------------------------------------------------- */
/* The one way. Tabs on a desk, accordion on a phone, from the same markup.
   A radio group — which is why it needs no script and why the arrow keys
   already work: a radio group is a tab list the browser has always known how to
   drive. The server renders `checked` from ?section=, so a segment has a real
   URL that survives a redirect, a bookmark and the back button.

   Phone: label, panel, label, panel — an accordion, one open at a time. */

.segments {
  display: block;
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
  background: var(--surface);
}
.segments__item { display: block; }
.segments__item + .segments__item { border-top: 1px solid var(--line-colour); }

.segments__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.segments__tab {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap);
  padding: var(--space-3);
  font-weight: 600;
  cursor: pointer;
}
.segments__tab::after { content: "+"; margin-left: auto; color: var(--ink-faint); }
.segments__radio:checked ~ .segments__tab::after { content: "−"; }
.segments__radio:focus-visible ~ .segments__tab {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.segments__panel { display: none; padding: 0 var(--space-3) var(--space-3); }
.segments__radio:checked ~ .segments__panel { display: block; }
.segments__panel > * + * { margin-top: var(--space-3); }
.segments__question { margin: 0 0 var(--space-3); color: var(--ink-faint); font-size: var(--text-sm); }
.segments__hint { margin: 0; padding: var(--space-3); color: var(--ink-faint); font-size: var(--text-sm); }

.photo-strip__caption { margin-top: var(--space-2); color: var(--ink-faint); font-size: var(--text-sm); }

/* The desk ------------------------------------------------------------------ */

@media (min-width: 768px) {
  .page__head { flex-direction: row; align-items: baseline; justify-content: space-between; }
  .page__actions { flex-direction: row; }
  .button-row { flex-direction: row; align-items: center; }
  .pagination { flex-direction: row; align-items: center; justify-content: space-between; }
  .pagination__links { flex-direction: row; }

  /* The sheet stops being a sheet and becomes a panel under its control. */
  .sheet__panel {
    position: absolute;
    left: 0;
    right: auto;
    bottom: auto;
    top: 100%;
    width: 22rem;
    max-height: none;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
  }

  /* Tabs. `display: contents` lifts every label and panel into one flex row, so
     `order` can put all the labels above all the panels — the same markup the
     phone reads as an accordion, with nothing duplicated and no script. */
  .segments { display: flex; flex-wrap: wrap; border: 0; background: none; }
  .segments__item { display: contents; }
  .segments__item + .segments__item { border-top: 0; }

  .segments__hint { order: 0; flex: 0 0 100%; padding: 0 0 var(--space-2); }

  .segments__tab {
    order: 1;
    flex: 0 0 auto;
    min-height: var(--tap);
    padding: var(--space-2) var(--space-4);
    border-bottom: 2px solid transparent;
    color: var(--ink-soft);
    font-weight: 500;
  }
  .segments__tab::after { content: none; }
  .segments__radio:checked ~ .segments__tab {
    border-bottom-color: var(--accent);
    color: var(--ink);
    font-weight: 600;
  }

  .segments__panel {
    order: 2;
    flex: 0 0 100%;
    padding: var(--space-4) 0 0;
    border-top: 1px solid var(--line-colour);
    margin-top: calc(var(--space-2) * -1 - 1px);
  }
}

/* The last six the library names and the stylesheet did not yet style ------- */

/* A folding block's heading when it does not fold. */
.entry__title { margin: 0 0 var(--space-3); font-size: var(--text-lg); }

/* One group of a spec block. */
.spec__group { min-width: 0; }

/* The header's figures: a row of small facts rather than a column of rows. */
.spec__list--inline { display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); gap: var(--space-3); }
.spec__list--inline .spec__row { display: block; border: 0; padding: 0; }
.spec__list--inline dd { text-align: left; font-weight: 600; }

/* A grid of tiles you can select from. The checkbox sits over the card, so the
   card needs somewhere to put it. */
.tiles--pickable .tile { position: relative; }

/* The filter panel's sheet. A `<details>` with no marker of its own — the
   toggle carries the count, which is what says how many filters are on. */
.filters__sheet { display: block; }
.filters__sheet > summary { list-style: none; }
.filters__sheet > summary::-webkit-details-marker { display: none; }

/* A list that can be selected from. The bar below it is the bulk bar. */
.picking { display: block; }

/* The three block-level containers the components above hang from. */
.menu { position: relative; }
.bulk { display: block; }
.gallery-group { display: block; }

/* Not styling — a contract. The script reads the choices a page's dropdowns
   offer out of this block, and a <script> is not rendered anyway. */
.edit-choices { display: none; }

/* The pattern library's own scaffolding ------------------------------------ */
/* A screen rather than a component, but a screen built after the standard, so
   its classes are registered in LIBRARY_CLASSES like everything else. */

.pattern__contents { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--flow); }

.pattern__rules { display: grid; gap: var(--space-2); margin: 0 0 var(--space-4); }
.pattern__rules > div { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.pattern__rules dt {
  flex: 0 0 5rem;
  color: var(--ink-faint);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.pattern__rules dd { margin: 0; flex: 1 1 12rem; }

.pattern__pair { display: grid; gap: var(--space-4); }
.pattern__wide, .pattern__narrow { min-width: 0; }
.pattern__label {
  margin: 0 0 var(--space-2);
  color: var(--ink-faint);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}
.pattern__stage {
  padding: var(--space-4);
  background: var(--paper);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
}
.pattern__frame {
  width: 360px;
  max-width: 100%;
  height: 30rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper);
}
.pattern__frame-body { padding: var(--space-4); }

.pattern__note { max-width: var(--measure); color: var(--ink-soft); font-size: var(--text-sm); }

.pattern__tokens { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.pattern__token {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--line-colour);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: var(--text-sm);
}
.pattern__swatch {
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
}
.pattern__swatch[data-token="--paper"] { background: var(--paper); }
.pattern__swatch[data-token="--surface"] { background: var(--surface); }
.pattern__swatch[data-token="--ink"] { background: var(--ink); }
.pattern__swatch[data-token="--ink-soft"] { background: var(--ink-soft); }
.pattern__swatch[data-token="--ink-faint"] { background: var(--ink-faint); }
.pattern__swatch[data-token="--line-colour"] { background: var(--line-colour); }
.pattern__swatch[data-token="--line-strong"] { background: var(--line-strong); }
.pattern__swatch[data-token="--accent"] { background: var(--accent); }
.pattern__swatch[data-token="--accent-ink"] { background: var(--accent-ink); }
.pattern__swatch[data-token="--danger"] { background: var(--danger); }

.pattern__states { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.pattern__laws { max-width: var(--measure); padding-left: var(--space-4); }
.pattern__laws li + li { margin-top: var(--space-2); }

@media (min-width: 900px) {
  .pattern__pair { grid-template-columns: minmax(0, 1fr) 360px; align-items: start; }
}
