/*
 * tokens.css -- design tokens for pbrs_manager
 *
 * Every colour used anywhere in the application is named here, exactly once,
 * and nowhere else. app.css, app.js and every template reach colour only
 * through var(--color-*) or var(--shadow-float). See DESIGN.md for the
 * rationale: a greenish tinted slate, not navy, with the brand green kept
 * under ten percent of the surface and never doubling as a status colour.
 *
 * Theme handling: the light palette lives on bare :root as the baseline
 * (so a no-JS render is still correct). The dark palette repeats twice by
 * necessity of the pattern: once behind a prefers-color-scheme media query
 * for a visitor who never chose, and once behind [data-theme="dark"] so an
 * explicit choice always wins over the operating system. app.js is the only
 * script that ever sets or clears the data-theme attribute, and only for an
 * explicit choice -- "system" is expressed by the attribute being absent.
 */

:root {
  /* ================= fonts ================= */
  --font-mono: 'Martian Mono', ui-monospace, 'Cascadia Mono', 'Consolas', 'SFMono-Regular', monospace;
  --font-sans: 'Familjen Grotesk', 'Segoe UI', system-ui, -apple-system, sans-serif;

  /* ================= spacing: fixed 4px base grid (DESIGN.md) ================= */
  --space-4: 0.25rem;
  --space-8: 0.5rem;
  --space-12: 0.75rem;
  --space-16: 1rem;
  --space-24: 1.5rem;
  --space-32: 2rem;
  --space-48: 3rem;
  --space-64: 4rem;

  /* ================= type scale: fixed steps (DESIGN.md) ================= */
  --text-12: 0.75rem;
  --text-13: 0.8125rem;
  --text-15: 0.9375rem;
  --text-17: 1.0625rem;
  --text-21: 1.3125rem;
  --text-27: 1.6875rem;

  /* ================= radii ================= */
  --radius-sm: 2px;
  --radius-md: 4px;
  --radius-lg: 8px;
  --radius-pill: 999px;

  /* ================= borders ================= */
  --border-width: 1px;
  --border-width-strong: 2px;

  /* ================= motion: 120-200ms, decelerating, never size/position ===== */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast: 120ms;
  --duration-base: 200ms;

  /* ================= layout ================= */
  /* 36px, the height of a table row. The header used to be 48px and carried
     the same three controls in the same one line -- the twelve pixels were
     air. On a laptop screen the plan grid wins them, which is one station
     more on the screen without a single row getting shorter. */
  --header-height: 2.25rem;
  --row-height: 36px;
  /* The plan grid packs its rows tighter than a table, because a booking bar
     carries a word and a table row carries eight columns. Fifteen stations
     fit a laptop screen at this height; below it a finger cannot hit a bar. */
  --row-height-compact: 26px;

  /* Density: how much room a hit target gets.
   *
   * This used to be decided by `any-pointer: coarse` alone, and that question
   * cannot be answered by a media query. An iPad with a keyboard reports a
   * *fine* primary pointer while its screen still takes a finger, and a
   * Windows laptop with a touchscreen reports a *coarse* pointer available
   * while the person is using a mouse. Both answer every query identically,
   * so whichever query is picked is wrong on one of the two -- and it was
   * wrong on the laptop, which spent every page in the iPad layout and lost
   * a third of the plan grid to it.
   *
   * So the media query only sets the *default*, and a person can overrule it;
   * `data-density` is then present exactly as `data-theme` is, absent meaning
   * nobody chose. `0px` is not "no minimum" by accident -- it is the value
   * that makes `min-height: var(--tap)` a no-op, so the touch rules can stay
   * where they are and simply stop having an effect. */
  --tap: 0px;
  --row-min: var(--row-height-compact);
  --content-max-width: 1680px;

  /* =====================================================================
   * Colour -- light, the baseline on bare :root.
   * Greenish slate (hue 155), chroma 0.004-0.014, not blue, not grey.
   * ===================================================================== */
  color-scheme: light;

  --color-bg: oklch(0.985 0.004 155);
  --color-surface: oklch(0.965 0.005 155);
  --color-surface-2: oklch(0.935 0.006 155);
  --color-border: oklch(0.885 0.008 155);
  --color-border-strong: oklch(0.79 0.010 155);

  --color-text: oklch(0.22 0.014 155);
  --color-text-2: oklch(0.44 0.012 155);
  --color-text-3: oklch(0.56 0.010 155);

  /* Accent: the one brand colour. Active element, primary button, focus
     ring. Never a status. */
  --color-accent: oklch(0.50 0.125 152);

  /* Traffic light: separate from the accent, exclusively for device and
     connection state. "unknown" is not a colour of its own, it borrows the
     third text tier so an unread state does not compete with real ones. */
  --color-good: oklch(0.50 0.140 148);
  --color-warning: oklch(0.55 0.130 62);
  --color-critical: oklch(0.52 0.185 25);
  --color-unknown: var(--color-text-3);

  /* Event palette. Identity, never state: which event a booking on the plan
     belongs to. Eight hues far enough apart to be told apart at four pixels
     wide, all at one lightness so no event looks more important than another,
     and at a chroma below the traffic light so a plan full of bookings stays
     quieter than one alarming station. The brand hue (152) is deliberately
     absent: the accent marks the active element and must not also mean "the
     Volksfest". Used only on the station plan. */
  --color-event-1: oklch(0.55 0.115 20);
  --color-event-2: oklch(0.55 0.110 60);
  --color-event-3: oklch(0.55 0.105 100);
  --color-event-4: oklch(0.55 0.100 185);
  --color-event-5: oklch(0.55 0.110 220);
  --color-event-6: oklch(0.55 0.115 260);
  --color-event-7: oklch(0.55 0.110 300);
  --color-event-8: oklch(0.55 0.115 340);

  /* The one shadow in the whole application, reserved for things that
     genuinely float above the page: open menus, short-lived tooltips.
     Nothing at rest carries a shadow. */
  --shadow-float: 0 8px 24px oklch(0.26 0.02 155 / 0.16);
}

