/* sail-jinx — shared styles.
 *
 * A clean race-management UI: sans-serif chrome over a soft off-white page, a
 * navy accent, gentle rounding. The one deliberate departure from all-sans is
 * the data the race officer scans under time pressure — time and TCF inputs
 * stay monospace, and tables use tabular figures so columns of times and
 * numbers line up.
 *
 * The reports at the bottom of this file are the other half of the job: they
 * print, and someone reads the printout aloud while another person types it
 * into SailSys. They are set larger and plainer than the screen UI for that
 * reason. */

:root {
  --brand:        #15487e;
  --brand-dark:   #0f3a68;
  --accent:       #2f6fb3;
  --accent-soft:  #eaf1fb;

  --ink:          #1f2a37;
  --muted:        #64727f;
  --faint:        #95a1ad;

  --line:         #e4e8ee;
  --line-strong:  #cfd6df;

  --bg:           #f5f7fa;
  --surface:      #ffffff;
  --surface-alt:  #f0f3f8;

  --warn-bg: #fff6e0; --warn-bd: #f0c245; --warn-fg: #7a5a05;
  --err-bg:  #fdecee; --err-bd:  #f1b6bd; --err-fg:  #8a1c28;
  --info-bg: #eaf1fb; --info-bd: #b9d0f0; --info-fg: #1a3f72;
  --ok-bg:   #e6f4ea; --ok-bd:   #b4dcc0; --ok-fg:   #1c6b38;
  --dirty-bg: #fff8db; --dirty-bd: #d8af1f;

  --radius:    8px;
  --radius-sm: 5px;
  --shadow:    0 1px 2px rgba(15,42,72,.06), 0 2px 8px rgba(15,42,72,.07);
  --shadow-pop: 0 8px 24px rgba(15,42,72,.18);

  --font-ui:   -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", "JetBrains Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

/* While a request is in flight (setBusy in common.js) show a wait cursor over
   everything, so the RO knows to wait. */
body.busy, body.busy * { cursor: wait !important; }

body {
  font-family: var(--font-ui);
  color: var(--ink);
  background: var(--bg);
  margin: 0;
  padding: 0 1.5rem 3rem;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

main { max-width: 1500px; margin: 0 auto; }

h1 { font-size: 1.55rem; font-weight: 650; letter-spacing: -0.01em; margin: 1rem 0 0.5rem; }
h2 {
  font-size: 1.15rem; font-weight: 620; margin: 1.75rem 0 0.6rem;
  padding-bottom: 0.3rem; border-bottom: 1px solid var(--line);
}
p.lead { color: var(--muted); font-size: 1.02rem; max-width: 60rem; }
ul, ol { max-width: 60rem; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--brand); text-decoration: underline; }

code { font-family: var(--font-mono); font-size: 0.9em; }

/* --- buttons ------------------------------------------------------------- */

button {
  font-family: var(--font-ui); font-size: 0.9rem; font-weight: 500;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  padding: 5px 12px; cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
button:hover:not(:disabled) { background: var(--surface-alt); border-color: var(--accent); }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
button.primary {
  background: var(--brand); color: #fff; border-color: var(--brand);
  padding: 6px 18px; font-weight: 600;
}
button.primary:hover:not(:disabled) { background: var(--brand-dark); border-color: var(--brand-dark); }
button:disabled { opacity: 0.55; cursor: default; }
/* A disabled primary isn't the current next step, so drop it to neutral grey —
   only the actionable primary should read as "do this now". */
button.primary:disabled {
  background: var(--surface-alt); color: var(--muted);
  border-color: var(--line-strong); opacity: 1;
}
button.link-btn {
  background: none; border: none; color: var(--accent);
  padding: 0 0.35rem; font-size: 0.88rem;
}
button.link-btn:hover { background: none; text-decoration: underline; }
/* The one link-button that destroys something. Coloured rather than made prominent:
   it sits in a row of ordinary actions and has to be distinguishable from them at a
   glance, without competing with Edit for the eye. */
button.link-btn.danger-btn { color: var(--err-fg); }
a.button-link {
  display: inline-block; font-size: 0.9rem; font-weight: 500;
  padding: 5px 12px; border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--ink);
}
a.button-link:hover { background: var(--surface-alt); border-color: var(--accent); text-decoration: none; }
/* A report link with nothing to report yet. Matched to a disabled button rather than
   hidden, so the sheet is visibly a step that is coming rather than one that does not
   exist. Deliberately NOT pointer-events:none — the title says why it is off, and
   suppressing pointer events would suppress the tooltip along with the click. The href
   is removed in script, which is what actually stops the navigation. */
a.button-link.disabled, a.button-link.disabled:hover {
  color: var(--muted); border-color: var(--line); background: var(--surface);
  cursor: not-allowed;
}

/* --- inputs -------------------------------------------------------------- */

input[type=text], input[type=number], input[type=date], input:not([type]), select {
  font-family: var(--font-ui); font-size: 0.9rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); padding: 4px 8px;
}
input:focus, select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}

