/* Shared design tokens for every operator surface.
 *
 * Why this file exists: the console, the till, the onboarding page and the
 * operations dashboard each defined their own colours, spacing and radii. Nothing
 * enforced consistency, so they drifted, and a fix to one never reached the
 * others. Worse, the member app carried a scheme aware palette while the console
 * carried a hardcoded light one, so a console opened on a phone in dark mode
 * looked broken. One file, served to all of them, is the fix.
 *
 * Two rules for anything using these tokens:
 *   1. Never write a raw colour in a page. If a token is missing, add it here.
 *   2. A layout may set spacing and radius, never a colour outside a scheme.
 *      That second rule is not style pedantry: a rule on body beats a rule on
 *      :root, so a colour set by a layout survives into dark mode and produced
 *      white text on white cards in the member app.
 *
 * Per-tenant brand colours are layered on top of these at runtime, computed for
 * contrast, which is why --brand and --accent are declared but left neutral here.
 */

:root {
  /* Brand, replaced per tenant at runtime and kept legible by theme.js */
  --brand: #1f3864;
  --accent: #2e74b5;
  /* What is legible ON the brand colour. White is only right for a dark brand, so
     the page recomputes this from the tenant's own colour at load. */
  --on-brand: #ffffff;
  --on-accent: #ffffff;
  --ok: #2f7d4f;
  /* Paper. Deliberately white in both schemes, for the two things that must stay
     dark on light whatever the operator's colour scheme: a QR code and a barcode
     have to scan, and a scanner does not have a dark mode. */
  --paper: #ffffff;
  --paper-ink: #101828;

  /* Surfaces, from the page backwards */
  --page: #f4f6fa;
  --surface: #ffffff;
  --surface-sunk: #f7f9fc;
  --line: #e2e8f0;
  /* --line is a hairline divider, which is decoration. --line-strong is the edge of
     a control, which is not: WCAG asks for 3:1 against the surface behind it, and
     the old value managed 1.51, so an input barely existed until you clicked in it.
     Girish spotted it by eye before the numbers were checked. */
  --line-strong: #7d8b9e;

  /* Text. --muted is used at 12 and 13px, so it carries a 4.5:1 obligation
     against every surface above, not just against white. */
  --ink: #1b2330;
  --ink-soft: #48546a;
  --muted: #5c687d;

  /* Meaning. Used for state, never for decoration. */
  --good: #1f6b40;
  --good-bg: #e8f4ec;
  --warn: #8a5300;
  --warn-bg: #fdf4e3;
  --bad: #a52c2c;
  --bad-bg: #fbecec;
  /* A filled destructive button, as opposed to --bad which is text. Kept as a token
     rather than left to each page, because the dialog had it hardcoded and so was the
     one control on the platform that could not follow a colour scheme. */
  --bad-solid: #99302f;
  --on-bad: #ffffff;
  --info: #1d5a94;
  --info-bg: #e9f1fa;

  /* Shape and rhythm */
  --radius: 8px;
  --radius-card: 12px;
  --gap-xs: 6px;
  --gap-sm: 10px;
  --gap: 14px;
  --gap-lg: 20px;
  --pad-card: 16px 18px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow-raised: 0 4px 16px rgba(16, 24, 40, .10);

  /* Type scale */
  --font: -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --size-title: 20px;
  --size-heading: 15px;
  --size-body: 14px;
  --size-small: 13px;
  --size-tiny: 12px;

  --content-max: 1080px;
}

