/* ---------------------------------------------------------------------------
   1 of M Register
   Utility direction: neutral greys biased slightly blue, steel on controls
   only. Semantic colour is reserved for record state, never for chrome.

   Two colours are the brand and are not interchangeable with the semantics
   above: steel (--accent) carries every control, and chalk orange (--chalk) is
   reserved for a flagged record — never decoration. The mark's tricolor is
   kept for the brand itself: the mark, the bar across a car page's header
   and the record sheet (CAR-323, CAR-324). No control or border borrows it.
   --------------------------------------------------------------------------- */

/* --- fonts ----------------------------------------------------------------
   Served from app/static/fonts rather than Google, so a page load makes no
   external request. Latin subset only; see that folder's README for why, and
   for how to refresh the files.

   Schibsted Grotesk is one variable file per style: 400 to 900 in the roman,
   the same range again in the italic. The mark needs both — its M is italic at
   900 — so the italic is not optional weight the way it would be in an app that
   only ever slants a caption. --------------------------------------------- */

@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('fonts/schibsted-grotesk-variable-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: italic;
  font-weight: 400 900;
  font-display: swap;
  src: url('fonts/schibsted-grotesk-variable-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Fragment Mono ships one weight and no more. Nothing in here asks the mono for
   a medium, because there is not one to ask for. */
@font-face {
  font-family: 'Fragment Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/fragment-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Light — the complete palette. Neutrals carry a faint blue cast so they sit
     with the accent rather than reading as unconsidered mid-grey. */
  --ground:        #f2f4f7;
  --surface:       #ffffff;
  --surface-2:     #f8f9fb;
  --surface-sunk:  #eceff4;
  --border:        #d8dde5;
  --border-strong: #bcc4d0;
  --text:          #171a1f;
  --text-muted:    #5d6675;
  --text-faint:    #8a93a1;

  --accent:        #2c4a63;
  --accent-hover:  #1b3040;
  --accent-soft:   #e6edf3;
  --accent-ring:   rgba(44, 74, 99, 0.35);

  --chalk:         #c4501e;
  --gunmetal:      #22272e;

  /* A UK rear number plate's own colours. Deliberately identical in both
     themes — the plate is a real-world object, the same argument as the metal
     of the logo — which is why these live on :root and are never overridden. */
  --plate-yellow:  #fedd00;
  --plate-edge:    #b89f00;
  --plate-ink:     #111111;

  /* Ink that sits on top of --accent. It was #fff written out at every call
     site with a dark-mode override beside it; one token retires four of those
     blocks and means a new accent-coloured control cannot get it wrong. */
  --on-accent:     #ffffff;

  --flag-warn:     #a8590b;
  --flag-warn-bg:  #fdf1e0;
  --flag-crit:     #ad2b22;
  --flag-crit-bg:  #fdeceb;
  --flag-good:     #12655f;
  --flag-good-bg:  #e2f2f0;
  /* For Sale's own blue (CAR-602): the sky stripe's hue family, but not the
     brand tokens, which stay reserved for the mark and the bar. */
  --sale:          #1f5a96;
  --sale-bg:       #ddeefa;

  --row-hover:     #f4f7fb;
  --row-selected:  #e6edf3;

  /* The car page and the record sheet (CAR-323, CAR-324): ink for the line
     and the primary button, a hairline for rows inside a card, the red a
     failed test is written in, and the brand's three colours. */
  --ink:           #14171b;
  --row-rule:      #eceff4;
  --fail-text:     oklch(48% 0.17 28);
  --tri-sky:       oklch(66% 0.12 225);
  --tri-navy:      oklch(38% 0.11 280);
  --tri-red:       oklch(54% 0.17 28);

  --shadow-panel:  0 1px 2px rgba(16, 24, 40, .06), 0 12px 32px rgba(16, 24, 40, .14);
  --shadow-pop:    0 1px 2px rgba(16, 24, 40, .06), 0 6px 16px rgba(16, 24, 40, .12);

  /* Type. Twelve sizes had accumulated in this file, which is how one grid row
     ended up mixing four of them. These are the ladder; a sixth size is a
     decision to argue for, not a default to reach for. Same for the weights —
     550, 600 and 650 were all in use and no reader could tell them apart. */
  --fs-micro:  10.5px;   /* uppercase metadata labels */
  --fs-dense:  11.5px;   /* table text, pills, column headers */
  --fs-body:   13px;     /* default UI and prose */
  --fs-title:  15px;     /* section and modal headings */
  --fs-hero:   27px;     /* dashboard tile numbers */

  --fw-normal: 400;
  --fw-medium: 600;
  --fw-bold:   700;

  --ui: 'Schibsted Grotesk', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --mono: 'Fragment Mono', ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --row-h: 34px;
  --toolbar-h: 44px;
  --topbar-h: 48px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:        #101216;
    --surface:       #181b21;
    --surface-2:     #1d2128;
    --surface-sunk:  #14171c;
    --border:        #2a2f39;
    --border-strong: #3b424f;
    --text:          #e8ebf0;
    --text-muted:    #9aa3b2;
    --text-faint:    #6d7686;

    --accent:        #86aac6;
    --accent-hover:  #a2c0d6;
    --accent-soft:   #1e2c38;
    --accent-ring:   rgba(134, 170, 198, 0.4);

    --chalk:         #e0703c;

    --on-accent:     #0b1219;

    --flag-warn:     #e0a45c;
    --flag-warn-bg:  #2c2113;
    --flag-crit:     #e8837a;
    --flag-crit-bg:  #2e1817;
    --flag-good:     #62c0b6;
    --flag-good-bg:  #122725;
    /* For Sale's own blue (CAR-602): the sky stripe's hue family, but not
       the brand tokens, which stay reserved for the mark and the bar. */
    --sale:          #7ab8e0;
    --sale-bg:       #132634;

    --row-hover:     #1e222a;
    --row-selected:  #1d2b37;

    --ink:           #e8ebf0;
    --row-rule:      #22262e;
    --fail-text:     #e8837a;
    --tri-sky:       oklch(70% 0.12 225);
    --tri-navy:      oklch(50% 0.11 280);
    --tri-red:       oklch(60% 0.17 28);

    --shadow-panel:  0 1px 2px rgba(0, 0, 0, .4), 0 12px 32px rgba(0, 0, 0, .5);
    --shadow-pop:    0 1px 2px rgba(0, 0, 0, .4), 0 6px 16px rgba(0, 0, 0, .45);
  }
}

:root[data-theme="dark"] {
  --ground:        #101216;
  --surface:       #181b21;
  --surface-2:     #1d2128;
  --surface-sunk:  #14171c;
  --border:        #2a2f39;
  --border-strong: #3b424f;
  --text:          #e8ebf0;
  --text-muted:    #9aa3b2;
  --text-faint:    #6d7686;

  --accent:        #86aac6;
  --accent-hover:  #a2c0d6;
  --accent-soft:   #1e2c38;
  --accent-ring:   rgba(134, 170, 198, 0.4);

  --chalk:         #e0703c;

  --on-accent:     #0b1219;

  --flag-warn:     #e0a45c;
  --flag-warn-bg:  #2c2113;
  --flag-crit:     #e8837a;
  --flag-crit-bg:  #2e1817;
  --flag-good:     #62c0b6;
  --flag-good-bg:  #122725;
  /* For Sale's own blue (CAR-602): the sky stripe's hue family, but not the
     brand tokens, which stay reserved for the mark and the bar. */
  --sale:          #7ab8e0;
  --sale-bg:       #132634;

  --row-hover:     #1e222a;
  --row-selected:  #1d2b37;

  --ink:           #e8ebf0;
  --row-rule:      #22262e;
  --fail-text:     #e8837a;
  --tri-sky:       oklch(70% 0.12 225);
  --tri-navy:      oklch(50% 0.11 280);
  --tri-red:       oklch(60% 0.17 28);

  --shadow-panel:  0 1px 2px rgba(0, 0, 0, .4), 0 12px 32px rgba(0, 0, 0, .5);
  --shadow-pop:    0 1px 2px rgba(0, 0, 0, .4), 0 6px 16px rgba(0, 0, 0, .45);
}

* { box-sizing: border-box; }

/* An author `display` rule outranks the UA rule behind the hidden attribute,
   so anything given `display: grid`/`flex` below would ignore `hidden`. This
   keeps the attribute authoritative wherever it is used. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--text);
  font-family: var(--ui);
  font-size: var(--fs-body);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: 2px;
}

/* --- wireframe banner ---------------------------------------------------- */

.wire-note {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  background: var(--flag-warn-bg);
  color: var(--flag-warn);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-dense);
}
.wire-note strong { font-weight: var(--fw-medium); }
.wire-note code {
  font-family: var(--mono);
  font-size: var(--fs-dense);
}

/* --- app shell ----------------------------------------------------------- */

.app {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  height: calc(100vh - 31px);
  min-height: 560px;
}

/* The phone layout lives at the end of this file — its overrides only win by
   source order, and while the block sat up here, half of it silently lost
   (CAR-228). Both classes, because .icon-btn alone sets display and would
   otherwise win on desktop. */
.icon-btn.nav-btn { display: none; }
/* Under the drawer, over everything else — the detail panel sits at 60, and
   the drawer at 66 above it, so opening the menu always reaches it. Modals
   (70) are unaffected: the drawer cannot be opened while one is up. */
.nav-scrim { z-index: 65; }
@media (prefers-reduced-motion: reduce) {
  .sidebar { transition: none !important; }
}

/* ---------------------------------------------------------------------------
   The mark

   "1 OF M" in three equal columns over a three-colour bar, each letter centred
   on its own third: the 2a lockup (CAR-346), which replaced the baseline-run
   plaque line of CAR-285. Two lockups are built here because two are used —
   the full plate on the access screen, and the inline wordmark in the sidebar.
   The icons draw the same lockup as SVG outlines, because an icon cannot
   reach a webfont.

   The tricolor is not BMW M's. It is deliberately shifted — sky, navy-violet,
   red. Its three variables live on :root because three things wear it: the
   mark, the bar across a car page's header card and the record sheet
   (CAR-323, CAR-324). No button, link or border in this file may borrow it.

   Everything scales from the numeral size: the bar is .1724 of it, the gap
   above the bar .2414, the lockup's least width 2.07 — 10px, 14px and 120px at
   the plate's 58px. The OF is stated per lockup because the sheet rounds it:
   16px at 58px, 8px at 26px.
   --------------------------------------------------------------------------- */

.mark {
  --mark-ink:   #1A1D21;
  --mark-frame: #C6CCD4;
  --mark-of:    #4B5563;
  --mark-sub:   #6B7280;
  --mark-foot:  #4B5563;
  --mark-rule:  #D8DDE5;
  --mark-face:  #ffffff;

  color: var(--mark-ink);
}
:root[data-theme="dark"] .mark {
  --mark-ink:   #F2F5F8;
  --mark-frame: #4A525C;
  --mark-of:    #B7BEC8;
  --mark-sub:   #8A93A1;
  --mark-foot:  #B7BEC8;
  --mark-rule:  #4A525C;
  --mark-face:  #191D22;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .mark {
    --mark-ink:   #F2F5F8;
    --mark-frame: #4A525C;
    --mark-of:    #B7BEC8;
    --mark-sub:   #8A93A1;
    --mark-foot:  #B7BEC8;
    --mark-rule:  #4A525C;
    --mark-face:  #191D22;
  }
}

/* The line itself: three equal columns, each letter centred in its own, so
   the OF sits mid-height between the two 900s and every letter lands over its
   own third of the bar. The columns are 1fr apiece, which in a fit-content
   box makes each as wide as the widest letter. The negative right margin on
   OF cancels the letter-space trailing its F, which would otherwise pull it
   .14em off centre. */
.mark-line {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  align-items: center;
  justify-items: center;
  min-width: 2.07em;
  font-size: var(--mark-size);
  font-weight: 900;
  line-height: 1;
}
.mark-line .of {
  font-family: var(--mono);
  font-size: var(--mark-of-size);
  font-weight: 400;
  color: var(--mark-of);
  letter-spacing: .14em;
  margin-right: -.14em;
}
.mark-line .m {
  font-style: italic;
}

/* One strip in three exact thirds. A gradient with hard stops rather than three
   divs: same result, and the bar stays one element to size and place. */
.mark-bar {
  height: calc(var(--mark-size) * .1724);
  background: linear-gradient(to right,
    var(--tri-sky)  0 33.3333%,
    var(--tri-navy) 33.3333% 66.6667%,
    var(--tri-red)  66.6667% 100%);
}

/* Line and bar travel together and are the same width, which is what puts
   each column over its own colour: keep them siblings in this one box. */