/* TCF input — sized for exactly "0.0000". content-box so the ch width is pure
   text space; the global border-box would fold padding in and clip the value. */
input.tcf-input {
  font-family: var(--font-mono); width: 6.5ch; padding: 3px 5px; text-align: right;
  box-sizing: content-box; -moz-appearance: textfield;
}
input.tcf-input::-webkit-outer-spin-button,
input.tcf-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input.tcf-input.dirty { background: var(--dirty-bg); border-color: var(--dirty-bd); }

/* Time input — sized for exactly "00:00:00". */
input.time-input {
  font-family: var(--font-mono); width: 8ch; padding: 3px 5px; text-align: right;
  box-sizing: content-box;
}
input.time-input:disabled { background: var(--surface-alt); color: var(--faint); }
/* Unparseable input stays on screen for the user to fix rather than being
   silently dropped — this is what marks it. */
input.invalid { background: var(--err-bg); border-color: var(--err-bd); }

button.now-btn {
  font-size: 0.72rem; font-weight: 600; padding: 2px 7px;
  color: var(--brand); background: var(--accent-soft); border-color: var(--info-bd);
  border-radius: 999px;
}
button.now-btn:hover:not(:disabled) { background: #dbe7f8; }
th.now-col, td.now-col { text-align: center; padding-left: 4px; padding-right: 4px; }

/* --- chrome -------------------------------------------------------------- */

.site-nav {
  display: flex; gap: 0.4rem; align-items: center;
  padding: 0.55rem 1rem; margin: 0 -1.5rem 1.25rem;
  background: var(--surface); border-bottom: 1px solid var(--line);
  font-size: 0.92rem;
}
.site-nav a {
  color: var(--muted); padding: 0.3rem 0.7rem;
  border-radius: 999px; font-weight: 500;
}
.site-nav a:hover { color: var(--brand); background: var(--accent-soft); text-decoration: none; }
.site-nav a.active { color: #fff; background: var(--brand); }
.site-nav a.nav-home {
  font-weight: 700; font-size: 1.1rem; margin-right: 0.5rem; color: var(--ink);
  padding: 0.15rem 0.3rem; background: none;
}
.site-nav a.nav-home:hover, .site-nav a.nav-home.active { background: none; color: var(--brand); }
.site-nav .build-widget { margin-left: auto; font-size: 0.85rem; color: var(--muted); }
.build-version { color: var(--faint); }
a.build-err, .build-err { color: var(--err-fg); font-weight: 600; }

.banner {
  padding: 0.55rem 0.85rem; border-radius: var(--radius-sm);
  margin-bottom: 0.75rem; font-size: 0.9em; border: 1px solid transparent;
}
.banner-warn  { background: var(--warn-bg); border-color: var(--warn-bd); color: var(--warn-fg); }
.banner-err   { background: var(--err-bg);  border-color: var(--err-bd);  color: var(--err-fg); }
.banner-info  { background: var(--info-bg); border-color: var(--info-bd); color: var(--info-fg); }
.banner-ok    { background: var(--ok-bg);   border-color: var(--ok-bd);   color: var(--ok-fg); }
.banner ul { margin: 0.4rem 0 0; }

ul.next-races { margin: 0; padding-left: 1.1rem; }
ul.next-races li { margin: 0.15rem 0; }
ul.next-races li:only-child { list-style: none; margin-left: -1.1rem; }

.hint  { color: var(--muted); font-size: 0.85em; }
.mono  { font-family: var(--font-mono); }

.tag {
  display: inline-block; padding: 0 7px; border-radius: 999px;
  font-size: 0.75em; font-weight: 600;
  background: var(--surface-alt); border: 1px solid var(--line-strong); color: var(--muted);
}

.state-pending  { color: var(--muted); }
.state-active   { color: var(--warn-fg); font-weight: 600; }
.state-done     { color: var(--ok-fg); font-weight: 600; }
.state-abandoned{ color: var(--err-fg); font-weight: 600; }

/* --- layout blocks ------------------------------------------------------- */

.toolbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.6rem;
  margin: 0.75rem 0;
}
.toolbar label { font-size: 0.9rem; color: var(--muted); display: inline-flex;
  align-items: center; gap: 0.35rem; }

.filters { display: flex; gap: 1rem; flex-wrap: wrap; font-size: 0.85rem; color: var(--muted); }
.filters label { display: inline-flex; align-items: center; gap: 0.35rem; }

/* A checkbox in a form-grid cell is a small mark in a wide column, and centring it
   against the label opposite reads as a stray tick rather than as that row's box. */
.form-grid .check-cell { display: flex; align-items: center; }
.form-grid .check-cell input { margin: 0; }
.cfg-warn { color: var(--warn-fg); }

.form-grid {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 0.45rem 1rem; align-items: center;
  margin: 0.75rem 0; max-width: 46rem;
}
.form-grid label { color: var(--muted); font-size: 0.9rem; }
/* A label or heading with a tooltip says so, since hover is the only way to find it. */
.form-grid label[title], .toolbar label[title], .filters label[title] {
  text-decoration: underline dotted var(--line-strong); text-underline-offset: 3px;
}
label[title], th[title]:not(.sortable) { cursor: help; }

/* Nav first, then the title: the arrows read as "step through the season" sitting
   beside the race they step from, rather than stranded on the far margin. */
/* The race page is worked down, not read, so the run-up to the table is squeezed: the
   title sits at half the usual gap from the nav, and each line below it 20% closer to
   the next. Every line saved here is a boat visible without scrolling. */
.race-head { display: flex; align-items: center; gap: 0.75rem; }
#race-page h1 { margin: 0.25rem 0 0.25rem; }
#race-page .banner { margin-bottom: 0.6rem; }
#race-page .toolbar { margin: 0.6rem 0; }
#race-page section { margin-top: 0.6rem; }
.race-nav { display: flex; gap: 0.3rem; }
.race-nav button { padding: 0.2rem 0.55rem; line-height: 1; }

/* Both hold HH:MM in a native time control. Sized by content rather than in ch: the
   picker button sits inside the box, and a width counted in characters put it on top
   of the minutes. The floor covers a locale that renders these 12-hour with an am/pm. */
input.hhmm-input { width: 5rem; }

/* The filters sit under the heading rather than opposite it: they are the things
   most often reached for, and hunting the far side of the page for them costs more
   than the line of space this takes. */
#race-entrants > h2 { margin-bottom: 0.35rem; }
#race-entrants > .filters { margin-bottom: 0.72rem; }

/* Removing an entrant is a repair, not part of the night's work. The toggle that
   reveals it reads as a warning, and the button itself is small and quiet — it is only
   ever on screen because somebody deliberately asked for it. */
label.danger-toggle { color: var(--err-fg); }
/* A computed time whose working is on the tooltip. The dotted underline is the only
   thing that says so — without it the detail is there and nobody looks for it. */
span.derived { border-bottom: 1px dotted var(--line-strong); cursor: help; }
td.remove-cell { text-align: center; padding-left: 4px; padding-right: 4px; }
button.remove-btn {
  border: 1px solid transparent; background: none; color: var(--muted);
  cursor: pointer; line-height: 1; padding: 2px 6px; border-radius: 3px;
}
button.remove-btn:hover {
  color: #fff; background: var(--err-fg); border-color: var(--err-fg);
}

/* NOW log: every NOW click, in a list that can be dragged back onto a time box. */
#now-log { margin: 0.5rem 0 1rem; }
#now-log .toolbar { margin: 0.4rem 0 0.2rem; }
#now-log-list { margin: 0; padding-left: 1.5rem; font-size: 0.9rem; }
li.now-log-entry { cursor: grab; padding: 1px 0; }
li.now-log-entry:active { cursor: grabbing; }
li.now-log-entry code {
  background: var(--surface-alt); border-radius: 3px; padding: 0 0.25rem;
}
.now-drag-handle { color: var(--faint); cursor: grab; user-select: none; }
li.now-log-entry:hover .now-drag-handle { color: var(--accent); }
input.time-input.now-drop-target {
  outline: 2px solid var(--accent); outline-offset: -1px;
}

/* The notice box and the Save/Reset box occupy one slot, not two. The slot is sized by
   the notice — with a floor deep enough for a row of buttons, so nothing on the page
   moves when an edit makes the save box appear over it. */
.notice-slot { position: relative; min-height: 2.5rem; margin-bottom: 0.6rem; }
/* The gap below belongs to the slot, not to the notice inside it. On the banner it sat
   inside the slot's height, so the overlay — which fills the slot — came out that much
   taller than the box it is covering. The id selector is to beat #race-page .banner. */
#race-page .notice-slot > .banner { margin-bottom: 0; }

.save-bar {
  position: absolute; inset: 0; z-index: 20;
  display: flex; align-items: center; gap: 0.75rem;
  /* No vertical padding: the height is the slot's, and the buttons centre in it. */
  padding: 0 0.85rem;
  background: var(--dirty-bg); border: 1px solid var(--dirty-bd);
  border-radius: var(--radius); box-shadow: var(--shadow-pop);
}
.save-bar span { color: var(--muted); font-size: 0.88rem; }

/* The entrants table gets its own scrollbar once the window is tall enough to show a
   useful number of boats at once — see fitEntrantsHeight in race.html, which sets the
   height and decides whether to set one at all. The header sticks, or scrolling the
   fleet would mean scrolling the column names off the top of it. */
/* Only as wide as the table. Left to itself the box fills the page and the table fills
   the box, which put a stretch of empty cell between the last column and the scrollbar
   — the bar is easier to reach where the table actually ends. */
.entrants-scroll { overflow: auto; width: fit-content; max-width: 100%; }
/* So the last toolbar's bottom margin stays inside #race-page rather than collapsing
   out of it: fitEntrantsHeight measures what is below the table up to the bottom of
   #race-page, and a margin poking out past it was enough to bring the page scrollbar
   back. */
#race-page { display: flow-root; }
.entrants-scroll table { width: auto; border-radius: 0; border-top: none; }
.entrants-scroll thead th {
  position: sticky; top: 0; z-index: 2;
  /* No background here on purpose: #entrants-table thead th already paints it brand,
     and an id beats a class. A sticky header MUST be opaque or the rows scroll visibly
     through it — so it inherits the one that is already there. */
}

/* --- tables -------------------------------------------------------------- */

table {
  width: 100%; border-collapse: collapse; font-size: 0.9rem;
  font-variant-numeric: tabular-nums; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
}
th {
  text-align: left; padding: 7px 10px; vertical-align: bottom;
  background: var(--surface-alt); color: var(--muted);
  font-weight: 600; font-size: 0.82rem;
  border-bottom: 1px solid var(--line-strong);
}
td { padding: 6px 10px; border-bottom: 1px solid var(--line); }
tbody tr:nth-child(even):not(:hover) td { background: #f7f9fb; }
tr:hover td { background: var(--accent-soft); }
tbody tr:last-child td { border-bottom: none; }

th.num-cell, td.num-cell { text-align: right; }
td.notes-cell { color: var(--muted); font-size: 0.85em; max-width: 20rem; }
td.actions-cell { white-space: nowrap; }

th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover { background: var(--brand-dark); color: #fff; }

tr.retired td { color: var(--faint); }
tr.editing td { background: var(--dirty-bg) !important; }
tr.selected-row td { background: var(--ok-bg); }
tr.unplaced td { color: var(--muted); }
.retire-label { font-size: 0.8rem; color: var(--muted); margin-left: 0.5rem; }

#entrants-table { width: auto; }
#entrants-table th, #entrants-table td { padding: 5px 8px; white-space: nowrap; }
#entrants-table thead th { background: var(--brand); color: #fff; border-bottom-color: var(--brand-dark); }

/* Drag-to-reorder handle on entrant rows. The working order matters on the
   night: boats are watched in roughly the sequence they are expected to
   finish. */
td.drag-handle {
  cursor: grab; user-select: none; text-align: center;
  color: var(--faint); font-size: 1.1rem; width: 1.5em;
}
td.drag-handle:hover { color: var(--brand); }
tr.drag-over td { border-top: 2px solid var(--accent); }

th.adjustment-cell, td.adjustment-cell { text-align: right; }
.adjustment { cursor: help; font-family: var(--font-mono); }

/* Flags cell — clickable, with a pencil hint that takes no layout space. */
/* Only where the cell will actually open. On a locked race the click is refused, and
   a pointer, a hover and a pencil that lead nowhere read as a control that is broken
   rather than one that is closed. */
td.flag-cell { position: relative; }
#entrants-table:not(.locked) td.flag-cell { cursor: pointer; }
#entrants-table:not(.locked) td.flag-cell:hover { background: #fff5cc; }
#entrants-table:not(.locked) td.flag-cell:hover::after {
  content: ' \270E'; color: var(--muted); font-size: 0.9em; margin-left: 0.3em;
}
.flag-popover {
  position: absolute; top: 100%; left: 0; z-index: 100;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-pop);
  padding: 0.5rem 0.7rem; font-size: 0.85rem; min-width: 8em; text-align: left;
}
.flag-popover label { display: block; padding: 2px 0; cursor: pointer; }
.flag-popover label:hover { background: var(--surface-alt); }
.flag-popover label.manual { font-weight: 600; }
.flag-popover .popover-foot {
  border-top: 1px solid var(--line); margin-top: 0.35rem; padding-top: 0.3rem;
  white-space: normal; max-width: 14rem;
}

#filter-chip {
  margin: 0 0 0.75rem; font-size: 0.9rem; color: var(--muted);
}
#filter-chip a { margin-left: 0.75rem; }

