/* ============================================================================
 * tokens.css -- ONE palette, one type scale, one spacing scale, one button.
 *
 * Before this file there were NINE `:root` blocks across the pilot-facing pages
 * (the audit counted six and missed `review.html`'s light theme and
 * `book_review.html`), in three colour notations, carrying three different
 * palettes. The shared values agreed by luck rather than structure, and were
 * already drifting -- `--fg` duplicated `--text`, `--amber` existed in two files
 * and not the others, `--sel` was a hex in an oklch system, `--red` lived only in
 * privacy.html. A line added to any of those files was a coin toss about which
 * palette it landed in, which is how `workspace.css` grew another literal `#fff`
 * the day after the audit named that file for exactly that.
 *
 * So: every pilot-facing page links this file FIRST, and its own `<style>` keeps
 * only what is genuinely local to that screen (a row grid, a canvas swatch, a
 * band tint). Tokens, never literals.
 *
 * The palette is `/book`'s warm-dark oklch family, which is the one the pilot
 * meets first and the one D1 settles on for every screen including the workspace
 * and the grid editor.
 *
 * Load order matters: this file is linked in `<head>` BEFORE each page's inline
 * `<style>`, so a page can still override a component deliberately (the Columns
 * screen's condensed bar does). The four copied `.primary`/`.ghost` blocks were
 * deleted rather than left to win by being later.
 * ========================================================================= */

:root {
  /* ---- surfaces ------------------------------------------------------- */
  --bg:         oklch(0.18 0.01 60);        /* the page */
  --panel:      oklch(0.21 0.01 60);        /* cards, bars, sidebars */
  --panel2:     oklch(0.235 0.01 60);       /* a panel on a panel */
  --stagebg:    oklch(0.14 0.01 60);        /* behind an image or a canvas */
  --stageframe: oklch(0.2 0.01 60);
  --border:     oklch(0.28 0.01 60);
  --rowdiv:     oklch(0.24 0.01 60);        /* table row divider */
  --selbg:      oklch(0.23 0.015 60);       /* a selected row's fill */
  --hover:      oklch(0.21 0.01 60);
  --barbg:      oklch(0.14 0.01 60 / 0.92); /* sticky bars, over content */
  --overlaybg:  oklch(0.14 0.01 60 / 0.82); /* modal backdrop */

  /* ---- ink ------------------------------------------------------------- */
  --text:     oklch(0.92 0.01 80);
  --text2:    oklch(0.78 0.01 80);
  --muted:    oklch(0.62 0.012 70);
  --dim:      oklch(0.48 0.012 70);
  --disabled: oklch(0.38 0.012 70);

  /* ---- brand ----------------------------------------------------------- */
  --accent:   oklch(0.74 0.13 65);          /* links, focus, the active thing */
  --accentbg: oklch(0.32 0.06 65 / 0.5);

  /* ---- the state colours, and what each one is ALLOWED to mean ---------
   * D4: the test is not "is this bad" but "IS THE PILOT STOPPED".
   *   --check   needs checking. The pilot can carry on; we would like them to
   *             look. Grid-line counts that disagree with the template, a page
   *             flagged in the book, a value we are unsure of. ONE colour for
   *             all of it -- review v2 already did this and is the reference.
   *   --red     BLOCKING only. A save that did not happen, an upload that
   *             failed. Nothing else, ever.
   *   --filled  we filled this in for you (teal).
   *   --ok      done, passed, present.
   */
  --check:   oklch(0.78 0.13 75);
  --checkbg: oklch(0.32 0.055 75 / 0.35);
  --filled:  oklch(0.78 0.09 185);
  --ok:      oklch(0.70 0.10 155);
  --green:   var(--ok);                     /* old name, kept so nothing breaks */
  --red:     oklch(0.68 0.17 25);
  --redbg:   oklch(0.3 0.08 25 / 0.35);

  /* ---- the two pages of a spread (D3) ---------------------------------
   * One pair on EVERY screen -- the wizard's Edges step, Fix photo and the
   * review alike. Magenta and cyan are chosen because neither is anywhere on a
   * logbook page: not the cream paper, not the printed rules, not any pen a
   * pilot writes with. They are also about as far apart as two inks get, which
   * is the whole requirement for "which page is this".
   *
   * These two are HEX on purpose. A <canvas> cannot read a CSS variable, so the
   * same literals are stroked in JS; keeping the CSS in hex means a reader can
   * grep one string and find both halves.
   */
  --page-left:  #e0218a;
  --page-right: #16c8e8;

  /* ---- selected (D7) ---------------------------------------------------
   * Pink now means "left page" and nothing else, so selection cannot also be
   * pink. White is the only colour left carrying no meaning -- which is why the
   * old "no white anywhere" rule becomes "WHITE IS SELECTION ONLY". A selected
   * thing takes a white outline and a soft glow, never a white fill.
   */
  --sel-outline: oklch(0.99 0 0);
  --sel-glow:    oklch(0.99 0 0 / 0.28);

  /* ---- type ------------------------------------------------------------ */
  --serif: 'Source Serif 4', Georgia, serif;   /* screen + section titles */
  --sans:  Geist, 'Helvetica Neue', Helvetica, sans-serif;
  --mono:  'Geist Mono', ui-monospace, monospace;

  /* Six sizes, no half-pixels. There were 24 distinct sizes, five of them
   * fractional, with 11/11.5/12/12.5/13/13.5/14 doing the work of about three. */
  --t-label: 11px;   /* mono labels, table headers: uppercase, 0.08em tracking */
  --t-help:  13px;   /* secondary and help text */
  --t-body:  14px;   /* body, and EVERY button label */
  --t-input: 16px;   /* every form input -- iOS zooms the page below this */
  --t-sect:  19px;   /* section titles (serif) */
  --t-title: 26px;   /* screen titles (serif) */

  /* ---- spacing and geometry -------------------------------------------
   * 4px base: 4, 8, 12, 16, 24, 32, 48 and nothing else.
   * Breakpoints are TWO: 760px (phone) and 1100px (narrow desktop). Seven were
   * in use (560/640/700/760/860/900/1000) with no scale behind them.
   */
  --ctl:      40px;    /* one control height: inputs, buttons, selects */
  --touch:    44px;    /* minimum under (pointer: coarse) -- see touch.css */
  --r-ctl:    6px;
  --r-card:   8px;
  --r-pill:   999px;
  --gutter:   16px;    /* phone */
  --gutter-d: 32px;    /* desktop */
  --barpad:   8px 16px;
  --w-page:   1180px;  /* wide-screen content */
  --w-prose:  720px;   /* prose: privacy, help */
  /* #31: how much of the grid editor's bottom sheet shows when it is closed -- the handle
   * plus the one primary. The sheet's transform and the canvas's bottom padding both read
   * it, so they cannot disagree and leave the canvas under the sheet. */
  --ge-peek:  104px;
}