.mark-lockup {
  display: flex;
  flex-direction: column;
  gap: calc(var(--mark-size) * .2414);
  width: fit-content;
}

/* --- the plate ----------------------------------------------------------- */

.mark-plate {
  --mark-size: 58px;
  --mark-of-size: 16px;

  border: 3px solid var(--mark-ink);
  border-radius: 12px;
  padding: 7px;
  background: var(--mark-face);
  width: fit-content;
}
.mark-plate-inner {
  border: 1px solid var(--mark-frame);
  border-radius: 6px;
  padding: 30px 36px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
/* .26em of tracking hangs off the last M as space nobody asked for; the
   negative margin takes it back so the line is centred on its letters. */
.mark-foot {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .26em;
  margin-right: -.26em;
  color: var(--mark-foot);
  white-space: nowrap;
}

/* --- the inline wordmark ------------------------------------------------- */

.mark-inline {
  --mark-size: 26px;
  --mark-of-size: 8px;

  display: flex;
  align-items: center;
  gap: 12px;
}
.mark-inline .mark-rule {
  width: 1px;
  align-self: stretch;
  background: var(--mark-rule);
}
.mark-inline .mark-sub {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .24em;
  margin-right: -.24em;
  color: var(--mark-sub);
  white-space: nowrap;
}

/* --- sidebar ------------------------------------------------------------- */

.sidebar {
  background: var(--surface-sunk);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* The header holds the inline wordmark and nothing else: 178px of lockup in
   the 182px the 210px sidebar leaves between its paddings, which is why the
   wordmark is the 26px one and not the plate. */
.brand {
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  padding: 0 14px;
  border-bottom: 1px solid var(--border);
  flex: none;
}

.side-group { padding: 12px 8px 4px; }
.side-label {
  padding: 0 6px 6px;
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.side-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 5px 6px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  text-align: left;
  cursor: pointer;
  color: var(--text-muted);
}
.side-item:hover { background: var(--row-hover); color: var(--text); }
.side-item[aria-current="true"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: var(--fw-medium);
}
/* A saved view that cannot answer anything about the table in front of you is
   turned off rather than left to return nothing (CAR-100). */
.side-item[disabled] { opacity: .4; cursor: default; }
.side-item[disabled]:hover { background: transparent; color: var(--text-muted); }
.side-item .ico { width: 14px; flex: none; opacity: .8; }
/* Icons are drawn, not typed: one 14px stroke set in currentColor, so every
   row carries the same visual weight and the set themes with its text. The
   unicode dingbats they replace rendered at whatever weight the platform's
   font gave them, which is why the sidebar looked assembled from parts. */
.ico svg { width: 14px; height: 14px; display: block; }
.side-count {
  margin-left: auto;
  font-size: var(--fs-dense);
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.side-foot {
  margin-top: auto;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  font-size: var(--fs-dense);
  color: var(--text-faint);
  line-height: 1.5;
}

/* Sign out lives under the sidebar note, and is only rendered when a password
   is actually configured — see index.html. */
.side-out {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.link-btn {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--text-faint);
  cursor: pointer;
}
.link-btn:hover { color: var(--accent); text-decoration: underline; }

/* --- main ---------------------------------------------------------------- */

.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--surface);
}

.topbar {
  height: var(--topbar-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 12px;
  border-bottom: 1px solid var(--border);
}
.view-tabs { display: flex; gap: 2px; }
.tab {
  padding: 5px 11px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}
.tab:hover { background: var(--row-hover); color: var(--text); }
.tab[aria-selected="true"] {
  background: var(--surface-sunk);
  color: var(--text);
  font-weight: var(--fw-medium);
  box-shadow: inset 0 0 0 1px var(--border);
}
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 6px; }

/* The option codes on a factory build sheet (CAR-371): two columns where
   there is room, the code in the mono face as BMW prints it. */
.build-options { margin: 0; padding: 0; list-style: none; columns: 2; column-gap: 24px; font-size: var(--fs-dense); }
.build-options li { break-inside: avoid; padding: 2px 0; }
.build-code { font-family: var(--mono); font-size: var(--fs-micro); color: var(--text-muted); margin-right: 4px; }
@media (max-width: 560px) { .build-options { columns: 1; } }
/* The options BMW's record says were added after the factory (CAR-693). */
.build-later-label { margin: 12px 0 4px; font-size: var(--fs-micro); letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); }
.search {
  position: relative;
  display: flex;
  align-items: center;
}
.search input {
  width: 210px;
  padding: 5px 9px 5px 26px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-2);
}
.search input::placeholder { color: var(--text-faint); }
.search .ico {
  position: absolute;
  left: 8px;
  color: var(--text-faint);
  pointer-events: none;
  font-size: var(--fs-dense);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { background: var(--row-hover); color: var(--text); border-color: var(--border-strong); }
.btn[aria-expanded="true"], .btn.is-on {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: var(--fw-medium);
}
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-sm { padding: 3px 8px; font-size: var(--fs-dense); }
.btn .badge {
  min-width: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  line-height: 16px;
  text-align: center;
}

/* --- toolbar ------------------------------------------------------------- */

.toolbar {
  height: var(--toolbar-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  overflow-x: auto;
  scrollbar-width: thin;
}
.toolbar .spacer { margin-left: auto; }
.record-count {
  font-size: var(--fs-dense);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.record-count b { color: var(--text); font-weight: var(--fw-medium); }
/* The register total, kept alongside a model count as context rather than
   as the answer (CAR-99). */
.record-count .tail { color: var(--text-faint); }

/* --- popovers ------------------------------------------------------------ */

.pop-wrap { position: relative; }
.pop {
  /* Fixed, not absolute. The toolbar sets overflow-x so its buttons can scroll
     on a narrow screen, and CSS will not let one axis scroll while the other
     overflows — overflow-y resolves to auto as well, which clipped every
     dropdown to the toolbar's own height. Taking the popover out of that
     scroll container is the fix; wirePop() positions it under its button. */
  position: fixed;
  z-index: 40;
  min-width: 260px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  box-shadow: var(--shadow-pop);
}
.pop[hidden] { display: none; }
.pop-title {
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 8px;
}
.pop-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 4px;
  border-radius: 4px;
  cursor: pointer;
}
.pop-row:hover { background: var(--row-hover); }
.pop-row input { accent-color: var(--accent); margin: 0; }
.pop-row .n {
  margin-left: auto;
  font-size: var(--fs-dense);
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.pop-sep { height: 1px; background: var(--border); margin: 8px 0; }
.pop-foot { display: flex; gap: 6px; padding-top: 8px; }

.field-label {
  display: block;
  font-size: var(--fs-dense);
  font-weight: var(--fw-medium);
  color: var(--text-muted);
  margin-bottom: 4px;
}
/* A label with something to the right of it — today, the link that opens the
   advert URL being typed in. The link sits outside the <label> deliberately:
   inside one, clicking it would focus the input instead of following it. */
.field-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.field-link { font-size: var(--fs-micro); color: var(--accent); white-space: nowrap; }
.select, .input, .textarea {
  width: 100%;
  padding: 5px 8px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-2);
}
.textarea { min-height: 60px; resize: vertical; font-family: inherit; }

/* --- active filter chips -------------------------------------------------- */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.chips[hidden] { display: none; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 4px 2px 8px;
  border: 1px solid var(--accent);
  border-radius: 4px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--fs-dense);
}
.chip b { font-weight: var(--fw-medium); }
.chip button {
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  padding: 0 3px;
  border-radius: 8px;
  line-height: 1;
}
.chip button:hover { background: rgba(0,0,0,.08); }

/* The Gallery's "with photos only" default (CAR-45). Muted rather than
   accented: it is something the view arrived with, not a filter that was
   chosen, and giving it the same blue would overstate it. */
.chip-view {
  border-color: var(--border);
  background: var(--surface);
  color: var(--text-muted);
}

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

.grid-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
  scrollbar-width: thin;
}

table.grid {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-variant-numeric: tabular-nums;
}

table.grid thead th {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border-strong);
  border-right: 1px solid var(--border);
  padding: 0;
  text-align: left;
  font-weight: var(--fw-medium);
  font-size: var(--fs-dense);
  color: var(--text-muted);
  white-space: nowrap;
}
table.grid thead th:last-child { border-right: 0; }

.th-btn {
  display: flex;
  align-items: center;
  gap: 5px;
  width: 100%;
  height: 30px;
  padding: 0 9px;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: var(--fw-medium);
  cursor: pointer;
}
.th-btn:hover { background: var(--row-hover); }
.th-btn .sort { color: var(--accent); font-size: var(--fs-micro); }
.th-num { justify-content: flex-end; }

table.grid tbody td {
  padding: 0 9px;
  height: var(--row-h);
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 260px;
}
table.grid tbody td:last-child { border-right: 0; }
table.grid tbody tr { cursor: pointer; }
table.grid tbody tr:hover td { background: var(--row-hover); }
table.grid tbody tr[aria-selected="true"] td { background: var(--row-selected); }

/* One rule decides the family here: mono for anything you read character by
   character — the row number, the VIN, the VRM, a model code — and the UI face
   for everything else. Quantities stay in the UI face: its tabular figures
   already align them, and mileage is a magnitude you compare by size, not a
   string you compare by character. The row number used to be UI 11px sitting
   against a mono 11.5px VIN, which is what made one row look like four fonts. */
.cell-num { text-align: right; }
.cell-mono { font-family: var(--mono); font-size: var(--fs-dense); letter-spacing: -.01em; }
.cell-idx {
  font-family: var(--mono);
  font-size: var(--fs-dense);
  color: var(--text-faint);
  text-align: right;
  width: 46px;
}

/* The Sales grid's edit button, which sits outside the chosen fields just as
   the row number does at the other end (CAR-100). */
.cell-act { width: 34px; text-align: right; padding-right: 6px; }
.cell-muted { color: var(--text-faint); }

.group-row td {
  position: sticky;
  top: 30px;
  z-index: 5;
  background: var(--surface-sunk) !important;
  font-weight: var(--fw-medium);
  font-size: var(--fs-dense);
  border-bottom: 1px solid var(--border-strong);
  color: var(--text-muted);
}
.group-row .n { color: var(--text-faint); font-weight: var(--fw-normal); margin-left: 6px; }

/* value pills */
.swatch {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 2px;
  margin-right: 6px;
  vertical-align: -1px;
  /* The ring has to be the thing that survives, not the fill: Sapphire Black
     against the dark table surface measures 1.04:1, so the swatch itself is
     invisible there and a black ring on top of it adds nothing. A themed
     border reads against both ends — light grey under a near-white paint,
     mid grey over a black one. */
  box-shadow: inset 0 0 0 1px var(--border-strong);
  flex: none;
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 1px 7px;
  border-radius: 4px;
  /* A pill is a word — a status, a model, a count — and words are set in
     the UI face. Only identifiers are mono (VIN, plate, engine number, sale
     id). The base used to be mono with three of four variants overriding it,
     so "For Sale" and "Sold" sat in two faces in one column. */
  font-family: var(--ui);
  font-size: var(--fs-dense);
  font-weight: var(--fw-medium);
  background: var(--surface-sunk);
  color: var(--text-muted);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The plain pill holds a model code, a plate or a count — identifiers, so mono.
   These three hold words, and words are the UI face. */
.pill-warn { background: var(--flag-warn-bg); color: var(--flag-warn); }
.pill-crit { background: var(--flag-crit-bg); color: var(--flag-crit); }
.pill-good { background: var(--flag-good-bg); color: var(--flag-good); }
.pill-accent { background: var(--accent-soft); color: var(--accent); }

/* The current VRM as the thing it is: a UK rear number plate (CAR-89). It
   keeps the plate's own yellow in both themes, but it is built on the pill's
   geometry and type — same height, same radius, same mono at the same size —
   so it reads as a sibling of the chips beside it rather than a sticker. The
   old version asked for a "UK Number Plate" font that was never shipped and
   silently fell back to mono; now it asks for what it gets.
   Worn by the header's current mark and by the Previous plates row — CAR-166
   reversed the earlier call that previous plates stay plain text. */

/* The Previous plates row: each old mark as a plate, with the date it was
   given up sitting quietly beside it. Wraps because a much-replated car can
   hold four or five. */

.tick { color: var(--flag-good); font-weight: var(--fw-bold); }
.cross { color: var(--flag-crit); font-weight: var(--fw-bold); }

/* Mileage over time on the car panel (CAR-143). Colours come from the same
   variables as everything else, so the chart follows the theme. */
.mot-chart { display: block; width: 100%; height: auto; margin-top: 12px; }
.mot-chart .mot-line { fill: none; stroke: var(--accent); stroke-width: 1.5; }
.mot-chart .mot-pt { fill: var(--accent); }
.mot-chart .mot-pt-fail { fill: var(--flag-crit); }
.mot-chart .mot-axis { stroke: var(--border); stroke-width: 1; }
.mot-chart text { fill: var(--text-faint); font-size: var(--fs-micro); font-family: var(--ui); }
.mot-chart + .card-note { margin: 6px 0 0; }
.dash { color: var(--text-faint); }

/* --- gallery ------------------------------------------------------------- */

.gallery {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 14px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(212px, 1fr));
  gap: 12px;
  align-content: start;
  /* Rows are sized explicitly from their content. With the default `auto`,
     Chrome sizes each row from the tile's contribution before its photo has
     loaded and never grows it again, so rows end up shorter than the tiles
     and the tiles overlap. Both declarations are needed: max-content fixes
     the row, start stops the tile stretching to fill it. */
  grid-auto-rows: max-content;
  align-items: start;
  scrollbar-width: thin;
}
.card {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  overflow: hidden;
  text-align: left;
  padding: 0;
  color: inherit;
  display: flex;
  flex-direction: column;
}
/* Only the gallery's tiles open a car; other cards do not point (CAR-801). */
.gallery .card { cursor: pointer; }
.gallery .card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-pop); }
.card-shot {
  height: 96px;
  display: grid;
  place-items: center;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-micro);
  color: var(--text-faint);
  letter-spacing: .12em;
  text-transform: uppercase;
  background:
    repeating-linear-gradient(-45deg,
      transparent 0 7px,
      color-mix(in srgb, var(--text-faint) 9%, transparent) 7px 8px);
}
.card-body { padding: 9px 10px; display: flex; flex-direction: column; gap: 5px; }
/* Neither part of a tile may shrink: left to the flex default they compress
   against each other while the photo is still loading, which clips the body. */