/* --- reports ------------------------------------------------------------- */
/* These get printed and read aloud. Bigger type, more leading, no decoration
   that costs toner or attention. */

body.report-page { background: var(--surface); }
.report { max-width: 46rem; margin: 0 auto; }
.report-toolbar {
  display: flex; align-items: center; gap: 1rem;
  max-width: 46rem; margin: 1rem auto 0;
}
/* The start sheet is eight columns, four of them blank space to write in, so 46rem
   wraps boat names for no reason. It gets the window instead — and prints the same,
   since the print rules already lift the cap for every report.

   After .report-toolbar, not before: both are a single class, so at equal specificity
   whichever comes last wins, and the toolbar would otherwise keep its own 46rem and sit
   misaligned above a full-width sheet. */
.report-wide { max-width: none; }
/* A boat name is one thing and reads as one thing; with the width above there is room
   for it. Marked by the column rather than by position — it was nth-child(2), which
   silently became the wrong column the moment either sheet was reordered. */
table.report-table td.nowrap, table.report-table th.nowrap { white-space: nowrap; }
.report-head { border-bottom: 2px solid var(--ink); padding-bottom: 0.5rem; margin-bottom: 1rem; }
.report-head h1 { margin: 0; font-size: 1.4rem; }
.report-sub { color: var(--muted); font-size: 0.95rem; margin-top: 0.2rem; }