/* ============================================================================
 * ONE BUTTON, two ranks. These were copy-pasted into four files and had drifted
 * to four geometries -- in `/book` a `.primary` (40px) sat beside a `.ghost`
 * (44px) and was visibly 4px shorter, and `/book`'s primary was the only one
 * with no `:disabled` state at all. One definition, 40px, centred, both states.
 *
 * `label.primary` is included because a label is inline by default, so height
 * and padding would do nothing to it; `a.ghost` because "Open workspace" is a
 * link dressed as a button.
 * ========================================================================= */
button.primary, label.primary, a.primary,
button.ghost, label.ghost, a.ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: var(--ctl); padding: 0 18px;
  font-family: var(--sans); font-size: var(--t-body); font-weight: 500;
  border-radius: var(--r-card); cursor: pointer; white-space: nowrap; flex: none;
  text-decoration: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
}
button.primary, label.primary, a.primary {
  border: 1px solid transparent; background: var(--text); color: var(--bg);
}
button.primary:hover, label.primary:hover, a.primary:hover { background: oklch(0.94 0.025 85); }
button.ghost, label.ghost, a.ghost {
  border: 1px solid var(--border); background: transparent; color: var(--text);
}
button.ghost:hover, label.ghost:hover, a.ghost:hover {
  border-color: var(--text); background: var(--panel);
}
button.primary:disabled, button.ghost:disabled,
button.primary[disabled], button.ghost[disabled] {
  opacity: 0.45; cursor: not-allowed;
}
/* `.small` is the one size variant worth keeping: a ghost inside a card row. */
a.ghost.small, button.ghost.small {
  height: 36px; padding: 0 14px; font-size: var(--t-help);
}