/* Dark, twice, and deliberately so.
 *
 * The machine's own preference is honoured by default, which is what a browser
 * expects. But a person also has to be able to say "give me the light one", because a
 * console is read next to a paper report under shop lighting, and one of the two
 * schemes will always be wrong for somebody. So an explicit choice on <html> wins over
 * the machine, and the machine wins when no choice has been made.
 *
 * That needs the palette in two rules, and two copies of anything drift. The suite
 * therefore asserts the two blocks declare the same variables with the same values, so
 * a change to one that misses the other fails the gate rather than reaching a screen.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --page: #0f1319;
    --surface: #171c24;
    --surface-sunk: #12161d;
    --line: #262e3a;
    --line-strong: #657590;

    --ink: #e9edf4;
    --ink-soft: #b3bdcc;
    --muted: #98a3b4;

    --good: #74d19a;
    --good-bg: #16281d;
    --warn: #e8b562;
    --warn-bg: #2a2113;
    --bad: #f09b9b;
    --bad-bg: #2c1a1a;
    --info: #8dbcea;
    --info-bg: #14202c;

    --shadow: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-raised: 0 4px 16px rgba(0, 0, 0, .5);
    --bad-solid: #c14a48;
    --on-bad: #1a0f0f;
  }
}
:root[data-theme="dark"] {
    --page: #0f1319;
    --surface: #171c24;
    --surface-sunk: #12161d;
    --line: #262e3a;
    --line-strong: #657590;

    --ink: #e9edf4;
    --ink-soft: #b3bdcc;
    --muted: #98a3b4;

    --good: #74d19a;
    --good-bg: #16281d;
    --warn: #e8b562;
    --warn-bg: #2a2113;
    --bad: #f09b9b;
    --bad-bg: #2c1a1a;
    --info: #8dbcea;
    --info-bg: #14202c;

    --shadow: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-raised: 0 4px 16px rgba(0, 0, 0, .5);
    --bad-solid: #c14a48;
    --on-bad: #1a0f0f;
}

/* ---------------------------------------------------------------------------
 * Primitives. Deliberately few: enough to build an operator screen without
 * inventing a component library, and small enough to read in one sitting.
 * ------------------------------------------------------------------------ */

* { box-sizing: border-box; margin: 0; font-family: var(--font); }

body {
  background: var(--page);
  color: var(--ink);
  font-size: var(--size-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--info); }

.wrap { max-width: var(--content-max); margin: 0 auto; padding: 0 18px 56px; }

/* Cards */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: var(--pad-card);
  margin-bottom: var(--gap);
  box-shadow: var(--shadow);
}
.card > h2 {
  font-size: var(--size-heading);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}
.card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-sm); flex-wrap: wrap; margin-bottom: var(--gap-sm);
}

/* A card that folds away.
   For the panels that report rather than do: they grow without limit and push
   everything below them off the screen. Built on details and summary so it works
   with the keyboard, is announced by a screen reader as expandable, and needs no
   script: a fold that depends on JavaScript is a card stuck shut when a script
   fails. */
.card > details > summary {
  cursor: pointer;
  display: flex; align-items: baseline; gap: var(--gap-sm);
  font-size: var(--size-heading); font-weight: 600; color: var(--ink);
  list-style: none;
}
.card > details > summary::-webkit-details-marker { display: none; }
/* Our own marker, so it points the way the fold will go rather than relying on
   whatever the browser draws. */
.card > details > summary::after {
  content: 'Show';
  margin-left: auto;
  font-size: var(--size-small); font-weight: 500; color: var(--accent);
}
.card > details[open] > summary::after { content: 'Hide'; }
.card > details > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
.card > details > summary .count { font-size: var(--size-small); font-weight: 400; color: var(--muted); }
.card > details > *:not(summary) { margin-top: var(--gap-sm); }
/* Every card ends the same way: a quiet explanation on the left, the action on
   the right. Consistency here is what stopped buttons floating at three
   different alignments down the page. */
.card-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-sm); flex-wrap: wrap;
  margin-top: var(--gap); padding-top: 12px; border-top: 1px solid var(--line);
}
.card-foot .hint { font-size: var(--size-tiny); color: var(--muted); }

/* Metrics. auto-fit rather than a fixed column count, so the last card is never
   orphaned on a row of its own at an awkward width. */
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--gap-sm); margin-bottom: var(--gap); }
.metric { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-card); padding: 13px 15px; }
.metric .label { font-size: var(--size-tiny); color: var(--muted); display: flex; align-items: center; gap: 5px; }
.metric .value { font-size: 25px; font-weight: 600; color: var(--ink); letter-spacing: -.4px; line-height: 1.25; }
.metric .note { font-size: var(--size-tiny); color: var(--muted); }
.metric .note.up { color: var(--good); }
.metric .note.attention { color: var(--warn); }

/* Controls */
label { font-size: var(--size-small); color: var(--ink-soft); display: block; }
input, select, textarea {
  font-size: var(--size-body); color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 9px 10px; width: 100%; max-width: 100%;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--info-bg); }