/* Nobody chose a density: a coarse pointer anywhere is the better guess,
   because getting it wrong on a tablet costs a missed tap and getting it
   wrong on a laptop costs only space. The switch in the header settles it
   either way. */
@media (any-pointer: coarse) {
  :root:not([data-density]) {
    --tap: 2.75rem;
    --row-min: 2.75rem;
  }
}

:root[data-density="touch"] {
  --tap: 2.75rem;
  --row-min: 2.75rem;
}

:root[data-density="compact"] {
  --tap: 0px;
  --row-min: var(--row-height-compact);
}

/* Nobody chose yet: follow the operating system, unless it was overruled
   by an explicit light choice (handled by staying on the :root baseline
   above, since this rule only fires for prefers-color-scheme: dark). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --color-bg: oklch(0.17 0.010 155);
    --color-surface: oklch(0.215 0.011 155);
    --color-surface-2: oklch(0.262 0.012 155);
    --color-border: oklch(0.315 0.012 155);
    --color-border-strong: oklch(0.42 0.014 155);

    --color-text: oklch(0.955 0.006 155);
    --color-text-2: oklch(0.79 0.010 155);
    --color-text-3: oklch(0.64 0.012 155);

    --color-accent: oklch(0.72 0.115 152);

    --color-good: oklch(0.76 0.145 148);
    --color-warning: oklch(0.80 0.130 78);
    --color-critical: oklch(0.68 0.175 22);
    --color-unknown: var(--color-text-3);

    /* The event palette, lifted for the dark surface. Same eight hues, same
       order, so an event keeps its colour when the theme changes. */
    --color-event-1: oklch(0.75 0.105 20);
    --color-event-2: oklch(0.75 0.100 60);
    --color-event-3: oklch(0.75 0.095 100);
    --color-event-4: oklch(0.75 0.090 185);
    --color-event-5: oklch(0.75 0.100 220);
    --color-event-6: oklch(0.75 0.105 260);
    --color-event-7: oklch(0.75 0.100 300);
    --color-event-8: oklch(0.75 0.105 340);

    --shadow-float: 0 8px 24px oklch(0 0 0 / 0.45);
  }
}

/* An explicit choice always wins over the operating system, in both
   directions -- this block only ever applies when app.js set data-theme
   itself after the visitor picked "Dark" in the theme switch. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --color-bg: oklch(0.17 0.010 155);
  --color-surface: oklch(0.215 0.011 155);
  --color-surface-2: oklch(0.262 0.012 155);
  --color-border: oklch(0.315 0.012 155);
  --color-border-strong: oklch(0.42 0.014 155);

  --color-text: oklch(0.955 0.006 155);
  --color-text-2: oklch(0.79 0.010 155);
  --color-text-3: oklch(0.64 0.012 155);

  --color-accent: oklch(0.72 0.115 152);

  --color-good: oklch(0.76 0.145 148);
  --color-warning: oklch(0.80 0.130 78);
  --color-critical: oklch(0.68 0.175 22);
  --color-unknown: var(--color-text-3);

  /* The event palette, lifted for the dark surface. Same eight hues, same
     order, so an event keeps its colour when the theme changes. */
  --color-event-1: oklch(0.75 0.105 20);
  --color-event-2: oklch(0.75 0.100 60);
  --color-event-3: oklch(0.75 0.095 100);
  --color-event-4: oklch(0.75 0.090 185);
  --color-event-5: oklch(0.75 0.100 220);
  --color-event-6: oklch(0.75 0.105 260);
  --color-event-7: oklch(0.75 0.100 300);
  --color-event-8: oklch(0.75 0.105 340);

  --shadow-float: 0 8px 24px oklch(0 0 0 / 0.45);
}