/* THE PHONE NOTE (phone_note.js): one line, in the flow, above the work.
 *
 * `display: none` by default and shown ONLY on a narrow screen with a coarse pointer -- a
 * small desktop window is not a phone, and an iPad is one of the two things the note
 * recommends. This base rule PRECEDES the media query on purpose: same specificity, so
 * written after it would win on source order and the note would never appear. That is twice
 * now (the sheet handle, the bar's toggle), which is why it is said here too.
 *
 * It is a note and not a gate: normal flow, one line, nothing overlaid, nothing disabled. */
.phonenote { display: none; }
@media (max-width: 760px) and (pointer: coarse) {
  .phonenote {
    display: flex; align-items: center; gap: 8px;
    padding: 8px var(--gutter); background: var(--checkbg);
    border-bottom: 1px solid var(--check); color: var(--text);
    font-family: var(--sans); font-size: var(--t-help); line-height: 1.35;
    flex: none;
  }
  /* TWO CLASSES, NOT ONE, on both children. The grid editor sets `.ge button { width: 100% }`
     for its sidebar, which is (0,1,1) and beats a lone `.phonenote-x` at (0,1,0) -- the close
     button took the whole row and squeezed the sentence to one word per line. A shared
     component dropped into a page with opinions has to out-specify them. */
  .phonenote .phonenote-t { flex: 1 1 auto; min-width: 0; }
  .phonenote .phonenote-x {
    flex: none; width: 44px; height: 44px; min-height: 44px; padding: 0;
    margin: -8px -8px -8px 0;
    background: none; border: 0; color: var(--text2);
    font-size: 20px; line-height: 1; cursor: pointer;
  }
  .phonenote .phonenote-x:hover { color: var(--text); background: none; }
}

/* =========================================================================
 * THE CONTROLS THE BROWSER DRAWS ITSELF
 *
 * A <select>'s popup is not part of the page. Windows Chrome and Edge draw it
 * as their own widget, and with no `color-scheme` they draw it LIGHT -- while
 * still handing it the page's `color`, which here is a pale warm grey meant
 * for a dark panel. That is exactly /book's "Change template to..." dropdown:
 * pale grey text on a white list (Logan, 2026-11-10).
 *
 * TWO DECLARATIONS, because neither does the whole job:
 *   `color-scheme: dark` is the only thing that makes Chrome and Edge draw the
 *   popup -- and its scrollbar, its hover and its focus ring -- dark at all.
 *   No amount of `background` on the <select> reaches them.
 *   `option` / `optgroup` colours are what make that popup the WARM dark of
 *   this app instead of the browser's neutral near-black.
 *
 * IT IS ON `select`, NOT ON `:root`, ON PURPOSE. Review v1 is still a light
 * theme (audit item 23, deliberately not in the cohesion pass), and a document
 * -wide dark scheme would turn its native controls inside out on a #f7f8fa
 * page. `color-scheme` inherits, so putting it here reaches the options and
 * nothing else; review.html opts its own v1 selects back out.
 *
 * SPECIFICITY IS (0,0,1) ON PURPOSE TOO: every screen that already dresses its
 * own select -- `select#book`, `.calibpick select`, `.selbox select.tplchange`,
 * `body.v2 .v2box .cell select.valsel` -- still wins for the CLOSED control.
 * What they cannot express, and what this adds, is the popup.
 * ========================================================================= */
select {
  color-scheme: dark;
  background-color: var(--panel);
  color: var(--text);
}
select:disabled { color: var(--disabled); }
/* The popup's rows. Measured honoured in Chromium on Windows (the engine Chrome and Edge
   both use, and the one this was checked in). Other engines vary in how far they let a page
   paint a native popup -- which is why `color-scheme` comes first: it is the part every
   engine applies, and on its own it already gets the popup out of white. */
option {
  background-color: var(--panel);
  color: var(--text);
}
/* A group heading is not a choice, so it reads as a label and never as a row
   the pilot could pick. The wizard's field list is all optgroups. */
optgroup {
  background-color: var(--panel);
  color: var(--muted);
  font-style: normal;
}
optgroup option { color: var(--text); }
option:disabled { color: var(--disabled); }
/* The row under the cursor and the row already chosen. Both are the app's
   accent surface rather than the browser's blue. */
option:checked { background-color: var(--selbg); color: var(--text); }

/* The selected state, once, so every screen spells it the same way (D7). */
.is-selected {
  outline: 2px solid var(--sel-outline);
  outline-offset: 1px;
  box-shadow: 0 0 0 4px var(--sel-glow);
}