table.report-table {
  width: 100%; box-shadow: none; border: none; border-radius: 0;
  font-size: 1.02rem;
}
table.report-table th {
  background: none; color: var(--ink); border-bottom: 1px solid var(--ink);
  font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.04em;
}
table.report-table td { padding: 7px 10px; border-bottom: 1px solid var(--line); }
table.report-table tbody tr:nth-child(even) td { background: none; }
table.report-table tr:hover td { background: none; }

/* Start-sheet write-in columns: blank space the RO fills in on the clipboard, so what
   matters is that there is room to write and a rule to write on. Sized in em so they
   hold their proportions at the 11pt the print rules drop the table to. */
table.report-table th.write-in { text-align: left; }
table.report-table td.write-in { border-left: 1px solid var(--line); }
table.report-table td.write-in-time, table.report-table th.write-in-time { min-width: 5.5em; }
table.report-table td.write-in-notes, table.report-table th.write-in-notes { min-width: 9em; }
table.report-table td.write-in-tick, table.report-table th.write-in-tick { text-align: center; }
/* Roomy enough to write a time into by hand, in the dark, on a moving boat. */
table.report-table td.write-in { height: 1.9em; }

.tickbox {
  display: inline-block; width: 0.85em; height: 0.85em;
  border: 1px solid var(--ink); border-radius: 2px; vertical-align: -0.05em;
}

