/* tokens.css — the ONE vocabulary the shell and the public booking page are drawn in.
 *
 * Every colour, size, weight, tracking, space and radius on screen resolves to a name declared
 * here, and shell-tokens-gate.test.mjs refuses a raw value anywhere else — in the two
 * stylesheets, in HTML style attributes, and in the scripts' inline styles. That gate is the
 * point of this file: the shell declared a scale in 2026-08 and then grew twenty-six raw type
 * sizes, eighty spacing values and fourteen radii around it, one live review at a time. A
 * scale that nothing enforces is a comment.
 *
 * Reading order: colour, shape, type, space. Light first; the dark set below redefines only
 * colour, so a component that reads tokens is dark-correct without knowing it. There is no
 * theme toggle — the system decides — and color-scheme lets native pickers and the keyboard
 * follow the page instead of contradicting it.
 */
:root {
  color-scheme: light dark;

  /* ── Colour ── one green-biased neutral ramp, four semantic hues each with a soft ground. */
  --bg: #F2F5F4; --surface: #FFFFFF; --surface-2: #F7FAF9;
  --ink: #14201C; --ink-2: #3D4B46;
  /* --muted was #6C7B75: 4.2:1 on white and under 4:1 on --bg, just below legible on a phone
     in daylight. One step darker, same hue. */
  --muted: #5F6E68; --faint: #93A19D;
  --hairline: rgba(20,32,28,0.10); --hairline-soft: rgba(20,32,28,0.06);
  /* The two neutral fills the stylesheet had improvised ten variants of: control grounds and
     tracks/rails. */
  --fill: rgba(20,32,28,0.05); --fill-2: rgba(20,32,28,0.12);
  --chrome: rgba(242,245,244,0.82);
  --accent: #0B5D51; --accent-press: #094C42; --accent-soft: #E7F1EF; --accent-tint: #ECF4F2;
  /* Second tint pair (share-venue-colours, 2026-09-08): the Share tab tells two venues apart
     by chip colour, and the first attempt paired clinic's --accent-tint with the general grey
     surface fill (--surface-2) for mobile — reusing a SURFACE token whose entire job is to sit
     almost on top of --surface, not to be told apart from a second coloured pill beside it.
     Measured 1.00:1 contrast / 10 RGB-distance between --surface-2 and --accent-tint in dark
     mode: the two venues were not actually distinguishable. This is a cool slate hue rather
     than another shade of the green ramp, built the same way --accent-tint/--accent-press
     are — a background tint plus the text/icon colour that reads on it — so a second semantic
     pair follows the pattern the first one set rather than borrowing a token built for a
     different job. */
  --neutral-tint: #DDE3EA; --neutral-press: #33414F;
  /* --ok was a byte-for-byte alias of --accent, so the one reserved meaning in the app —
     money settled — was worn by every selected chip, the active tab, the add button and every
     primary control. A true green now, distinct from the teal that means "selected". */
  --ok: #1F7A3F; --ok-soft: #E3F3E8;
  --warn: #8F6300; --warn-soft: #FAF1DC;
  --bad: #B33720; --bad-soft: #FAEAE6; --bad-press: #8E2B19;
  --info: #2B5E8C; --info-soft: #E9F1F8;
  --shadow-card: 0 1px 1px rgba(20,32,28,0.04), 0 8px 24px -12px rgba(20,32,28,0.12);
  --shadow-pop: 0 1px 2px rgba(20,32,28,0.10), 0 3px 8px rgba(20,32,28,0.06);
  --shadow-fab: 0 6px 16px -6px rgba(11,93,81,0.55), 0 2px 4px rgba(20,32,28,0.12);
  /* Paper: a ground that stays white in BOTH schemes, with its own ink. For the one thing a
     phone is asked to show at maximum contrast regardless of appearance — a QR code a client
     scans in daylight. Not redefined in the dark set, on purpose. */
  --paper: #FFFFFF; --paper-ink: #14201C; --paper-muted: #5F6E68;

  /* ── Shape ── three radii and the pill. Containers lg, inset groups and menus md, controls sm. */
  --r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-pill: 999px;

  /* ── Type ── six sizes, four weights, two trackings, two leadings, two faces. */
  --t-cap: 11px; --t-sub: 13px; --t-body: 15px; --t-title: 17px; --t-lg: 22px; --t-display: 27px;
  --w-reg: 400; --w-med: 500; --w-semi: 600; --w-bold: 700;
  --tk-caps: 0.06em; --tk-tight: -0.02em;
  --lh-body: 1.45; --lh-tight: 1.2;
  --font: -apple-system, "SF Pro Text", system-ui, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* ── Space ── a 4px grid. --tap is the minimum height of anything a finger is asked to hit. */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;
  --tap: 44px; --tabbar-h: 60px;
  /* The desktop frame's left sidebar (index.html, html[data-layout="desktop"]). Read only
     under that attribute; the frame drops it under 66rem, where the sidebar stacks above the content. */
  --sidebar-w: 21rem;
  /* The desktop appointment panel (index.html, DESKTOP VISIT PANEL; reference.md §3.16): about 31%
     of the content column beside the sidebar, never narrower than the payment controls need. */
  --visit-panel-w: clamp(24rem, calc((100vw - var(--sidebar-w)) * 0.31), 36rem);
  /* The non-production banner's real rendered height (index.html DESKTOP FRAME; app.js
     syncEnvBannerHeight_): 0 by default — production carries no bar, and this is the value every
     desktop scroll container reserves as its bottom clearance before JS ever runs. The banner's
     own text can wrap to a second line depending on viewport width and which environment it
     names, so a fixed px guess would be wrong for some width or environment; this is measured,
     not guessed, and JS overwrites it on the root element once the page has a layout. */
  --envbar-h: 0px;
}