.card-img, .card-shot, .card-body { flex: none; }
.card-vin { font-family: var(--mono); font-size: var(--fs-dense); letter-spacing: -.01em; }
.card-meta { display: flex; align-items: center; gap: 6px; font-size: var(--fs-dense); color: var(--text-muted); }
.card-foot { display: flex; align-items: center; gap: 6px; margin-top: 2px; flex-wrap: wrap; }

/* --- empty --------------------------------------------------------------- */

.empty {
  flex: 1;
  display: grid;
  place-items: center;
  padding: 40px;
  text-align: center;
  color: var(--text-muted);
}
.empty h3 { margin: 0 0 6px; font-size: var(--fs-title); color: var(--text); font-weight: var(--fw-medium); }
.empty p { margin: 0 0 14px; max-width: 42ch; }

/* --- detail panel -------------------------------------------------------- */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(12, 16, 22, .38);
  animation: fade .14s ease-out;
}
.scrim[hidden], .panel[hidden], .modal[hidden] { display: none; }
@keyframes fade { from { opacity: 0; } }
@keyframes slide { from { transform: translateX(16px); opacity: .4; } }
@media (prefers-reduced-motion: reduce) {
  .scrim, .panel, .modal { animation: none !important; }
}

.panel {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  z-index: 60;
  width: min(560px, 100vw);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-panel);
  animation: slide .16s ease-out;
}
.panel-head {
  flex: none;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.panel-title { min-width: 0; }
.panel-title .vin {
  font-family: var(--mono);
  font-size: var(--fs-title);
  letter-spacing: -.01em;
  word-break: break-all;
}
.panel-title .model-line {
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 3px;
}
.panel-title .colour-line {
  display: flex;
  align-items: center;
  margin-top: 3px;
  color: var(--text-muted);
  font-size: var(--fs-body);
}
.panel-title .sub {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 8px;
  color: var(--text-muted);
  font-size: var(--fs-dense);
}
.panel-actions { margin-left: auto; display: flex; gap: 6px; flex: none; }
.icon-btn {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--fs-body);
  line-height: 1;
}
.icon-btn:hover { background: var(--row-hover); color: var(--text); }

.panel-body { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 16px 20px; scrollbar-width: thin; }

.sec { padding-top: 16px; }
.sec-title {
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.sec-title .spacer { margin-left: auto; }

.kv {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: 7px 12px;
  align-items: start;
}
@media (max-width: 480px) { .kv { grid-template-columns: 116px minmax(0, 1fr); } }
/* Label and value share a size, and only the family changes — mono where the
   value is an identifier, ui everywhere else. The values used to sit at body
   size next to dense labels, so adjacent rows (Model at 13px ui, VIN at 11.5px
   mono) read as four different fonts (CAR-172). */
.kv dt { color: var(--text-muted); font-size: var(--fs-dense); }
.kv dd { margin: 0; word-break: break-word; font-size: var(--fs-dense); }
.kv dd.mono { font-family: var(--mono); }

table.sales {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-dense);
  font-variant-numeric: tabular-nums;
}
table.sales th {
  text-align: left;
  font-weight: var(--fw-medium);
  font-size: var(--fs-micro);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 0 8px 6px 0;
  white-space: nowrap;
}
table.sales td {
  padding: 7px 8px 7px 0;
  border-top: 1px solid var(--border);
  vertical-align: top;
}
/* Six columns inside a 560px panel. The numeric ones are given a left gap of
   their own rather than relying on the seller column to leave them one — it
   did not, and mileage ran straight into price as `5,729£59,377` (CAR-195).
   The date holds one line for the same reason: wrapped to two, it made every
   row in the table taller than it needed to be. */
table.sales td.num, table.sales th.num {
  text-align: right; padding-right: 0; padding-left: 12px; white-space: nowrap;
}
table.sales td.when, table.sales th.when { white-space: nowrap; }
/* The way back to what the sale actually said. Inline after the seller, so it
   costs a row no height. */
.advert-link { color: var(--accent); font-size: var(--fs-micro); white-space: nowrap; }

.none-yet {
  padding: 14px;
  border: 1px dashed var(--border-strong);
  border-radius: 5px;
  color: var(--text-muted);
  text-align: center;
  font-size: var(--fs-dense);
}

/* --- modal --------------------------------------------------------------- */

.modal {
  position: fixed;
  z-index: 70;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: min(540px, calc(100vw - 24px));
  max-height: min(88vh, 760px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-panel);
  animation: fade .14s ease-out;
}
.modal-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--border);
}
/* An existing sale opens with the dialog itself focused (CAR-345), so the
   arrow keys reach the list rather than the date field; no ring for that. */
.modal:focus { outline: none; }
.modal-head h2 { margin: 0; font-size: var(--fs-title); font-weight: var(--fw-medium); }
.modal-head .sub { color: var(--text-muted); font-size: var(--fs-dense); }
.modal-body { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 16px; scrollbar-width: thin; }
.modal-foot {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  border-radius: 0 0 8px 8px;
}
.modal-foot .spacer { margin-left: auto; }
/* On a narrow screen the footer hint took its full sentence down a thin
   column and squashed the buttons beside it. The hint moves to its own line
   above them instead (CAR-102). */
@media (max-width: 560px) {
  .modal-foot { flex-wrap: wrap; }
  .modal-foot .hint { flex: 1 1 100%; order: -1; }
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 11px;
}
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 460px) { .form-grid { grid-template-columns: minmax(0, 1fr); } }

/* The sale form is the first screen from the Sales page (CAR-159), so it is
   sized to be worked in rather than glanced at: the facts on the left, notes
   beside them at full height. Below 900px the two panes stack, which is the
   layout the form has always had. */
#modal { width: min(940px, calc(100vw - 24px)); max-height: min(92vh, 940px); }
#modal .modal-body { padding: 16px 20px 20px; }

.sale-panes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 11px; }
/* Notes take whatever height the fields beside them come to, which is what
   turns the width into somewhere you can actually write. */
.sale-notes { display: flex; flex-direction: column; }
.sale-notes .textarea { flex: 1; }

@media (min-width: 900px) {
  .sale-panes { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 22px; }
}

.hint { font-size: var(--fs-dense); color: var(--text-faint); margin-top: 4px; }
.err { font-size: var(--fs-dense); color: var(--flag-crit); margin-top: 4px; }
.err[hidden] { display: none; }
.input[aria-invalid="true"], .select[aria-invalid="true"] { border-color: var(--flag-crit); }

.car-ref {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-sunk);
  font-size: var(--fs-dense);
  margin-bottom: 13px;
}
.car-ref .mono { font-family: var(--mono); }

/* The car is one click away from inside the sale form (CAR-159). */
.car-ref-btn {
  width: 100%;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.car-ref-btn:hover { border-color: var(--accent); }
.car-ref .car-ref-go {
  margin-left: auto;
  font-size: var(--fs-micro);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
}

/* Moving a sale onto the right car (CAR-219). It sits under the car reference
   it is about to change, closed until it is asked for. */
.move-sale {
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-sunk);
  margin: -5px 0 13px;
}
.move-sale[hidden] { display: none; }
.move-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 10px;
}

/* --- toast --------------------------------------------------------------- */

.toast {
  position: fixed;
  z-index: 90;
  bottom: 18px; left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  box-shadow: var(--shadow-panel);
  font-size: var(--fs-body);
  max-width: calc(100vw - 24px);
}
.toast[hidden] { display: none; }
.toast .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--flag-good); flex: none; }
.toast code { font-family: var(--mono); font-size: var(--fs-dense); color: var(--text-muted); }
/* The link to copy by hand when the clipboard is refused (CAR-332). */
.toast-link {
  font-family: var(--mono); font-size: var(--fs-dense); color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 4px;
  padding: 3px 6px; margin-left: 6px; width: min(38ch, 60vw);
}

/* --- photos -------------------------------------------------------------- */
/* Added for the live app: the wireframe had no images to show. */

.card-img {
  width: 100%;
  height: 128px;
  object-fit: cover;
  display: block;
  border-bottom: 1px solid var(--border);
  background: var(--surface-sunk);
}

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 8px;
  font-size: var(--fs-dense);
  color: var(--text-muted);
}
.shot {
  display: block;
  border: 1px solid var(--border);
  border-radius: 5px;
  overflow: hidden;
  background: var(--surface-sunk);
}
.shot:hover { border-color: var(--accent); }
.shot img {
  width: 100%;
  height: 78px;
  object-fit: cover;
  display: block;
}
.report {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-sunk);
  color: var(--accent);
  text-decoration: none;
  /* A long filename shortens from the left, because the useful part of
     "carVertical - ***********S71863.pdf" is the end. */
  white-space: nowrap;
  overflow: hidden;
}
.report-name {
  overflow: hidden;
  text-overflow: ellipsis;
  direction: rtl;
  text-align: left;
}
.report-kind {
  flex: none;
  margin-left: auto;
  padding: 1px 6px;
  font-size: var(--fs-micro);
  letter-spacing: .04em;
  color: var(--text-faint);
  border: 1px solid var(--border);
  border-radius: 999px;
}
.report:hover { border-color: var(--accent); }

/* The loading state reuses .empty, which is a flex child of .main. */
#loading { background: var(--surface); }

/* ---------------------------------------------------------------------------
   Edit car (CAR-17)
   --------------------------------------------------------------------------- */

/* A checkbox and its wording read as one control, so they share a row and the
   label is clickable across its whole width. */
.check {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-body);
  color: var(--text);
  padding: 3px 0;
  cursor: pointer;
}
.check input { margin: 0; accent-color: var(--accent); }

/* Changing a VIN and archiving a car are the two actions here that are hard to
   undo, so they are folded away behind a summary rather than sitting among the
   ordinary fields where they could be triggered while doing something else. */
.danger {
  margin-top: 20px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
  padding: 0 11px;
}
.danger > summary {
  cursor: pointer;
  padding: 9px 0;
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--flag-warn, var(--text-muted));
}
.danger[open] { padding-bottom: 12px; }
.danger .hint { margin: 0 0 10px; }
.danger .form-grid { gap: 9px; }

/* The edit modal carries far more than the sale form, so it is allowed to be
   wider before the two-column grid starts to feel cramped. */
#editModal { width: min(680px, calc(100vw - 24px)); }
#editModal .sec-title { margin-bottom: 9px; }

/* Photo upload (CAR-17) --------------------------------------------------- */

.drop {
  display: block;
  margin-top: 10px;
  padding: 13px;
  border: 1px dashed var(--border-strong);
  border-radius: 7px;
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: var(--fs-body);
  text-align: center;
  cursor: pointer;
  transition: border-color .12s, background .12s, color .12s;
}
.drop:hover { border-color: var(--accent); color: var(--text); }
/* Dragging over it needs to look unmistakably different from hovering, or you
   cannot tell whether letting go will do anything. */
