/* NARA admin - light warm canvas, one coral accent (ADR-0016, design spec
   docs/superpowers/specs/2026-08-18-admin-redesign-design.md).

   This deliberately DIVERGES from the customer app's dark/gold palette
   (mobile/lib/core/theme/palette.dart). The app is a dining room; the admin is a
   back office opened for hours in daylight, and it optimises for legibility.

   Selector names are unchanged from the previous stylesheet on purpose: this file
   restyles the existing Thymeleaf markup, so no template needs to change for the
   new look to land. Markup-level work (the live board, the KPI icon discs, the
   table-to-card transform) follows in its own stories. */

:root {
  /* Surfaces and ink */
  --canvas: #F7F4F0;
  --card: #FFFFFF;
  --ink: #1B1714;
  --ink-2: #6E665C;
  --ink-3: #A39B90;
  --line: #EDE7E0;
  --grid: #F3EEE8;

  /* Coral splits in two. --coral is a FILL and a chart mark only: it is 3.44:1
     on white and fails as text. --coral-ink is the text and filled-button token
     at 5.07:1. Never swap them. */
  --coral: #F0572B;
  --coral-ink: #C63F17;
  --coral-wash: #FEEFE9;
  --coral-deep: #A83A16;

  /* Status. A closed family, reserved for order and availability state - charts
     never borrow from it. */
  --st-paid: #2563A8;      --st-paid-bg: #E9F0F8;
  --st-prep: #B26A00;      --st-prep-bg: #FBF1E0;
  --st-done: #1F7A55;      --st-done-bg: #E7F3ED;
  --st-bad: #C0392B;       --st-bad-bg: #FAEAE8;
  --st-idle: #6E665C;      --st-idle-bg: #F1EEEA;

  /* Names the templates reference inline - kept so no template breaks. */
  --text: var(--ink);
  --text-2: var(--ink-2);
  --text-3: var(--ink-3);
  --success: var(--st-done);
  --error: var(--st-bad);
  --hairline: var(--line);

  --shadow: 0 1px 2px rgba(27, 23, 20, .04), 0 10px 28px -14px rgba(27, 23, 20, .14);
  --r-card: 16px;
  --r-tile: 12px;
  --r-ctl: 10px;
}

/* Rubik is the designed face. It is NOT loaded from a third party: a blocking
   webfont request is exactly what the "fast on restaurant wifi" argument in
   ADR-0016 rules out. It renders when installed; otherwise the system Hebrew
   face does. Self-hosting the two weights under static/admin/fonts/ is a
   follow-up story. */
* { box-sizing: border-box; margin: 0; }

body {
  background: var(--canvas);
  color: var(--ink);
  min-height: 100vh;
  font-family: Rubik, "Heebo", -apple-system, "Segoe UI", "Arial Hebrew", Arial, sans-serif;
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--coral-ink); text-decoration: none; }
a:hover { color: var(--coral-deep); }

/* One visible focus ring for every interactive element. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
label.nav-btn:focus-visible {
  outline: 2px solid var(--coral-ink);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Latin and numeric runs inside an RTL page - phone numbers, slugs, wire codes.
   Without isolation the bidi algorithm reorders their punctuation. Applied to a
   span rather than the cell, so the cell itself stays RTL and its card-mode
   label keeps to the correct side. */
.ltr { direction: ltr; unicode-bidi: isolate; }

/* The trailing action column. `end` is logical - the previous physical `left`
   put the buttons on the far side of an RTL row. */
td.cell-actions { text-align: end; white-space: nowrap; }

/* The delivery address on an order row (#437): the street line reads first, the
   apartment/floor/label detail sits under it in the secondary ink so a driver can
   scan addresses without the door details competing with them. */
.addr-detail { display: block; font-size: 12.5px; color: var(--ink-3); }