/* Per-account readability changes type only. Spacing and --tap stay fixed so Small never
   makes a control harder to hit, while Large does not create a second spacing system. */
:root[data-text-size="small"] {
  --t-cap: 10px; --t-sub: 12px; --t-body: 14px; --t-title: 16px; --t-lg: 20px; --t-display: 25px;
}
:root[data-text-size="large"] {
  --t-cap: 12px; --t-sub: 15px; --t-body: 17px; --t-title: 20px; --t-lg: 25px; --t-display: 31px;
}
/* These three app surfaces intentionally compact their local scale. Attribute + id specificity
   keeps that relationship while allowing the account choice to reach them too. */
:root[data-text-size="small"] #tab-book { --t-body: 13px; --t-sub: 12px; }
:root[data-text-size="large"] #tab-book { --t-body: 16px; --t-sub: 15px; }
:root[data-text-size="small"] #bookIntake { --t-body: 12px; --t-sub: 11px; }
:root[data-text-size="large"] #bookIntake { --t-body: 15px; --t-sub: 14px; }
:root[data-text-size="small"] #face-marketing {
  --t-body: 13px; --t-sub: 11px; --t-title: 15px; --t-cap: 10px;
}
:root[data-text-size="large"] #face-marketing {
  --t-body: 16px; --t-sub: 14px; --t-title: 19px; --t-cap: 12px;
}
/* iOS needs at least 16px on text-entry controls to avoid focus zoom. Small and Medium retain
   that floor; Large may grow it without changing the control's tap geometry. */
:root[data-text-size="large"] input:not([type=checkbox]):not([type=radio]):not([type=range]):not(.amtfield),
:root[data-text-size="large"] select,
:root[data-text-size="large"] textarea { --t-body: 18px; }

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0F1614; --surface: #182220; --surface-2: #1E2926;
    --ink: #F2F5F4; --ink-2: #C5CFCB; --muted: #8C9A94; --faint: #6E7D78;
    --hairline: rgba(242,245,244,0.12); --hairline-soft: rgba(242,245,244,0.07);
    --fill: rgba(242,245,244,0.06); --fill-2: rgba(242,245,244,0.14);
    --chrome: rgba(15,22,20,0.82);
    --accent: #5FBFAB; --accent-press: #7ACDBB; --accent-soft: #163530; --accent-tint: #142B27;
    --neutral-tint: #28313C; --neutral-press: #B4C2D2;
    --ok: #6FBF95; --ok-soft: #16301F;
    --warn: #D9A959; --warn-soft: #35290F;
    --bad: #E88379; --bad-soft: #3A1B17; --bad-press: #F0A198;
    --info: #7FB0DA; --info-soft: #172A3A;
    --shadow-card: 0 1px 1px rgba(0,0,0,0.30), 0 8px 24px -12px rgba(0,0,0,0.50);
    --shadow-pop: 0 1px 2px rgba(0,0,0,0.35), 0 3px 8px rgba(0,0,0,0.30);
    --shadow-fab: 0 6px 16px -6px rgba(0,0,0,0.60), 0 2px 4px rgba(0,0,0,0.30);
  }
}