.drop.over {
  border-color: var(--accent);
  border-style: solid;
  background: var(--accent-soft);
  color: var(--accent);
}
.drop.busy { opacity: .65; cursor: progress; border-style: solid; }

/* Removing a photo (CAR-39) ------------------------------------------------ */

.shot-wrap, .report-wrap { position: relative; display: inline-block; }
/* A report is a document, not a picture: it spans the gallery rather than
   sitting in a photo-sized cell. The span has to carry this, because the span
   is the grid item — putting it on the anchor inside did nothing, and left the
   PDF looking like an image that had failed to load (CAR-62). */
.report-wrap { display: block; grid-column: 1 / -1; }

/* Hidden until the tile is hovered or the button itself has focus, so the
   gallery stays a gallery — but always present for keyboard and touch, where
   there is no hover to reveal it. */
.shot-x {
  position: absolute;
  top: 4px; right: 4px;
  width: 21px; height: 21px;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-micro);
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s, background .12s, color .12s, border-color .12s;
}
.shot-wrap:hover .shot-x,
.report-wrap:hover .shot-x,
.shot-x:focus-visible { opacity: 1; }
.shot-x:hover {
  background: var(--flag-warn-bg, var(--surface-sunk));
  color: var(--flag-warn, var(--text));
  border-color: var(--flag-warn, var(--border-strong));
}

/* The two arrows that put a grid in order (CAR-440), revealed the same way as
   the remove button and, like it, always there for keyboard and touch. Top
   left, so they are nowhere near the ✕ at the other corner: these move a
   photograph and that one takes it away. An arrow with nowhere to go is
   hidden rather than greyed — the first photograph simply cannot go back. */
.shot-move {
  position: absolute;
  top: 4px;
  width: 21px; height: 21px;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-body);
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s, background .12s, color .12s, border-color .12s;
}
.shot-move[data-move="back"] { left: 4px; }
.shot-move[data-move="on"] { left: 29px; }
.shot-wrap:hover .shot-move,
.shot-move:focus-visible { opacity: 1; }
.shot-move:hover { background: var(--surface-sunk); color: var(--text); border-color: var(--text-faint); }
.shot-move:disabled { opacity: 0; pointer-events: none; }
@media (hover: none) { .shot-x, .shot-move { opacity: 1; } }

/* ---------------------------------------------------------------------------
   Dashboard (CAR-25)

   There is one chart colour, steel, and it is measured rather than judged:
   #256f9c light on the sunk track, #3f8bbd dark, both inside the lightness band,
   over the chroma floor (steel proper is too grey to read as a hue at chart
   size) and past 3:1 against every surface they meet.

   One colour, because there is only ever one series. Sales each year and
   average price each year are separate charts on separate cards with their own
   titles and a value printed on every column — the second hue they used to
   carry told the reader nothing, and the brand has no second hue to spend on it
   anyway: chalk orange is reserved for a flagged record, never decoration.

   Bar length already encodes magnitude, so shading darker-where-bigger would
   say the same thing twice. Status tones are reserved for MOT, where the colour
   means a state, and always ship beside their label.
   --------------------------------------------------------------------------- */

/* The chart colours live on the root, not on the dashboard alone: the model
   page draws the same column chart and its bars were invisible while the
   colour was scoped to .dash (CAR-252). */
:root {
  --chart-1:     #256f9c;
  --chart-track: var(--surface-sunk);
}
:root[data-theme="dark"] { --chart-1: #3f8bbd; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --chart-1: #3f8bbd; }
}

/* The Dashboard, Sellers and Review pages' container. Not .dash, which is
   the grid's "—" (CAR-801). */
.summary {
  /* MOT is the one chart where colour means a state rather than an identity,
     so it keeps three. Re-stepped darker: the old amber measured 1.59:1 against
     its own track and was effectively an empty bar. These clear the lightness
     band, the chroma floor and colourblind separation in both themes, and every
     bar ships beside its label and count. */
  --chart-good:  #1a7d55;
  --chart-warn:  #c98213;
  --chart-bad:   #b0342a;
  --chart-none:  var(--border-strong);

  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 16px 18px 28px;
}

/* Headline numbers. A single figure is a tile, never a one-bar chart. */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 11px;
  margin-bottom: 16px;
}
/* Two to a row on a phone, not one number per screen-width (CAR-799). */
@media (max-width: 560px) { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 13px 15px;
}
.tile-n { font-size: var(--fs-hero); font-weight: var(--fw-medium); letter-spacing: -.02em; color: var(--text); }
.tile-l { font-size: var(--fs-dense); color: var(--text-muted); margin-top: 2px; }
.tile-note { font-size: var(--fs-dense); color: var(--text-faint); margin-top: 6px; }

.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 11px;
  align-items: start;
}
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 15px 16px;
  min-width: 0;
}
.card.wide { grid-column: 1 / -1; }
.card h3 {
  margin: 0 0 3px;
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
  display: flex;
  align-items: center;
}
.card-count { font-weight: var(--fw-normal); color: var(--text-faint); text-transform: none; letter-spacing: 0; }
.card-note { margin: 0 0 12px; font-size: var(--fs-dense); line-height: 1.5; color: var(--text-faint); }
.dash-empty { font-size: var(--fs-body); color: var(--text-faint); margin: 4px 0; }

/* Horizontal bars: label, track, value. The value is always written out, so
   the chart never depends on reading a bar against an axis. */
.bars { display: flex; flex-direction: column; gap: 5px; max-width: 640px; }
/* A list past six rows shows the six and the rest a click away (CAR-799). */
.more { margin-top: 2px; }
.more > summary { cursor: pointer; list-style: none; font-size: var(--fs-dense); color: var(--accent); padding: 2px 0; }
.more > summary::-webkit-details-marker { display: none; }
.more[open] > summary { margin-bottom: 5px; }
.bar-row { display: grid; grid-template-columns: minmax(0, 148px) 1fr 54px; gap: 9px; align-items: center; }
/* Room for a count and its share, "1,234 · 100%" (CAR-540). */
.bars-wide .bar-row { grid-template-columns: minmax(0, 148px) 1fr 96px; }
/* Name, launch price, bar, count: a model's options at new (CAR-630). */
.bars-priced .bar-row { grid-template-columns: minmax(0, 200px) 60px 1fr 54px; }
.bar-price { font-size: var(--fs-dense); font-variant-numeric: tabular-nums; text-align: right; color: var(--text-muted); white-space: nowrap; }
.bar-k {
  font-size: var(--fs-dense); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bar-track { background: var(--chart-track); border-radius: 3px; height: 15px; overflow: hidden; }
.bar-fill {
  height: 100%;
  background: var(--chart-1);
  /* Rounded only at the data end, anchored to the baseline. */
  border-radius: 0 3px 3px 0;
  min-width: 2px;
}
.bar-v { font-size: var(--fs-dense); font-variant-numeric: tabular-nums; text-align: right; color: var(--text-muted); }
.bar-row.muted .bar-k, .bar-row.muted .bar-v { color: var(--text-faint); }
.bar-fill.tone-good { background: var(--chart-good); }
.bar-fill.tone-warn { background: var(--chart-warn); }
.bar-fill.tone-bad  { background: var(--chart-bad); }
.bar-row.muted .bar-fill { background: var(--chart-none); }

/* Columns over time. */
/* A few years of one figure (CAR-799): the value over a short bar, the
   year and what the figure is built from under it, about 70px in all. */
.years { display: grid; grid-template-columns: repeat(auto-fit, minmax(64px, 1fr)); gap: 8px; max-width: 560px; }
.yr { display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 0; font-variant-numeric: tabular-nums; }
.yr-v { font-size: var(--fs-dense); color: var(--text); white-space: nowrap; }
.yr-v.muted { color: var(--text-faint); font-style: italic; }
.yr-bar { width: 100%; max-width: 48px; height: 28px; display: flex; align-items: flex-end; border-bottom: 1px solid var(--border); }
.yr-bar i { display: block; width: 100%; background: var(--chart-1); border-radius: 3px 3px 0 0; }
.yr-x { font-size: var(--fs-micro); color: var(--text-muted); }
.yr-n { font-size: var(--fs-micro); color: var(--text-faint); }
/* The same idea inside a table cell, kept on the figure's own line. Inline
   rather than a block under it, so a row carrying one is exactly as tall as a
   row that is not — which is the whole point of it (CAR-206). */
.cell-basis {
  font-size: var(--fs-micro); color: var(--text-faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

.dash-table { width: 100%; border-collapse: collapse; font-size: var(--fs-dense); }
.dash-table th {
  text-align: left; font-weight: var(--fw-medium); font-size: var(--fs-micro); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-faint);
  padding: 0 10px 7px 0; border-bottom: 1px solid var(--border);
}
.dash-table td { padding: 7px 10px 7px 0; border-bottom: 1px solid var(--border); color: var(--text); }
.dash-table tbody tr:last-child td { border-bottom: 0; }
.dash-table .pc { color: var(--text-faint); font-size: var(--fs-dense); }
.dash-table .mono { font-family: var(--mono); font-size: var(--fs-dense); }
.dash-table tr.clickable { cursor: pointer; }
.dash-table tr.clickable:hover td { background: var(--surface-2); }
.dash-scroll { overflow-x: auto; }


/* A year with no price recorded: a gap, not a zero. */

/* A long checkbox list — forty-odd sellers — scrolls inside the popover
   rather than scrolling the popover itself, which would carry the headings
   above it off the top (CAR-100). */
.pop-scroll { max-height: 220px; overflow-y: auto; margin: 0 -4px; padding: 0 4px; }

/* Range filters (CAR-34) */
.pop-range { display: flex; align-items: center; gap: 7px; padding: 3px 0 7px; }
.pop-range .to { font-size: var(--fs-dense); color: var(--text-faint); }
.input-sm { padding: 5px 7px; font-size: var(--fs-dense); min-width: 0; flex: 1; }

/* Editing a sale (CAR-43) */
.row-edit {
  border: 0;
  background: none;
  color: var(--text-faint);
  cursor: pointer;
  font-size: var(--fs-body);
  line-height: 1;
  padding: 2px 4px;
  border-radius: 4px;
  opacity: 0;
  transition: opacity .12s, color .12s, background .12s;
}
.sales tr:hover .row-edit,
table.grid tbody tr:hover .row-edit,
/* The Sellers page's table is a dash-table and was covered by neither rule
   above, so its edit button was invisible on any machine with a mouse — the
   hover:none rule below is the only reason it ever showed, and only on a
   phone. The seller form was unreachable on a desktop (CAR-263). */
.dash-table tbody tr:hover .row-edit,
.row-edit:focus-visible { opacity: 1; }
.row-edit:hover { color: var(--accent); background: var(--surface-2); }
@media (hover: none) { .row-edit { opacity: 1; } }

/* Delete sits apart from Cancel and Save, on the other side of the footer. */
.btn-danger { color: var(--flag-warn, #d03b3b); }
.btn-danger:hover { border-color: var(--flag-warn, #d03b3b); background: var(--surface-2); }

/* The Dashboard's comparison (CAR-798): measures down the side, a column
   per model and the register at the end, every figure right-aligned so the
   columns read down. A figure that opens its cars is a button that looks
   like the number it is until it is pointed at. */
.compare-card { margin-bottom: 11px; }
/* Fixed columns, so the two tables' model columns sit under each other. */
.compare { font-variant-numeric: tabular-nums; table-layout: fixed; min-width: 560px; }
.compare thead th:first-child { width: 30%; }
.compare th, .compare td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.compare tbody tr:last-child th { border-bottom: 0; }
/* On a phone the table scrolls sideways in its card; the labels stay put. */
.compare tr > th:first-child { position: sticky; left: 0; z-index: 1; background: var(--surface); }
.compare thead th:not(:first-child), .compare td { text-align: right; }
.compare thead th:not(:first-child) { padding-left: 14px; }
.compare tbody th {
  text-align: left; font-weight: var(--fw-normal); font-size: var(--fs-dense); letter-spacing: 0;
  text-transform: none; color: var(--text-muted); padding: 6px 10px 6px 0; border-bottom: 1px solid var(--border);
}
.compare td { padding: 6px 0 6px 14px; }
.compare tr.grp th {
  padding-top: 16px; font-size: var(--fs-micro); letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-faint); font-weight: var(--fw-medium);
}
.compare tr.sub th { padding-left: 14px; }
.compare .col-all { border-left: 1px solid var(--border); font-weight: var(--fw-medium); }
.compare .is-picked { background: var(--accent-soft); }
.compare .zero, .compare .dash { color: var(--text-faint); }
.cell-link {
  border: 0; padding: 0; background: none; font: inherit; color: inherit; cursor: pointer;
  border-bottom: 1px dotted transparent;
}
.cell-link:hover { color: var(--accent); border-bottom-color: var(--accent); }
/* The model page's counts that open their cars read the same way. */
.model-figures .kv-row .v a { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--border-strong); }
.model-figures .kv-row .v a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.cell-link:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }

/* Drill-through from a dashboard figure to the cars behind it (CAR-25) */
.tile-link, .bar-link { cursor: pointer; }
.tile-link { transition: border-color .12s, background .12s; }
/* A tile that is a link (the model page) reads like the tiles beside it. */
a.tile-link { color: inherit; text-decoration: none; }
.tile-link:hover { border-color: var(--accent); background: var(--surface-2); }
.tile-link:focus-visible,
.bar-link:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
.bar-link { border-radius: 4px; }
.bar-link:hover { background: var(--surface-2); }
.bar-link:hover .bar-k { color: var(--accent); }

/* .spacer is scoped to the toolbar, so a card heading needs its own — without
   it the count runs straight into the title. */
.card h3 .spacer { margin-left: auto; }

/* Plate changes and the MOT timeline are multi-line records kept as text.
   They need to wrap and stay readable in a narrow panel without turning into
   a horizontal scrollbar. */
.wrap {
  margin: 0;
  font: inherit;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.45;
}

/* ---------------------------------------------------------------------------
   Access screen (/login)

   The only page with no app shell. The background is gunmetal in both themes —
   it is the outside of the building, not a surface — while the card follows the
   theme so it does not flare white on a dark desktop at night.
   --------------------------------------------------------------------------- */

/* The card carries its own tones rather than the app's surfaces. In dark it has
   to be lighter than the gunmetal it sits on, or it reads as a hole rather than
   something laid on top — and --surface is darker than gunmetal. The inputs
   stay a step below the card, recessed the way an input should be. */
.access {
  --card:        #ffffff;
  --card-input:  var(--surface-2);
  --card-border: var(--border);

  min-height: 100vh;
  background: var(--gunmetal);
  display: grid;
  place-items: center;
  padding: 24px;
}
:root[data-theme="dark"] .access {
  --card:        #2c333c;
  --card-input:  #21262d;
  --card-border: #3b434e;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .access {
    --card:        #2c333c;
    --card-input:  #21262d;
    --card-border: #3b434e;
  }
}

.access-card {
  /* 332 is the plate's own width plus the card's padding either side. The
     plate is fixed by the brand sheet and the card is not, so the card is what
     gives. */
  width: 332px;
  max-width: 100%;
  background: var(--card);
  border-radius: 10px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .4);
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* The form carries the fields but not the rhythm — display:contents lets the
   card's own gap space every child, plate to button, on one scale. */
.access-card form {
  display: contents;
}

/* The full plate, the one place it gets room to breathe. The card is sized to
   hold it: the plate is fixed by the brand sheet, so the box gives way. */
.access-plate {
  display: flex;
  justify-content: center;
  padding: 4px 0 2px;
}

.access-copy {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--text-muted);
  text-align: center;
}

.access-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.access-field label {
  font-size: var(--fs-dense);
  font-weight: var(--fw-medium);
  color: var(--text-muted);
}
.access-field input {
  padding: 8px 10px;
  border: 1px solid var(--card-border);
  border-radius: 5px;
  background: var(--card-input);
  color: var(--text);
  font-size: var(--fs-body);
}
.access-field input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}
/* The password reads as a stamped serial, spaced like one. */
.access-field input[type="password"] {
  font-family: var(--mono);
  letter-spacing: .22em;
}