input[type=checkbox] { width: auto; }
.field { display: block; margin-bottom: var(--gap-sm); }
.field > span { display: block; font-size: var(--size-small); color: var(--ink-soft); margin-bottom: 4px; }
/* align-items: end matters more than it looks. Grid items stretch by default, so a
   label that wraps onto a second line pushes its own input down while the input beside
   it stays up, and a row of boxes ends up on two different lines. Aligning the bottom
   of each cell puts every input on the same line whatever its label does, at any width.
   Reported by Girish on the Earn rules row, where "Remind before a reward closes
   (days)" wraps and its box sat below the rest. */
.fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
          gap: var(--gap-sm) var(--gap); align-items: end; }

button {
  font-size: var(--size-small); font-weight: 500; cursor: pointer;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 8px 14px;
}
button:hover { border-color: var(--accent); color: var(--accent); }
/* One filled action per card at most, which is what keeps a screen calm. */
button.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
button.primary:hover { filter: brightness(1.07); color: var(--on-accent); }
button.danger { color: var(--bad); border-color: var(--bad); }
button.danger:hover { background: var(--bad-bg); color: var(--bad); }
button.icon { padding: 6px 9px; line-height: 1; }
button:disabled { opacity: .55; cursor: default; border-color: var(--line); color: var(--muted); }

/* Tables */
table { width: 100%; border-collapse: collapse; font-size: var(--size-small); }
th, td { padding: 9px 8px; text-align: left; border-bottom: 1px solid var(--line); }
th { font-size: var(--size-tiny); font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; }
/* A scroll box with a pinned header, so a long list stays readable without
   paging being the only answer. */
.table-scroll { max-height: 420px; overflow-y: auto; border: 1px solid var(--line); border-radius: var(--radius); }
.table-scroll th { position: sticky; top: 0; background: var(--surface-sunk); z-index: 1; }
.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Rows that mix inputs with figures.
   A cell holding an input is taller than a cell holding a number, so with the
   default middle alignment the figures floated in the space beside the boxes and
   nothing lined up with anything. Everything is topped instead, and a plain cell
   gets the same top padding as an input's own text, so a number sits on the same
   line as the text in the box next to it. */
table.mixed td { vertical-align: top; }
table.mixed td.figure { padding-top: 18px; }
/* The line under an input, explaining it. Reserved space whether or not there is
   anything to say, so a row with a note is not taller than a row without one and
   the rows stop stepping down the page. */
table.mixed .cell-note {
  min-height: 1.2em; margin-top: 4px;
  font-size: var(--size-tiny); color: var(--muted);
}

/* Chips: a small removable tag. This is where the colour scheme bug showed itself
   in the field, as a pale pill with pale text on it, so the fill and the text on
   the fill are both tokens rather than one being assumed. */
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--surface-sunk); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 16px;
  padding: 5px 11px; margin: 3px 4px 3px 0; font-size: var(--size-small);
}
.chip a { color: var(--muted); text-decoration: none; font-size: var(--size-tiny); }
.chip a:hover { color: var(--bad); }

/* Status pills */
/* A tint alone is not enough to make a pill read as an object: in dark mode the
   warn tint sits 1.08:1 from the card behind it, so only the text showed and the
   badge did not command attention. The border does that work, and it comes from
   the state colour so it cannot be a mismatch. */
.pill { display: inline-block; font-size: var(--size-tiny); padding: 3px 10px; border-radius: 20px; border: 1px solid transparent; }
.pill.good { background: var(--good-bg); color: var(--good); border-color: var(--good); }
.pill.warn { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
.pill.bad { background: var(--bad-bg); color: var(--bad); border-color: var(--bad); }
.pill.info { background: var(--info-bg); color: var(--info); border-color: var(--info); }

/* Notices */
.notice { border-radius: var(--radius); padding: 11px 14px; font-size: var(--size-small); margin-bottom: var(--gap); }
.notice.warn { background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn); }
.notice.bad { background: var(--bad-bg); color: var(--bad); border: 1px solid var(--bad); }
.notice.good { background: var(--good-bg); color: var(--good); border: 1px solid var(--good); }
.notice.info { background: var(--info-bg); color: var(--info); border: 1px solid var(--info); }

.note { font-size: var(--size-tiny); color: var(--muted); }
.hidden { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