/* Every figure in this admin is a count or an amount, so digits align. */
.stat .v, table td, .bars .b .v, .hbar .v, .heat .c, .legend b, .code { font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- Shell */
.shell { display: flex; min-height: 100vh; }

.side {
  width: 248px;
  flex-shrink: 0;
  background: var(--card);
  border-inline-end: 1px solid var(--line);
  padding: 24px 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.side .logo { width: 58px; margin: 0 auto 18px; display: block; }

/* Stroke-only icons on a 20px grid, inheriting the row's colour so they follow
   hover and active without a second rule per state. */
.ico {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.side a.nav {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  border-radius: var(--r-ctl);
  color: var(--ink-2);
  font-size: 14px;
  font-weight: 400;
}
.side a.nav:hover { background: var(--grid); color: var(--ink); }
.side a.nav.active {
  background: var(--coral-wash);
  color: var(--coral-ink);
  font-weight: 500;
}
/* The active marker is a bar on the logical start edge, not a border on the box -
   a border would shift the label by its own width. */
.side a.nav.active::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 8px;
  bottom: 8px;
  width: 3px;
  border-radius: 999px;
  background: var(--coral);
}

.nav-group {
  margin: 14px 14px 3px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .3px;
  color: var(--ink-3);
}
/* Hebrew has no uppercase, so these micro labels separate by weight and colour.
   text-transform would be a no-op here and is deliberately absent. */
.nav-group:first-of-type { margin-top: 0; }

.side .foot {
  margin-top: auto;
  padding-top: 14px;
  font-size: 13px;
  color: var(--ink-3);
}

.nav-toggle { display: none; }
.topbar { display: none; }

.main {
  flex: 1;
  min-width: 0;
  padding: 30px 34px 34px;
  max-width: 1240px;
}

h1 {
  font-size: 24px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: .1px;
  margin-bottom: 22px;
}
h2 {
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
  margin: 28px 0 12px;
}

/* ---------------------------------------------------------------- Cards, stats, tables */
.card {
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  padding: 20px 22px;
}

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 16px;
  margin-bottom: 26px;
}
.stat { padding: 18px 20px; }
.stat-head { display: flex; align-items: center; gap: 11px; margin-bottom: 12px; }
.stat-ico {
  width: 38px;
  height: 38px;
  border-radius: var(--r-tile);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* The disc tint comes from the status family, so a tile's colour means the same
   thing it means everywhere else on the page. */
.stat-ico.coral { background: var(--coral-wash); color: var(--coral-ink); }
.stat-ico.good { background: var(--st-done-bg); color: var(--st-done); }
.stat-ico.warn { background: var(--st-prep-bg); color: var(--st-prep); }
.stat-ico.bad { background: var(--st-bad-bg); color: var(--st-bad); }
/* A currency mark is a glyph, not an icon - it is set in type, not drawn. */
.stat-ico.glyph { font-size: 17px; font-weight: 600; line-height: 1; }
.stat .v {
  font-size: 32px;
  font-weight: 600;
  line-height: 1.05;
  color: var(--ink);
}
.stat .l {
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.35;
}

table { width: 100%; border-collapse: collapse; }
th, td {
  text-align: start;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
}
th {
  color: var(--ink-3);
  font-weight: 500;
  font-size: 12px;
  padding-block: 0 12px;
  white-space: nowrap;
}
td { font-size: 13.5px; }
tr:last-child td { border-bottom: 0; }

/* ---------------------------------------------------------------- Controls */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  background: var(--coral-ink);
  color: #FFFFFF;
  border: 1px solid var(--coral-ink);
  padding: 9px 18px;
  border-radius: var(--r-ctl);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.4;
  cursor: pointer;
}
.btn:hover { background: var(--coral-deep); border-color: var(--coral-deep); color: #FFFFFF; }

.btn.ghost {
  background: var(--card);
  color: var(--ink-2);
  border-color: var(--line);
}
.btn.ghost:hover { background: var(--grid); color: var(--ink); border-color: var(--line); }

.btn.danger { background: var(--card); color: var(--st-bad); border-color: #EBD3CF; }
.btn.danger:hover { background: var(--st-bad-bg); color: var(--st-bad); border-color: #EBD3CF; }

.btn.small { padding: 6px 13px; font-size: 13px; }
.btn.icon { padding-inline: 10px; }

input, select, textarea {
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  padding: 9px 12px;
  font-size: 14px;
  font-family: inherit;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--coral-ink); }
input::placeholder, textarea::placeholder { color: var(--ink-3); }
input[type="time"] { width: 112px; }
input[type="number"] { width: 112px; }
input[type="checkbox"] { accent-color: var(--coral-ink); width: 17px; height: 17px; }

form.inline { display: inline-flex; gap: 8px; align-items: center; }
form.inline.wrap { flex-wrap: wrap; }

/* ---------------------------------------------------------------- Menu editor */
.cat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 28px 0 12px;
}
.cat-head h2 { margin: 0; }
.cat-title { display: flex; align-items: center; gap: 10px; }
.cat-title .count {
  color: var(--ink-2);
  font-size: 12px;
  background: var(--grid);
  border-radius: 999px;
  padding: 2px 10px;
}
.cat-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.cat-edit { flex-wrap: wrap; }

.item-status { display: flex; align-items: center; gap: 10px; margin: -12px 0 18px; flex-wrap: wrap; }

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px 18px; }
.form-grid label { display: flex; flex-direction: column; gap: 6px; font-size: 12.5px; font-weight: 500; color: var(--ink-2); }
.form-grid .full { grid-column: 1 / -1; }
.form-grid textarea { resize: vertical; line-height: 1.55; }

.form-grid fieldset.tags { border: 1px solid var(--line); border-radius: var(--r-tile); padding: 12px 16px 14px; }
.form-grid fieldset.tags legend { font-size: 12.5px; font-weight: 500; color: var(--ink-2); padding-inline: 6px; }
.form-grid .tag {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  display: inline-flex;
  margin-inline-end: 18px;
  color: var(--ink);
  font-weight: 400;
  font-size: 13.5px;
}
.form-grid .check { flex-direction: row; align-items: center; gap: 9px; color: var(--ink); font-weight: 400; font-size: 13.5px; }

/* Menu translations (#496): one bordered block per translatable field, three
   columns inside it - Hebrew source (readonly), English, Russian. The readonly
   column is tinted so it reads as "this is the source", not "this is broken". */
.i18n-field { border: 1px solid var(--line); border-radius: var(--r-tile); padding: 12px 16px 16px; margin-bottom: 14px; }
.i18n-field legend { font-size: 12.5px; font-weight: 500; color: var(--ink-2); padding-inline: 6px; }
.i18n-field input[readonly], .i18n-field textarea[readonly] { background: var(--grid); color: var(--ink-2); }
.i18n-field input:not([readonly]), .i18n-field textarea:not([readonly]) { direction: ltr; text-align: start; }

/* The compact per-row translation forms (#525) on option groups, options and
   removable ingredients. Those kinds have a name and nothing else, so a full
   three-column panel per row would bury the editor - the Hebrew source is the
   row's own name to the start of the form, and only en/ru are typed here. */
.i18n-inline input[type="text"] { width: 130px; direction: ltr; text-align: start; }
.i18n-tag { color: var(--ink-3); font-size: 12px; }
/* The option's translation row belongs to the row above it, not beside it. */
tr:has(+ tr.i18n-row) td { border-bottom: 0; }
tr.i18n-row td { padding-top: 0; }

.actions-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.image-row { display: flex; align-items: flex-start; gap: 22px; flex-wrap: wrap; }
.item-photo {
  width: 168px;
  height: 168px;
  object-fit: cover;
  border-radius: var(--r-tile);
  border: 1px solid var(--line);
}
.image-actions { display: flex; flex-direction: column; gap: 10px; }
input[type="file"] { border: 0; background: transparent; padding: 0; color: var(--ink-2); font-size: 13px; }

/* Intro film thumbnails (#403) - a reference strip below the picker, the selected
   film's still is highlighted with the coral accent. */
.intro-thumbs { margin-top: 18px; }
.thumb-grid { display: flex; flex-wrap: wrap; gap: 12px; }
.thumb-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 92px;
  font-size: 12px;
  color: var(--ink-2);
  text-align: center;
}
.thumb-card img {
  width: 92px;
  height: 92px;
  object-fit: cover;
  border-radius: var(--r-tile);
  border: 1px solid var(--line);
}
.thumb-card.selected img { border-color: var(--coral); border-width: 2px; }
.thumb-card.selected span { color: var(--coral-ink); font-weight: 600; }