.access-error {
  margin: 0;
  padding: 8px 10px;
  border-radius: 5px;
  background: var(--flag-crit-bg);
  color: var(--flag-crit);
  font-size: var(--fs-dense);
  line-height: 1.45;
}

.access-btn {
  padding: 9px 12px;
  border: 1px solid var(--accent);
  border-radius: 5px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  cursor: pointer;
}
.access-btn:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

/* ---------------------------------------------------------------------------
   Inspector's chalk

   A flagged record, marked the way a hand would mark it. Deliberately not wired
   to the flagged rows: the mark only carries weight while it is the only one on
   screen, and a table of flagged cars would print a dozen. Apply it by hand, to
   one thing, when one thing needs saying.
   --------------------------------------------------------------------------- */

.chalk {
  border: 1.6px solid var(--chalk);
  border-radius: 3px;
  padding: 2px 6px;
  transform: rotate(-2deg);
  display: inline-block;
}

/* ---------------------------------------------------------------------------
   The front page (CAR-633)

   The one page a stranger sees. Its own classes throughout, so nothing here
   leans on the app shell and the shell leans on nothing here. The top bar
   borrows the access screen's gunmetal; the rest sits on the ground colour
   in ordinary cards, and the plate is drawn once, in the hero, at full size.
   --------------------------------------------------------------------------- */

.front { margin: 0; background: var(--ground); color: var(--text); font-family: var(--ui); font-size: 15px; line-height: 1.55; }
.front-wrap { max-width: 1080px; margin: 0 auto; padding: 0 24px; }