.report-note {
  margin-top: 1.25rem; padding: 0.6rem 0.8rem;
  border-left: 3px solid var(--line-strong); color: var(--muted); font-size: 0.9rem;
}
.report-foot {
  margin-top: 1.5rem; padding-top: 0.5rem; border-top: 1px solid var(--line);
  color: var(--muted); font-size: 0.85rem;
}

@media print {
  body { padding: 0; background: #fff; }
  .no-print, .site-nav { display: none !important; }
  .report { max-width: none; }
  .report-note { break-inside: avoid; }
  table.report-table { font-size: 11pt; }
  table.report-table th { border-bottom: 1pt solid #000; }
  /* Repeat the header on every page — a fleet of forty can spill over. */
  table.report-table thead { display: table-header-group; }
  table.report-table tr { break-inside: avoid; }
  /* Black, not the screen's grey: a rule you are meant to write on has to survive a
     club printer that is low on toner. */
  table.report-table td.write-in { border-left: 0.5pt solid #000; }
  .tickbox { border-color: #000; }
}

/* --- CSV import ---------------------------------------------------------- */

#import-panel textarea {
  width: 100%; max-width: 60rem; font-family: var(--font-mono); font-size: 0.85rem;
  padding: 0.6rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); resize: vertical;
}
#import-panel textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
#import-report { margin-top: 1rem; }
#import-report table { margin-top: 0.5rem; }
tr.conflict-row td { background: var(--warn-bg); }

/* The boat id is worth showing — it is how boats are talked about — but it is
   reference data, not something to read first. */
td.id-cell { color: var(--muted); font-size: 0.82em; }

#import-panel textarea {
  width: 100%; max-width: 60rem; font-family: var(--font-mono); font-size: 0.85rem;
  padding: 0.6rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); resize: vertical;
}
#import-panel textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
#import-panel h3 { margin-top: 1rem; }

/* The printed sheets sort on screen; the header affordance is not worth ink. */
@media print { table.report-table th.sortable { cursor: auto; } }
table.report-table th.sortable:hover { background: var(--surface-alt); color: var(--brand); }