.group-card { margin-bottom: 14px; }
.group-card h3 { font-size: 15px; font-weight: 600; }

.chips { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.chip-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 6px 4px 13px;
  font-size: 13px;
}
.chip-row .muted { color: var(--ink-3); text-decoration: line-through; }

label.mini { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ink-2); }
label.mini input[type="number"] { width: 76px; }
label.mini.check-inline { color: var(--ink); }

/* ---------------------------------------------------------------- Flash, badges, notes */
.flash {
  background: var(--st-done-bg);
  border: 1px solid #CBE4D8;
  color: var(--st-done);
  border-radius: var(--r-tile);
  padding: 11px 16px;
  margin-bottom: 20px;
  font-size: 13.5px;
  font-weight: 500;
}
.flash.error { background: var(--st-bad-bg); border-color: #F0D5D1; color: var(--st-bad); }

/* Status is never colour alone - every badge carries its Hebrew label. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 500;
  background: var(--st-idle-bg);
  color: var(--st-idle);
}
.badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
  flex-shrink: 0;
}
.badge.ok { background: var(--st-done-bg); color: var(--st-done); }
.badge.off { background: var(--st-bad-bg); color: var(--st-bad); }

.note { color: var(--ink-3); font-size: 12.5px; margin-top: 12px; }
.empty { color: var(--ink-3); font-size: 13px; }

/* ---------------------------------------------------------------- Auth */
.auth {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--canvas);
  padding: 24px;
}
/* min() rather than width + max-width: an auto grid/flex track sizes to the
   card's max-content, against which a percentage max-width never caps. */