.front-top { background: var(--gunmetal); color: #e8ebf0; }
.front-top-inner { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 52px; flex-wrap: wrap; }
.front-top-name { font-family: var(--mono); font-size: 12px; letter-spacing: .26em; color: #e8ebf0; text-decoration: none; white-space: nowrap; }
.front-nav { display: flex; gap: 18px; flex-wrap: wrap; }
.front-nav a { color: #b7bec8; text-decoration: none; font-size: 13px; }
.front-nav a:hover { color: #ffffff; }

.front-hero { background: var(--surface); border-bottom: 1px solid var(--border); }
.front-hero .front-wrap { display: grid; grid-template-columns: auto 1fr; gap: 40px; align-items: center; padding-top: 56px; padding-bottom: 48px; }
.front-hero h1 { margin: 0 0 14px; font-size: 38px; line-height: 1.12; letter-spacing: -.02em; font-weight: var(--fw-bold); max-width: 20ch; }
.front-lede { margin: 0; font-size: 17px; max-width: 58ch; color: var(--text-muted); }
.front-figures { display: flex; flex-wrap: wrap; gap: 28px; margin: 28px 0 0; padding: 0; }
.front-figures div { display: flex; flex-direction: column-reverse; gap: 2px; }
.front-figures dt { font-family: var(--mono); font-size: var(--fs-micro); letter-spacing: .14em; text-transform: uppercase; color: var(--text-faint); }
.front-figures dd { margin: 0; font-size: var(--fs-hero); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }

.front-section { padding: 48px 0 8px; }
.front-section h2 { margin: 0 0 6px; font-size: 26px; line-height: 1.2; letter-spacing: -.015em; font-weight: var(--fw-bold); }
.front-section > .front-wrap > p { margin: 0 0 22px; max-width: 64ch; color: var(--text-muted); }
.front-eyebrow { font-family: var(--mono); font-size: var(--fs-micro); letter-spacing: .14em; text-transform: uppercase; color: var(--text-faint); }
.front-note { font-size: 13px; color: var(--text-faint); max-width: 70ch; margin: 14px 0 0; }

.front-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.front-models { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.front-model { display: flex; flex-direction: column; }
.front-model-photo { aspect-ratio: 3 / 2; background: var(--surface-sunk); }
.front-model-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.front-model-body { padding: 18px 20px 20px; display: flex; flex-direction: column; gap: 8px; }
.front-model h3 { margin: 0; font-size: 21px; font-weight: var(--fw-medium); letter-spacing: -.01em; }
.front-model p { margin: 0; color: var(--text-muted); font-size: 14px; }
.front-model-figures { display: flex; gap: 24px; margin: 6px 0 0; padding: 12px 0 0; border-top: 1px solid var(--border); }
.front-model-figures div { display: flex; flex-direction: column-reverse; gap: 2px; }
.front-model-figures dt { font-size: 12px; color: var(--text-faint); }
.front-model-figures dd { margin: 0; font-size: 20px; font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }

.front-two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start; }
.front-list { margin: 0; padding: 20px 22px; list-style: none; display: flex; flex-direction: column; gap: 10px; }
.front-list li { padding-left: 18px; position: relative; }
.front-list li::before { content: ""; position: absolute; left: 0; top: .62em; width: 8px; height: 8px; border-radius: 2px; background: var(--accent); }
.front-list strong { font-weight: var(--fw-medium); }

/* One record, typed in by hand with no plate and no VIN: the shape of an
   entry, not a door to one. */
.front-record { padding: 18px 22px 20px; }
.front-record-head { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; margin-bottom: 12px; }
.front-record-head h3 { margin: 0; font-size: 18px; font-weight: var(--fw-medium); }
.front-record dl { margin: 0; display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 7px 16px; font-size: 14px; }
.front-record dt { color: var(--text-faint); }
.front-record dd { margin: 0; }

.front-list-solo { max-width: 680px; }

.front-plans { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; }
.front-plan { padding: 20px 22px 22px; display: flex; flex-direction: column; gap: 8px; }
.front-plan + .front-plan { border-left: 1px solid var(--border); }
.front-plan h3 { margin: 0; font-size: 18px; font-weight: var(--fw-medium); }
.front-plan p { margin: 0; color: var(--text-muted); font-size: 14px; }
.front-plan ul { margin: 4px 0 0; padding-left: 18px; color: var(--text); font-size: 14px; display: flex; flex-direction: column; gap: 5px; }
.front-plans-foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 16px 22px; border-top: 1px solid var(--border); background: var(--surface-2); }
.front-btn { display: inline-block; padding: 9px 14px; border: 1px solid var(--accent); border-radius: 5px; background: var(--accent); color: var(--on-accent); font-size: 14px; font-weight: var(--fw-medium); text-decoration: none; }
.front-btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.front-plans-foot span { font-size: 13px; color: var(--text-muted); }

.front-sources { padding: 20px 22px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 24px; font-size: 14px; }
.front-sources div strong { display: block; font-weight: var(--fw-medium); }
.front-sources div span { color: var(--text-muted); }

/* The sign-in box: the access card, at the foot of the page instead of alone
   on gunmetal. The fields and the button are the card's own rules, which
   read their colours from the three variables the old full-screen wrapper
   used to set; here the page's tokens set them, so the card follows the
   theme like everything else on the page. */
.front-signin { padding: 48px 0 56px; }
.front-signin .access-card {
  --card:        var(--surface);
  --card-input:  var(--surface-2);
  --card-border: var(--border);

  width: 100%;
  max-width: 420px;
  box-shadow: none;
  border: 1px solid var(--border);
}
.front-signin .access-card form { display: contents; }

/* The register-your-interest page: one short column, one card, one email. */
.front-interest { padding-bottom: 56px; }
.front-interest .front-wrap { max-width: 640px; }
.front-interest-card { padding: 20px 22px; display: flex; flex-direction: column; gap: 10px; font-size: 14px; }
.front-interest-card p, .front-interest-card ul { margin: 0; }
.front-interest-card ul { padding-left: 18px; display: flex; flex-direction: column; gap: 6px; }
.front-interest-card .front-btn { align-self: flex-start; margin-top: 6px; }
.front-note a { color: var(--accent); }
/* The form (CAR-639): the access card's own fields, plus a select, a textarea
   and two rows of tick boxes. The honeypot sits off the page where only a
   script fills it in. */
.front-form { gap: 14px; }
.front-form .access-field { gap: 6px; }
.front-form .access-field label { font-size: var(--fs-dense); font-weight: var(--fw-medium); color: var(--text-muted); }
.front-form .access-field input, .front-form .access-field select, .front-form .access-field textarea {
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 5px;
  background: var(--surface-2); color: var(--text); font: inherit; font-size: var(--fs-body); width: 100%;
}
.front-form .access-field textarea { resize: vertical; min-height: 72px; }
.front-form .access-field input:focus-visible, .front-form .access-field select:focus-visible,
.front-form .access-field textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.front-choices { border: 0; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 18px; }
.front-choices legend { font-size: var(--fs-dense); font-weight: var(--fw-medium); color: var(--text-muted); padding: 0; margin-bottom: 6px; width: 100%; }
.front-choices label { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; }
.front-form .access-btn { align-self: flex-start; }
.front-form-note { margin: 2px 0 0; font-size: 12.5px; color: var(--text-faint); }
.front-form-note a { color: var(--accent); }
.front-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* The privacy notice: one readable column, headed sections, nothing else. */
.front-prose { padding-bottom: 56px; }
.front-prose .front-wrap { max-width: 720px; }
.front-prose h3 { margin: 26px 0 6px; font-size: 17px; font-weight: var(--fw-medium); letter-spacing: -.01em; }
.front-prose p, .front-prose li { font-size: 15px; line-height: 1.6; }
.front-prose .front-wrap > p { margin: 0 0 10px; color: var(--text); max-width: none; }
.front-prose ul { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 10px; }
.front-prose a { color: var(--accent); }

.front-foot { background: var(--gunmetal); color: #b7bec8; font-size: 13px; }
.front-foot .front-wrap { display: flex; flex-wrap: wrap; gap: 8px 22px; padding: 18px 24px; }
.front-foot a { color: #e8ebf0; text-decoration: none; }
.front-foot a:hover { text-decoration: underline; }

@media (max-width: 760px) {
  .front-hero .front-wrap { grid-template-columns: 1fr; gap: 28px; padding-top: 36px; padding-bottom: 36px; }
  .front-hero h1 { font-size: 30px; }
  .front-models, .front-two, .front-plans, .front-sources { grid-template-columns: 1fr; }
  .front-plan + .front-plan { border-left: 0; border-top: 1px solid var(--border); }
  .front-record dl { grid-template-columns: 1fr; gap: 2px; }
  .front-record dt { margin-top: 8px; }
}

/* ---------------------------------------------------------------------------
   Phone layout

   This block stays at the END of the file. Its selectors match base rules of
   equal specificity — a media query adds none — so source order is the only
   thing that makes these overrides win. When the block sat near the top, the
   topbar height and search width below quietly lost to the base rules, the
   topbar stayed 48px tall while its contents wrapped past 90px, and the
   toolbar painted over the tabs and the search box (CAR-228).

   On a phone the sidebar becomes a drawer behind the menu button, instead of
   being hidden outright — hiding it took the saved views, the model scopes and
   sign-out with it (CAR-102). The view tabs keep to one row and scroll
   sideways rather than wrapping; the search and + New sale take the second
   row. The cars grid keeps its own horizontal scroll — that one is deliberate.
   --------------------------------------------------------------------------- */

@media (max-width: 820px) {
  .app { grid-template-columns: minmax(0, 1fr); }
  .icon-btn.nav-btn { display: grid; }
  .sidebar {
    position: fixed;
    top: 0; bottom: 0; left: 0;
    z-index: 66;
    width: min(280px, 84vw);
    transform: translateX(-105%);
    transition: transform .16s ease-out;
    box-shadow: var(--shadow-panel);
  }
  body.nav-open .sidebar { transform: none; }
  .topbar {
    height: auto;
    min-height: var(--topbar-h);
    flex-wrap: wrap;
    padding: 6px 12px;
  }
  .view-tabs {
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .view-tabs::-webkit-scrollbar { display: none; }
  .tab { flex: none; }
  .topbar-right { flex: 1 1 100%; }
  .search { flex: 1; }
  .search input { width: 100%; min-width: 120px; }
  /* The toolbar scrolls sideways at this width, so the count is already the
     last thing to reach. The register total is context rather than the
     answer, and it is the half to drop (CAR-99). */
  .record-count .tail { display: none; }
}

/* Fingers are wider than pointers: on a screen without hover the tabs grow to
   Apple's 44px touch target. */
@media (pointer: coarse) {
  .tab { padding: 11px 12px; }
}

/* --- a car's own page (CAR-241, redrawn on CAR-323) ------------------------
   One card style for everything, from the handoff under
   design_spec/design_handoff_car_page_pdf: white cards on the ground, a
   mono micro-label on each, the story down the left and the facts down the
   right in a single rule-divided card. No pills, ticks or crosses here — a
   state is a word with a dot beside it, and a plate is a chip. The sidebar's
   entries and the tabs are links now, so they are told to look as they did
   as buttons. */
a.tab, a.side-item { text-decoration: none; color: inherit; }
.side-item[aria-disabled="true"] { opacity: .4; cursor: default; }
.side-item[aria-disabled="true"]:hover { background: transparent; color: var(--text-muted); }

.car-page {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 28px 24px 80px;
  background: var(--ground);
  scrollbar-width: thin;
}
.car-wrap { max-width: 1160px; margin: 0 auto; display: flex; flex-direction: column; gap: 20px; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.sec-card { padding: 20px 22px; display: flex; flex-direction: column; gap: 14px; }
.card-label {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.card-label .spacer { flex: 1; }
.card-count { letter-spacing: 0; text-transform: none; color: var(--text-faint); }

/* The brand's three colours, as a bar across the top of the header card. */
.tri-bar { display: flex; height: 4px; }
.tri-bar span { flex: 1; }
.tri-bar span:nth-child(1) { background: var(--tri-sky); }
.tri-bar span:nth-child(2) { background: var(--tri-navy); }
.tri-bar span:nth-child(3) { background: var(--tri-red); }

.car-head { overflow: hidden; }
.car-head-inner {
  padding: 22px 26px 24px;
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  justify-content: space-between;
  align-items: flex-start;
}
.car-title { display: flex; flex-direction: column; gap: 10px; min-width: 260px; flex: 1 1 320px; }
.car-crumbs { display: flex; align-items: baseline; gap: 14px; font-family: var(--mono); font-size: 12px; }
.car-back { color: var(--text-faint); text-decoration: none; }
.car-back:hover { color: var(--text); }
.car-model { letter-spacing: .14em; text-transform: uppercase; color: var(--accent); text-decoration: none; }
.car-model:hover { color: var(--accent-hover); }
/* Previous and next car in the run the Cars page was showing (CAR-329):
   two arrows and "12 of 461", in the crumbs' own mono. The sale form's
   header uses the same for the sales list it was opened from (CAR-345). */
.car-run { display: inline-flex; align-items: baseline; gap: 6px; color: var(--text-faint); }
.car-run-step { color: var(--text-muted); text-decoration: none; font-size: 16px; line-height: 1; padding: 0 4px; border-radius: 4px; }
.car-run-step:hover { color: var(--text); background: var(--row-hover); }
.car-run-step.is-end { opacity: .35; pointer-events: none; }
.car-run-pos { font-size: 11px; letter-spacing: .04em; }
/* The page's own name, and on a car's page that is its VIN — the one thing
   on the header a person is checking they are on the right car, so it carries
   the weight (CAR-459). The mono has no bold, so the browser smeared one
   together; the grotesk has a real one, and a VIN never uses the I, O or Q
   the mono is there to tell apart (CAR-532). */
.car-title .vin {
  margin: 0;
  font-family: var(--ui);
  font-variant-numeric: tabular-nums;
  font-size: clamp(22px, 3.5vw, 32px);
  font-weight: var(--fw-bold);
  letter-spacing: .04em;
  word-break: break-all;
}
/* A car's page names the car the way the register does (CAR-587): the model
   and its plate as the heading, and one line beneath saying what the car is
   and where it stands (CAR-602). The plate chip is the mark a person looks
   for first. */
.car-title .car-name {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  font-family: var(--ui);
  font-size: clamp(22px, 3.2vw, 30px);
  line-height: 1.1;
  font-weight: var(--fw-bold);
  letter-spacing: .01em;
}
.chip-plate-xl { padding: 3px 11px; border-radius: 6px; font-size: clamp(18px, 2.5vw, 24px); letter-spacing: .06em; }
/* What the car is and where it stands, as one line in one style: the VIN,
   the colour, then the states as pills. No separators; the swatch and the
   pills mark where each item starts (CAR-602). */
.car-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; font-size: 14px; color: var(--text-muted); }
.car-line .car-vin { font-family: var(--ui); letter-spacing: .04em; font-variant-numeric: tabular-nums; }
.car-line .car-status { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* The line under the name: colour, and every condition true of the car.
   The colour's swatch and a condition's dot are the same size and sit the same
   distance from their word, because they are the same kind of thing — a mark
   and what it means. They were 14px and 7px, and the row read as two rows
   (CAR-459). */
.car-ident { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.car-colour { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; color: var(--text-muted); }
.car-colour .swatch { width: 11px; height: 11px; border-radius: 3px; margin: 0; }
.mot-state { margin: 0 0 10px; padding: 8px 10px; border-radius: 5px; border-left: 3px solid var(--flag-warn); background: var(--flag-warn-bg); color: var(--text); }
.mot-state-question { border-left-color: var(--flag-crit); background: var(--flag-crit-bg); }
.mot-state a { color: inherit; }

/* Where the car stands, as pills at the end of the header's line (CAR-587,
   CAR-602): a state in its colour with what the pill cannot say beside it,
   then the market when there is one. Pill text is 13px, a touch under the
   line's 14px, so the pills don't outweigh it. Desirable is green with
   Clean: nothing is against the car, and its star tells the two apart. */
.status-item { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; min-width: 0; }
.status-chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 3px 11px 3px 9px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: var(--fw-medium);
  white-space: nowrap;
  background: var(--surface-sunk);
  color: var(--text);
}
.status-chip b { font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; color: var(--text); }
.status-ico { width: 12px; height: 12px; flex: none; }
.status-good, .status-star { background: var(--flag-good-bg); color: var(--flag-good); }
.status-for_sale { background: var(--sale-bg); color: var(--sale); }
.status-warn { background: var(--flag-warn-bg); color: var(--flag-warn); }
.status-crit { background: var(--flag-crit-bg); color: var(--flag-crit); }
.status-sub { font-size: 14px; color: var(--text-muted); }
.status-sub a { color: inherit; text-decoration: none; }
.status-sub a:hover { color: var(--text); text-decoration: underline; }

/* The header's buttons: ghost in mono, the primary in ink. */
.car-actions { align-items: flex-start; }
.car-actions .btn {
  font-family: var(--mono);
  font-size: 12px;
  padding: 7px 13px;
  border-radius: 6px;
  border-color: var(--border-strong);
  color: var(--text);
  text-decoration: none;
}
.car-actions .btn:hover { background: var(--row-hover); }
.car-actions .btn-primary { background: var(--ink); border-color: var(--ink); color: var(--surface); }
.car-actions .btn-primary:hover { background: var(--text-muted); border-color: var(--text-muted); }
/* Share, Refresh and Edit: in the row on a wide screen, behind ⋯ on a phone
   (CAR-602). */
.car-more, .car-more-items { display: contents; }
.car-more-btn { display: none; }

/* A state as a word with a dot beside it. */
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); flex: none; }
.dot-good { background: var(--flag-good); }
.dot-warn { background: var(--flag-warn); }
.dot-wait { background: var(--flag-warn); }
.dot-crit { background: var(--flag-crit); }
.dot-accent { background: var(--accent); }
.dot-fail { background: var(--tri-red); width: 8px; height: 8px; }
.dot-odd { background: var(--surface); border: 1.5px solid var(--ink); width: 8px; height: 8px; box-sizing: border-box; }
.dot-sale { background: var(--tri-sky); }
.dot-dealer { background: var(--surface); border: 2px solid var(--tri-sky); width: 8px; height: 8px; box-sizing: border-box; }
.status-word { display: inline-flex; align-items: center; gap: 7px; }

/* A plate as a chip: the current one in the plate's own yellow, an earlier
   one in grey. The yellow is never themed (see :root). */
.chip-plate {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: 4px;
  background: var(--plate-yellow);
  border: 1px solid var(--plate-edge);
  color: var(--plate-ink);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .04em;
  white-space: nowrap;
}
.chip-plate-lg { padding: 3px 10px; border-radius: 5px; font-size: 15px; letter-spacing: .06em; }
.chip-plate-old { background: var(--surface-sunk); border-color: var(--border-strong); color: var(--text-muted); }

/* Two columns that wrap to one: the story wider than the facts. */
.car-body { display: flex; flex-wrap: nowrap; gap: 20px; align-items: flex-start; }
.car-story { flex: 1.63 1 460px; min-width: 0; display: flex; flex-direction: column; gap: 20px; }
/* The right column: the facts card, and the factory build sheet under it
   (CAR-467). The wrapper carries the width so the two stack the way the
   left column's cards do. */
.car-side { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 20px; }
.car-facts { min-width: 0; padding: 6px 22px; }
.facts-sec { padding: 16px 0 14px; border-bottom: 1px solid var(--row-rule); }
.facts-sec:last-child { border-bottom: 0; padding-bottom: 18px; }
.facts-sec .card-label { margin-bottom: 10px; }
.kv-rows { display: flex; flex-direction: column; gap: 8px; font-size: 13.5px; }
.kv-row { display: flex; justify-content: space-between; align-items: center; gap: 16px; }
.kv-row .k { color: var(--text-muted); flex: none; }
.kv-row .v { flex: 1 1 auto; text-align: right; min-width: 0; word-break: break-word; }
.kv-row .v.mono { font-family: var(--mono); font-size: 12.5px; }
.kv-prose { flex-direction: column; align-items: stretch; gap: 4px; }
.kv-prose .v { text-align: left; white-space: pre-wrap; line-height: 1.5; }
/* A figure with a source behind it (CAR-698): dotted beneath, and a tap
   opens the muted line under the row that says where it came from. The
   button unsets its chrome and keeps the row's own .v rules. */
/* How fresh a row's source is (CAR-738): one word beside the value. */
.fresh-mark { margin-left: 6px; vertical-align: 1px; white-space: nowrap; }
/* A reading's source and the day it was true, quiet under its value; the
   warning colour once the source is past its window (CAR-796). A row with
   a line sits on its first line, not its middle. */
.kv-row:has(.src) { align-items: flex-start; }
.kv-row .src { display: block; margin-top: 1px; font-size: var(--fs-micro); color: var(--text-faint); }
.kv-row .src.is-old { color: var(--flag-warn); }
/* The two "checked" dates are about the register, not the car: one muted
   line at the foot of the facts card. */
.plate-rows { gap: 9px; font-size: var(--fs-body); }
.muted { color: var(--text-muted); }
.is-pass { color: var(--flag-good); }
.is-fail { color: var(--fail-text); }
.is-warn { color: var(--flag-warn); }
.car-facts .prose { font-size: 13.5px; line-height: 1.5; white-space: pre-wrap; }
.car-facts .none-yet { padding: 4px 0 0; text-align: left; font-size: 13.5px; }
/* The notes are edited where they are read (CAR-652): the text is a
   button that opens a box in its place. */
.notes-view { all: unset; display: block; cursor: text; border-radius: 6px; margin: -4px -6px; padding: 4px 6px; }
.notes-view:hover, .notes-view:focus-visible { background: var(--surface-2); }
.notes-view:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.notes-view .v { display: block; text-align: left; white-space: pre-wrap; line-height: 1.5; }
.notes-edit .textarea { width: 100%; min-height: 110px; box-sizing: border-box; }
.notes-btns { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }

/* Photos: the lead across the card at 16:9, the rest at 4:3 below, reports
   as chips in a row with the way to add more beside them. The whole card is
   the drop target (CAR-17); .over is the class app.js sets while a file is
   held over it. */
.photo-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.photo-grid:empty { display: none; }
.photo-grid .shot-wrap { display: block; aspect-ratio: 4 / 3; }
.photo-grid .photo-lead { grid-column: 1 / -1; aspect-ratio: 16 / 9; }
.photo { display: block; width: 100%; height: 100%; border-radius: 8px; overflow: hidden; background: var(--surface-sunk); }
.photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo img.portrait { object-fit: contain; }

/* The photos one at a time (CAR-328): the picture over a dark ground, an
   arrow either side, the count and the file's name under it. */
.lightbox {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10, 12, 16, .92);
}
.lightbox[hidden] { display: none; }
body.lb-open { overflow: hidden; }
.lb-figure { margin: 0; max-width: calc(100vw - 120px); max-height: 100vh; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.lb-figure img { max-width: 100%; max-height: calc(100vh - 80px); object-fit: contain; display: block; border-radius: 4px; background: #000; }
.lb-cap { display: flex; gap: 14px; align-items: baseline; font-family: var(--mono); font-size: 12px; color: #c9ced6; }
.lb-cap a { color: #c9ced6; text-decoration: underline; text-underline-offset: 2px; }
.lb-cap a:hover { color: #fff; }
.lb-btn {
  position: absolute; border: 0; background: rgba(255, 255, 255, .08); color: #fff;
  width: 44px; height: 44px; border-radius: 50%; font-size: 26px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.lb-btn:hover { background: rgba(255, 255, 255, .18); }
.lb-btn[hidden] { display: none; }
.lb-close { top: 16px; right: 16px; font-size: 16px; }
.lb-prev { left: 16px; top: 50%; transform: translateY(-50%); }
.lb-next { right: 16px; top: 50%; transform: translateY(-50%); }
@media (max-width: 820px) {
  .lb-figure { max-width: 100vw; }
  .lb-figure img { max-height: calc(100vh - 110px); border-radius: 0; }
  .lb-prev, .lb-next { top: auto; bottom: 14px; transform: none; }
  .lb-cap { flex-wrap: wrap; justify-content: center; padding: 0 70px; text-align: center; }
}
.report-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.report-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 14px;
  font-size: var(--fs-body);
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
}
.report-chip:hover { border-color: var(--border-strong); }
.report-tag {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  background: var(--surface-sunk);
  border-radius: 4px;
  padding: 2px 6px;
  color: var(--text-muted);
  flex: none;
}
.report-chip .report-name { overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }
.drop-hint {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-faint);
  cursor: pointer;
  padding: 4px 0;
}
.drop-hint:hover { color: var(--accent); }
#photosCard.over { border-color: var(--accent); background: var(--accent-soft); }
#photosCard.busy { opacity: .7; cursor: progress; }
.report-row .shot-x { top: 50%; transform: translateY(-50%); right: -8px; }

/* The MOT chart (CAR-143, redrawn on CAR-323): the line from registration,
   the area under it in the brand's sky, a failed test as a red dot. */
.mot-chart { display: block; width: 100%; height: auto; }
.mot-chart .mot-grid { stroke: var(--row-rule); stroke-width: 1; }
.mot-chart .mot-base { stroke: var(--border); stroke-width: 1; }
.mot-chart .mot-area { fill: var(--tri-sky); fill-opacity: .12; }
.mot-chart .mot-line { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; }
.mot-chart .mot-pt { fill: var(--ink); }
.mot-chart .mot-pt-fail { fill: var(--tri-red); }
.mot-chart .mot-pt-odd { fill: var(--surface); stroke: var(--ink); stroke-width: 1.5; }
/* A sale's reading and the dealer's, off the line (CAR-690). */
.mot-chart .mot-pt-sale { fill: var(--tri-sky); }
.mot-chart .mot-pt-dealer { fill: var(--surface); stroke: var(--tri-sky); stroke-width: 2; }
.mot-chart .mot-text { fill: var(--text-faint); font-size: 10px; font-family: var(--mono); }
.chart-legend { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-faint); }

/* Where a car's mileage sits in its model (CAR-799), drawn by
   _model_charts.html for this page and the record sheet; record.css styles
   the same names for paper. One line high: the quarters as a track, the
   car's quarter shaded, the car a dot. */
.mstrip { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.mstrip-head { display: flex; justify-content: space-between; gap: 12px; font-size: 13.5px; }
.mstrip-q { color: var(--text-muted); text-align: right; }
.mstrip-track { position: relative; height: 14px; margin: 4px 0 0; }
.mstrip-seg { position: absolute; top: 4px; height: 6px; background: var(--border-strong); border-left: 2px solid var(--surface); }
.mstrip-seg:first-child { border-left: 0; border-radius: 3px 0 0 3px; }
.mstrip-seg:nth-child(4) { border-radius: 0 3px 3px 0; }
.mstrip-seg.is-this { background: var(--chart-1); }
.mstrip-dot { position: absolute; top: 0; width: 14px; height: 14px; margin-left: -7px; border-radius: 50%;
  background: var(--tri-red); border: 2px solid var(--surface); }
.mstrip-scale { display: flex; justify-content: space-between; font-family: var(--mono); font-size: 10px; color: var(--text-faint); }
.mchart-caption { font-size: 12.5px; color: var(--text-faint); line-height: 1.5; }

/* The tables: mono uppercase headers, hairline row rules, numbers right in
   mono, and room on the right of every cell so columns never abut. */
.table-scroll { overflow-x: auto; }
.car-table { border-collapse: collapse; width: 100%; font-size: 13.5px; }
.car-table th {
  text-align: left;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: var(--fw-normal);
  padding: 6px 14px 6px 0;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.car-table td { padding: 8px 14px 8px 0; border-bottom: 1px solid var(--row-rule); vertical-align: top; }
.car-table tr:last-child td { border-bottom: 0; }
/* Figures in the page's own face with tabular digits, not the mono: the
   date, the mileage and the price on one row read as one table rather than
   two typefaces side by side (CAR-331). The mono is for identifiers — the
   VIN, the plates, the engine number — and for labels. */
.car-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.car-table .when { font-variant-numeric: tabular-nums; white-space: nowrap; }
.car-table .act { padding-right: 0; width: 1%; }
.car-table tr[data-href] { cursor: pointer; }
/* On a phone a sale is two lines, the date, status and price, then the
   seller and the mileage, so the price never falls off the edge (CAR-801). */
@media (max-width: 560px) {
  .sales-table thead { display: none; }
  .sales-table tr { display: grid; grid-template-columns: auto 1fr auto auto; column-gap: 10px; row-gap: 2px;
    padding: 8px 0; border-bottom: 1px solid var(--row-rule); }
  .sales-table tr:last-child { border-bottom: 0; }
  .sales-table td { padding: 0; border: 0; }
  .sales-table td:nth-child(1) { grid-area: 1 / 1; }
  .sales-table td:nth-child(2) { grid-area: 1 / 2; }
  .sales-table td:nth-child(5) { grid-area: 1 / 3 / 2 / 5; }
  .sales-table td:nth-child(3) { grid-area: 2 / 1 / 3 / 3; color: var(--text-muted); }
  .sales-table td:nth-child(4) { grid-area: 2 / 3; color: var(--text-muted); }
  .sales-table td:nth-child(6) { grid-area: 2 / 4; }
}
/* Why a test failed, under its row (CAR-333): the tester's words, small. */
.car-table tr.mot-why td { padding-top: 0; padding-bottom: 10px; border-bottom: 1px solid var(--row-rule); }
.car-table tr.mot-why + tr td { border-top: 0; }
.mot-reasons { margin: 0; padding: 0 0 0 14px; font-size: var(--fs-dense); color: var(--text-muted); line-height: 1.45; }
.mot-reasons li { margin: 0; }
.car-table .advert-link { font-family: var(--mono); font-size: 11px; }
.car-table .row-edit { font-family: var(--mono); }
.car-table tr:hover .row-edit { opacity: 1; }
.car-page .card-note { margin: 0; }

/* The audit trail: a mono date, then what changed and by whom, one line
   per entry — from car_audit (CAR-19), as what changed (CAR-294). */
.history { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: var(--fs-body); }
.history > li { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
.history-when { font-family: var(--mono); font-size: 11px; color: var(--text-faint); min-width: 88px; }
.history-body { min-width: 0; }
.history-change { margin-right: 10px; word-break: break-word; }
.history-old { color: var(--text-faint); }
.history-subject { font-weight: 600; margin-right: 6px; }
.history-who { color: var(--text-faint); }
/* The trail is folded behind its title (CAR-365): the count shows either
   way, the caret says which way it is. */
.history-box > summary { cursor: pointer; list-style: none; }
.history-box > summary::-webkit-details-marker { display: none; }
.history-box[open] > summary { margin-bottom: 14px; }
.history-box .card-note { margin: 12px 0 0; }
.history-caret::before { content: "\203A"; display: inline-block; font-size: 15px; line-height: 1; color: var(--text-faint); transition: transform .15s; }
.history-box[open] .history-caret::before { transform: rotate(90deg); }
.link-btn { align-self: flex-start; border: 0; background: none; padding: 0; font-family: var(--mono); font-size: 11px; color: var(--accent); cursor: pointer; }
.link-btn:hover { color: var(--accent-hover); }

/* The Sources page (CAR-366): the four cards in two columns on a wide
   screen and one on a phone, each a section card like the car page's. The
   spend table right-aligns its figures, and the daily cap sits beside
   today's in the faint colour the dashboard uses for a share. */
.sources-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: 20px; }
/* The source's name reads like a model's title (Paul, 20 October 2026), and
   what it has left, or what the trickle is doing, is the one figure on the
   card worth a glance, so it carries the weight; the date beside the name
   and the muted notes stay as the other cards have them. */
.source-card .card-label { align-items: baseline; }
.source-card .source-name { font-family: var(--ui); font-size: 22px; font-weight: var(--fw-bold); letter-spacing: .04em; text-transform: none; color: var(--text); }
.source-card .source-balance { font-size: 16px; font-weight: var(--fw-medium); }
.source-card .source-balance .muted { font-size: var(--fs-body); font-weight: var(--fw-normal); }
.source-card .kv-rows { font-size: var(--fs-body); }
.spend-table { font-size: var(--fs-body); }
.spend-table th.n, .spend-table td.n { text-align: right; padding-right: 0; white-space: nowrap; font-variant-numeric: tabular-nums; }
.spend-table td.n .pc { margin-left: 6px; }
.spend-table td:first-child { color: var(--text-muted); }
.source-form .move-actions { align-items: center; }
.source-form .move-actions .hint { margin: 0; }
.source-form .move-actions .spacer { flex: 1; }
@media (max-width: 460px) { .sources-grid { grid-template-columns: minmax(0, 1fr); } }

/* A phone reads one column, in the CAR-195 order: what it looks like, which
   car it is, what it has done and sold for, then the reference detail. The
   facts card steps aside and each of its sections becomes a card. */
@media (max-width: 999px) {
  .car-page { padding: 14px 12px 40px; }
  .car-body, .car-story, .car-side { display: contents; }
  .car-facts { display: contents; }
  .car-wrap > .car-body .facts-sec {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 20px 22px;
  }
  .car-body .o1 { order: 1; } .car-body .o2 { order: 2; } .car-body .o3 { order: 3; }
  .car-body .o4 { order: 4; } .car-body .o5 { order: 5; } .car-body .o6 { order: 6; }
  .car-body .o7 { order: 7; } .car-body .o8 { order: 8; } .car-body .o9 { order: 9; }
  .car-body .o10 { order: 10; } .car-body .o11 { order: 11; } .car-body .o12 { order: 12; }
  .car-body .o13 { order: 13; } .car-body .o14 { order: 14; }
  .car-head-inner { padding: 18px 18px 20px; }
}
/* On a phone the header's buttons share the width rather than running off
   the screen (CAR-587): + Sale and PDF sheet, with Share, Refresh and Edit
   behind ⋯, in one row of 44px targets (CAR-602). */
@media (max-width: 640px) {
  .car-line { gap: 6px 16px; font-size: 13.5px; }
  /* The ⋯ menu hangs below the card, so the card lets it out and the bar
     keeps the card's rounded top on its own. */
  .car-head { overflow: visible; }
  .car-head .tri-bar { border-radius: 11px 11px 0 0; overflow: hidden; }
  .car-actions { flex: 1 1 100%; flex-wrap: nowrap; margin-left: 0; gap: 8px; }
  .car-actions .btn { height: 44px; justify-content: center; }
  .car-sale { order: 1; flex: 1 1 0; }
  .car-pdf { order: 2; flex: 1 1 0; }
  .car-more { order: 3; display: block; position: relative; flex: none; }
  .car-more-btn { display: inline-flex; width: 44px; padding: 0; }
  .car-more-items {
    display: none; position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
    min-width: 180px; padding: 6px; flex-direction: column; gap: 4px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow-pop);
  }
  .car-more.is-open .car-more-items { display: flex; }
  .car-more-items .btn { width: 100%; justify-content: flex-start; border-color: transparent; }
}
}

/* --- table, tiles or list (CAR-242) ---------------------------------------- */
.show-btns { display: inline-flex; gap: 0; }
.show-btns .btn { border-radius: 0; margin-left: -1px; }
.show-btns .btn:first-child { border-radius: 4px 0 0 4px; margin-left: 0; }
.show-btns .btn:last-child { border-radius: 0 4px 4px 0; }
.show-btns .btn[aria-pressed="true"] { background: var(--row-selected); color: var(--text); }

@media (max-width: 820px) {
  .show-btns .btn { padding: 6px 10px; }
}

/* A sale's address, on its form (CAR-243). */
.sale-link { color: var(--accent); text-decoration: none; }
.sale-link:hover { text-decoration: underline; }

/* --- the model page (CAR-244) ----------------------------------------- */
.dash-about { margin-left: auto; align-self: center; color: var(--accent); font-size: var(--fs-dense); text-decoration: none; padding: 0 8px; }
.dash-about:hover { text-decoration: underline; }
.tiles-page { padding: 0; }
.model-page .car-title .model-line { margin-bottom: 3px; }
.model-line a { color: inherit; text-decoration: none; }
.model-line a:hover { text-decoration: underline; }
.bars a.bar-row { color: inherit; text-decoration: none; }

/* A seller's name leads to their sales (CAR-245). */
.seller-link { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--border-strong); }
.seller-link:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* Resolving a review item happens on the page (CAR-194). */
.review-car { font-family: var(--mono); color: inherit; text-decoration: none; border-bottom: 1px dotted var(--border-strong); }
.review-car:hover { color: var(--accent); border-bottom-color: var(--accent); }
.review-evidence { margin-top: 4px; }
.review-evidence summary { cursor: pointer; color: var(--text-faint); font-size: var(--fs-micro); }
/* The cars a source has not spoken for, under its card on the Sources page
   (CAR-767): one line per model, folded away behind the summary. */
.coverage-box { margin-top: 10px; }
.coverage-list { list-style: none; margin: 8px 0 0; padding: 0; font-size: 13px; line-height: 1.6; }
.review-evidence pre { margin: 4px 0 0; font-family: var(--mono); font-size: var(--fs-micro); color: var(--text-muted); white-space: pre-wrap; }
.review-form-row td { background: var(--surface-2); }
.review-form { display: flex; flex-direction: column; gap: 6px; max-width: 640px; }
.review-form-actions { display: flex; gap: 6px; }

/* What a refresh just wrote, lit for a moment (CAR-261). */

/* A sale's id is an identifier, wherever it is shown (type audit, CAR-251). */
.sale-link { font-family: var(--mono); }

/* --- a run's cars (CAR-276) ------------------------------------------------
   What happened to each car a refresh changed or refused, in the run's own
   words. A native dialog, so Escape and the backdrop come for free; it
   borrows the modal's head and body. */
.run-cars {
  width: min(820px, calc(100vw - 24px));
  max-height: min(88vh, 820px);
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-panel);
}
.run-cars[open] { display: flex; flex-direction: column; }
.run-cars::backdrop { background: rgba(0, 0, 0, .35); }
.run-cars .modal-head .spacer { margin-left: auto; }
.run-cars h3 { margin: 4px 0 6px; font-size: var(--fs-dense); color: var(--text-muted); font-weight: var(--fw-medium); }
.run-cars h3 + ol { margin-bottom: 14px; }
.run-cars ol { list-style: none; margin: 0; padding: 0; }
.run-cars li {
  display: grid;
  grid-template-columns: 11em minmax(0, 1fr);
  gap: 10px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-dense);
}
.run-cars li:last-child { border-bottom: 0; }
.run-cars .run-car-who { font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 560px) {
  .run-cars li { grid-template-columns: minmax(0, 1fr); gap: 2px; }
}

/* Sortable headings on a summary table (the Sellers page, CAR-279): the
   grid's button, in the summary heading's clothes. */
.dash-table th .th-btn {
  width: auto; height: auto; padding: 0;
  text-transform: inherit; letter-spacing: inherit; color: inherit; font-size: inherit;
}
.dash-table th .th-btn:hover { background: transparent; color: var(--text); }
.dash-table th .th-num { justify-content: flex-start; }

/* --- a model's story and its press photographs (CAR-398) --------------- */
/* The same shape as its page in the record sheet: the opening paragraph,
   two columns of sections, the quotes in a band, the photographs last. */
.profile { display: flex; flex-direction: column; gap: 18px; }
.profile-stand { margin: 0; font-size: 15px; line-height: 1.55; max-width: 66ch; }
.profile-grid { display: grid; grid-template-columns: 1.18fr 1fr; gap: 28px; }
.profile-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.profile-label {
  font-family: var(--mono);
  font-size: var(--fs-micro);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.profile-p { margin: 0; font-size: var(--fs-body); line-height: 1.6; max-width: 70ch; }
.profile-kv { grid-template-columns: 100px minmax(0, 1fr); }
.profile-quotes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; }
.profile-quote { margin: 0; display: flex; flex-direction: column; gap: 8px; }
.profile-quote p { margin: 0; font-size: var(--fs-body); line-height: 1.5; }
.profile-quote cite {
  font-style: normal;
  font-family: var(--mono);
  font-size: var(--fs-micro);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted);
  line-height: 1.5;
  border-top: 1px solid var(--border);
  padding-top: 7px;
}
.profile-quote cite span { display: block; color: var(--text-faint); }
@media (max-width: 760px) {
  .profile-grid, .profile-quotes { grid-template-columns: minmax(0, 1fr); }
}

/* Press photographs sit two across at 3:2, a caption line under each. */
.press-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.press-grid .shot-wrap { display: flex; flex-direction: column; gap: 6px; aspect-ratio: auto; margin: 0; }
.press-shot .photo { display: block; aspect-ratio: 3 / 2; overflow: hidden; border-radius: 8px; background: var(--surface-sunk); }
.press-shot .photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.press-shot figcaption { margin: 0; }
.press-caption { width: 100%; }
.press-caption[aria-invalid="true"] { border-color: var(--flag-warn, var(--border-strong)); }
.model-photos .drop-hint { display: block; margin-top: 10px; }
@media (max-width: 560px) { .press-grid { grid-template-columns: minmax(0, 1fr); } }

/* The profile form holds paragraphs, so it is wider than the others. */
.modal-wide { width: min(760px, calc(100vw - 24px)); }

/* The Models tab: one card per model, its lead photograph beside its opening.
   The direction is said out loud because .card sets column, and inheriting it
   here stretched a 240px thumbnail across the whole card as a letterbox band
   (CAR-439). */
.models-list { display: flex; flex-direction: column; gap: 20px; }
.model-card { display: flex; flex-direction: row; gap: 22px; padding: 20px 22px; color: inherit; text-decoration: none; }
.model-card:hover { border-color: var(--border-strong); }
.model-card-photo { flex: 0 0 240px; aspect-ratio: 3 / 2; border-radius: 8px; overflow: hidden; background: var(--surface-sunk); }
.model-card-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.model-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.model-card h2 { margin: 0; font-size: 22px; font-weight: var(--fw-medium); letter-spacing: -.01em; }
.model-card p { margin: 0; font-size: var(--fs-body); line-height: 1.55; max-width: 66ch; color: var(--text-muted); }
@media (max-width: 640px) {
  .model-card { flex-direction: column; }
  .model-card-photo { flex-basis: auto; }
}

/* The Refresh dialog (CAR-460): every source that can be asked about a car,
   with its price and what is already held. It sits in the same overlay the
   lightbox uses, so it inherits the backdrop. */
.rbox { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
        width: min(720px, calc(100vw - 32px)); max-height: calc(100vh - 64px);
        overflow: auto; padding: 16px 18px 12px; }
.rbox-list { margin: 10px 0 4px; }
/* A fixed money column, so a long word on the right can never squeeze the
   name and its lines into a column a word wide (CAR-508). */
.rbox-row { display: grid; grid-template-columns: 20px minmax(0, 1fr) 96px;
            gap: 2px 10px; align-items: baseline; padding: 9px 0;
            border-bottom: 1px solid var(--border); cursor: pointer; }
.rbox-row:last-child { border-bottom: 0; }
.rbox-row.is-off { opacity: .62; }
.rbox-name { font-weight: 600; }
.rbox-price { grid-row: 1; grid-column: 3; text-align: right;
              font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.rbox-gives { grid-column: 2 / 3; font-size: 12px; color: var(--text-muted); }
/* Why a source cannot be asked, when one was last held, and what a source
   answered once it has been asked. All three are sentences, so they land on
   this line rather than in the price column, which is a narrow right-aligned
   one (CAR-460, CAR-508). */
.rbox-note { grid-column: 2 / 3; font-size: 12px; color: var(--text); }
.rbox-note:empty { display: none; }
.rbox-note.is-bad { color: var(--chalk); }
.rbox-foot { display: flex; align-items: center; gap: 8px; padding-top: 10px;
             border-top: 1px solid var(--border); }
.rbox-total { font-size: 12px; color: var(--text-muted); }
.rbox-row.is-off { cursor: default; }
.rbox-row.is-off .rbox-price { color: var(--text-faint); }

/* BMW's digital service book (CAR-469). One line an event, newest first:
   date, reading, garage, work. Half the events name no garage, so the column
   is simply empty there rather than filled with a guess. */
.svc-list { list-style: none; margin: 8px 0 0; padding: 0; }
.svc-event { display: grid; grid-template-columns: 92px max-content 1fr; gap: 2px 12px;
             padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.svc-event:last-child { border-bottom: 0; }
.svc-date { font-variant-numeric: tabular-nums; }
.svc-miles { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.svc-where { color: var(--text-muted); }
.svc-work { grid-column: 3; font-size: 12px; color: var(--text-faint); }

/* A model's figures under its story (CAR-739): one card a row, so a card's
   tiles sit side by side. */
.model-figures { display: flex; flex-direction: column; gap: 16px; }
.model-facts { gap: 14px; }
.model-facts a { color: var(--accent); }