.auth .card { width: min(380px, 100%); text-align: center; padding: 34px 32px; }
.auth .logo { width: 74px; margin: 0 auto 18px; }
.auth h1 { font-size: 20px; margin-bottom: 4px; }
.auth form { display: flex; flex-direction: column; gap: 13px; margin-top: 20px; }
.auth input { text-align: center; }
.auth .btn { padding-block: 12px; }
.auth .err { color: var(--st-bad); font-size: 13px; margin-top: 12px; }

.secret {
  direction: ltr;
  unicode-bidi: isolate;
  text-align: left;
  font-family: ui-monospace, monospace;
  background: var(--coral-wash);
  border: 1px dashed #F2C4B1;
  border-radius: var(--r-ctl);
  padding: 11px 13px;
  word-break: break-all;
  font-size: 12.5px;
  color: var(--coral-ink);
}

/* ---------------------------------------------------------------- Stats pages
   One visual grammar for every figure: magnitude = one coral hue, flat on the
   baseline and rounded only at the data end; intensity = the coral ramp
   (.q1-.q4); a categorical mix = the fixed series order .s1/.s2/.s3, assigned by
   meaning and never re-coloured by rank. Status colours are never used here.

   The series colours were machine-validated rather than picked by eye (lightness
   band, chroma floor, colour-vision separation, normal-vision floor). Orange is
   deliberately absent so no series ever competes with the coral accent. */
.range-form { display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 24px; }
.range-form label { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; font-weight: 500; color: var(--ink-2); }
.range-form .quick { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; }
.range-form .quick a {
  padding: 7px 15px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink-2);
  font-size: 13px;
}
.range-form .quick a:hover { border-color: var(--ink-3); color: var(--ink); }
.range-form .quick a.on {
  background: var(--coral-wash);
  border-color: var(--coral-wash);
  color: var(--coral-ink);
  font-weight: 500;
}

.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 20px; }
.grid2 h2:first-child { margin-top: 0; }

/* Vertical series: flat on the baseline, 4px only at the data end. */
.bars { display: flex; align-items: stretch; gap: 4px; height: 190px; }
.bars .b { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.bars .b .v { height: 15px; font-size: 10.5px; color: var(--ink-3); text-align: center; white-space: nowrap; }
.bars .b .track { flex: 1; display: flex; align-items: flex-end; }
.bars .b .track > i {
  display: block;
  width: 100%;
  background: var(--coral);
  min-height: 2px;
  border-start-start-radius: 4px;
  border-start-end-radius: 4px;
}
.bars .b .t { height: 19px; padding-top: 5px; font-size: 10.5px; color: var(--ink-3); text-align: center; white-space: nowrap; }

/* Ranked horizontal series: the same rules rotated - the rounded end is the data end. */
.hbars { display: flex; flex-direction: column; gap: 9px; }
.hbar { display: grid; grid-template-columns: 160px minmax(0, 1fr) 82px; align-items: center; gap: 12px; }
.hbar .n { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar .track { display: flex; background: var(--grid); border-radius: 4px; height: 14px; }
.hbar .track > i {
  display: block;
  height: 14px;
  background: var(--coral);
  min-width: 2px;
  border-start-end-radius: 4px;
  border-end-end-radius: 4px;
}
.hbar .v { font-size: 13px; font-weight: 500; color: var(--ink-2); text-align: start; white-space: nowrap; }

/* Weekday x hour intensity: the coral ramp, bucketed by quartile of the busiest
   cell. Every step carries dark ink - white would fall below 4.5:1 on q3/q4. */
.heat-scroll { overflow-x: auto; }
.heat { display: grid; grid-template-columns: 52px repeat(24, minmax(0, 1fr)); gap: 3px; min-width: 560px; }
.heat .hh { font-size: 9.5px; color: var(--ink-3); text-align: center; }
.heat .dd { font-size: 11.5px; color: var(--ink-2); white-space: nowrap; align-self: center; }
.heat .c {
  height: 28px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10.5px;
  color: var(--ink);
}
.heat .c.z { background: #F3EFEA; color: var(--ink-3); }
.heat .c.q1 { background: #FBE6DC; }
.heat .c.q2 { background: #F6BFA6; }
.heat .c.q3 { background: #F08A64; }
.heat .c.q4 { background: #DC5628; }

/* Categorical mix: 2px surface gaps, always a legend AND the percentage in text -
   three of the five series sit under 3:1 on white, so identity is never colour alone. */
.mix { display: flex; gap: 2px; }
.mix > i { display: block; height: 18px; border-radius: 3px; min-width: 3px; flex-basis: 0; }
.legend { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 13px; font-size: 12.5px; color: var(--ink-2); }
.legend .k { display: inline-flex; align-items: center; gap: 7px; }
.legend .chip { width: 10px; height: 10px; border-radius: 3px; }
.legend b { color: var(--ink); font-weight: 600; }

.s1 { background: #2A78D6; }
.s2 { background: #1BAF7A; }
.s3 { background: #EDA100; }
/* Not a fourth category colour - the neutral bucket for a key we cannot name. */
.s-other { background: var(--ink-3); }

/* Funnel: the stage rows are .hbar - one hue, because this is a magnitude chart
   and colouring the stages would imply they are categories. */
.funnel .step {
  padding-block: 4px;
  padding-inline-start: calc(160px + 12px);
  font-size: 11.5px;
  color: var(--ink-3);
}

/* Paired series: two counts of the SAME unit on one shared scale. 1px inside a
   pair against 4px between days, so a day reads as one group. */
.bars.paired { gap: 7px; }
.bars .b .track.pair { gap: 1px; }
.bars .b .track.pair > i { width: auto; flex: 1; min-width: 0; }
.bars .b .track.pair > i.s1 { background: #2A78D6; }
.bars .b .track.pair > i.s2 { background: #1BAF7A; }
.bars .b .track.pair > i.zero { min-height: 0; }

/* ASCII inside an RTL page: event types and reason codes are wire values, and
   without isolation the bidi algorithm reorders their punctuation. text-align is
   physical on purpose - the element's own direction is ltr, so the logical
   `start` would place a code against the far edge of its RTL column. */
.code {
  direction: ltr;
  unicode-bidi: isolate;
  text-align: right;
  font-family: ui-monospace, monospace;
  font-size: 12px;
}

/* Dashboard week chart */
.chart { display: flex; align-items: flex-end; gap: 10px; height: 150px; padding-top: 8px; }
.chart .bar { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }
.chart .bar > i {
  display: block;
  background: var(--coral);
  border-radius: 4px 4px 2px 2px;
  min-height: 2px;
}
.chart .bar span { font-size: 11px; color: var(--ink-3); text-align: center; margin-top: 7px; }

/* ---------------------------------------------------------------- Live board (#352)
   The home screen's centre of gravity. Columns mirror the staff-driven transitions
   exactly; DELIVERED is a count chip, not a column. */
.board-meta { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.board-done {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 13px;
  border-radius: 999px;
  background: var(--st-done-bg);
  color: var(--st-done);
  font-size: 12.5px;
  font-weight: 500;
}
#alerts-toggle.on { background: var(--coral-wash); color: var(--coral-ink); border-color: var(--coral-wash); }

.board { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; align-items: start; }
.board-col { display: flex; flex-direction: column; min-width: 0; }
.board-col-head { display: flex; align-items: center; gap: 8px; padding: 0 2px 12px; }
.board-col-count { margin-inline-start: auto; font-size: 12.5px; font-weight: 500; color: var(--ink-3); }
.board-cards { display: flex; flex-direction: column; gap: 10px; }
.board-empty { margin: 0; padding: 14px 2px; color: var(--ink-3); font-size: 12.5px; }

/* An order card is a bordered tile rather than a shadowed one: the board is a
   dense grid, and a shadow per card would turn into noise. */
.ocard {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-tile);
  padding: 13px 14px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.ocard-top { display: flex; align-items: center; gap: 8px; }
.ocard-id { font-size: 14px; font-weight: 600; }
.ocard-meta { display: flex; flex-direction: column; gap: 2px; font-size: 12.5px; color: var(--ink-2); }
.ocard-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  row-gap: 10px;
  border-top: 1px solid var(--line);
  padding-top: 9px;
}
.ocard-total { font-size: 17px; font-weight: 600; }
.ocard-acts { margin-inline-start: auto; display: flex; gap: 6px; flex-wrap: wrap; }

/* The chip that drives kitchen priority: neutral, amber past ten minutes, coral
   past twenty. board.js retints it every second; these are also the classes the
   server-rendered value keeps if the script never runs. */
.age {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-inline-start: auto;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--st-idle-bg);
  color: var(--st-idle);
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.age::before { content: ""; width: 5px; height: 5px; border-radius: 999px; background: currentColor; }
.age.warm { background: var(--st-prep-bg); color: var(--st-prep); }
.age.hot { background: var(--coral-wash); color: var(--coral-ink); }

/* Column-head badges reuse the status family. */
.badge.info { background: var(--st-paid-bg); color: var(--st-paid); }
.badge.warn { background: var(--st-prep-bg); color: var(--st-prep); }

/* A swap in flight dims the board, so a tap reads as answered before the response
   lands. htmx adds and removes this class itself. */
#board.htmx-request { opacity: .6; transition: opacity .12s ease; }

/* ---------------------------------------------------------------- Phone
   The owner advances orders and toggles sold-out from a phone. The rail becomes a
   top bar plus a drawer; multi-column grids collapse. */
@media (max-width: 880px) {
  .shell { flex-direction: column; }

  .topbar {
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--card);
    border-bottom: 1px solid var(--line);
    padding: 11px 16px;
    position: sticky;
    top: 0;
    z-index: 10;
  }
  .topbar .logo { width: 38px; }
  .nav-btn {
    font-size: 20px;
    line-height: 1;
    color: var(--ink);
    cursor: pointer;
    padding: 10px 13px;
    border: 1px solid var(--line);
    border-radius: 11px;
  }

  .side {
    display: none;
    width: auto;
    border-inline-end: 0;
    border-bottom: 1px solid var(--line);
    padding: 14px 16px 18px;
  }
  .side .logo { display: none; }
  .side .foot { margin-top: 16px; }
  .nav-toggle:checked ~ .shell .side { display: flex; }

  .main { padding: 18px 16px 24px; max-width: none; }
  h1 { font-size: 21px; margin-bottom: 16px; }
  h2 { font-size: 16px; margin: 22px 0 10px; }

  .stat-row { grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 20px; }
  .stat { padding: 14px 16px; }
  .stat-head { gap: 9px; margin-bottom: 9px; }
  .stat-ico { width: 32px; height: 32px; }
  .stat .l { font-size: 12.5px; }
  .stat .v { font-size: 26px; }
  .grid2 { grid-template-columns: 1fr; gap: 16px; }
  .form-grid { grid-template-columns: 1fr; }

  /* Tap targets. */
  .btn { padding: 11px 18px; min-height: 44px; }
  .btn.small { padding: 9px 14px; min-height: 40px; }
  input, select, textarea { padding: 11px 12px; }

  /* Column-header tables opt into the card layout below by carrying data-label.
     What remains is header-less or key-value, and fits 390 unaided - so no
     min-width is forced on them. .card keeps overflow-x as a safety net for any
     future wide table rather than as the routine behaviour. */
  .card { overflow-x: auto; }

  /* Inline forms are the densest thing in these cells; let them wrap rather than
     push their card sideways. */
  form.inline { flex-wrap: wrap; }

  table:has(td[data-label]) { min-width: 0; }
  /* These tables carry their header as a bare <tr><th> with no <thead>, so both
     shapes have to be hidden - matching only thead leaves the header row laid out
     as a table row while every other row is a block, and it overflows the card. */
  table:has(td[data-label]) thead,
  table:has(td[data-label]) tr:has(th) { display: none; }
  table:has(td[data-label]),
  table:has(td[data-label]) tbody,
  table:has(td[data-label]) tr,
  table:has(td[data-label]) td { display: block; }
  table:has(td[data-label]) tr {
    border: 1px solid var(--line);
    border-radius: var(--r-tile);
    padding: 10px 12px;
    margin-bottom: 10px;
  }
  table:has(td[data-label]) td {
    border-bottom: 0;
    padding: 5px 0;
    display: flex;
    align-items: center;
    gap: 10px;
    white-space: normal;
  }
  table:has(td[data-label]) td::before {
    content: attr(data-label);
    color: var(--ink-3);
    font-size: 12px;
    min-width: 84px;
    flex-shrink: 0;
  }

  /* The action cell carries no label and its buttons go full width - advancing an
     order is the whole reason this screen gets opened on a phone. */
  table:has(td[data-label]) td.cell-actions { flex-wrap: wrap; gap: 8px; padding-top: 10px; }
  table:has(td[data-label]) td.cell-actions::before { content: none; }
  table:has(td[data-label]) td.cell-actions form.inline { flex: 1 1 auto; }
  table:has(td[data-label]) td.cell-actions .btn { width: 100%; }

  /* One column of cards, and the action that advances an order goes full width -
     this is the single thing the board exists to do from a phone. */
  .board { grid-template-columns: 1fr; gap: 22px; }
  .ocard-acts { width: 100%; margin-inline-start: 0; }
  .ocard-acts form.inline { flex: 1 1 auto; }
  /* 44px, not the 40px .btn.small carries: this is the most-tapped control in
     the admin, and it is tapped standing up in a kitchen. */
  .ocard-acts .btn { width: 100%; min-height: 44px; }
  .board-meta { gap: 10px; }
  .board-done { margin-inline-start: 0; }

  /* Ranked bars restack: name and value on one line, the bar full width below. */
  .hbar { grid-template-columns: minmax(0, 1fr) auto; gap: 4px 10px; }
  .hbar .track { grid-column: 1 / -1; order: 3; }
  .funnel .step { padding-inline-start: 0; }

  /* Translation inputs go full width rather than pushing their card sideways, and
     an option's translation row stays welded to the option card above it (#525). */
  .i18n-inline label.mini { flex: 1 1 150px; }
  .i18n-inline input[type="text"] { width: 100%; min-width: 0; }
  table:has(td[data-label]) tr.i18n-row {
    margin-top: -10px;
    border-top: 0;
    border-start-start-radius: 0;
    border-start-end-radius: 0;
  }

  .image-row { gap: 16px; }
  .item-photo { width: 132px; height: 132px; }
}

@media (max-width: 600px) {
  body { font-size: 14px; }
  .stat-row { grid-template-columns: 1fr; }
  .range-form { gap: 10px; }
  .cat-head { align-items: flex-start; }
}

/* Motion is decorative here; honour the preference. */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* #578: the coupon-game odds field reads as one sentence ("one in every N orders wins") with the
   number input inline, the same compact shape as label.mini on the pricing pages. */
.form-grid .inline-field { display: inline-flex; align-items: center; gap: 8px; color: var(--ink); font-weight: 400; font-size: 13.5px; }
.form-grid .inline-field input[type="number"] { width: 76px; }

/* Upsell pool editor (#579): one card per menu category, each an htmx swap target. */
.pool-cat > h3 { margin: 0 0 10px; font-size: 15px; }
.pool-cat.htmx-request { opacity: .6; transition: opacity .12s ease; }
.pool-add { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; margin-top: 12px; }
.pool-add select { min-width: 190px; }
.pool-add input[type="text"] { width: 96px; }
.pool-kind { display: inline-flex; align-items: center; gap: 6px; font-weight: 400; font-size: 13px; }
.form-grid .pool-kind { flex-direction: row; }
.pool-error { margin: 0 0 10px; color: var(--st-bad); font-size: 12.5px; }
/* The in-place discount edit sits in the actions column, so its value field keeps the
   add row's compact width instead of the browser's default text-input width. */
.pool-cat td.cell-actions input[type="text"] { width: 76px; }
