/*
 * HotelOS DS — TOKENS layer
 * ---------------------------------------------------------------------------
 * Layer 2 of 3 (base -> tokens -> components). Loads AFTER os_ds, on purpose.
 *
 * This is where HotelOS extends the base design system: it keeps os-ds's role
 * NAMES and repoints their primitive TARGETS (gray -> slate, sky -> teal), adds
 * the room-status vocabulary HotelOS needs, and supplies the handful of
 * primitives os-ds doesn't ship. Pinned by test/lint/hotelos_ds_test.rb.
 *
 * os-ds ships the shared ~90% and defaults to DiveOS (sky-700 + Inter).
 * arena-ops IS HotelOS: same role names, different primitive targets.
 *
 * WHY A LOAD-AFTER OVERRIDE: the gem's README documents re-theming by shadowing
 * tokens/semantic.css on the postcss-import path. That hook does not exist in
 * Propshaft mode — os_ds.css is a pre-flattened artifact. So we load after it
 * and redeclare the semantic roles in :root. (Reported upstream, tasks/043 §8.)
 *
 * MUST load AFTER os_ds and BEFORE the app CSS. Pinned by test/lint/hotelos_theme_test.rb.
 */

/* ─── Control DENSITY — the form-pairing fix (2026-07-27, tasks/073 A6) ────
   THE DEFECT, measured on /front_office/g/11?edit=journey: an `.os-input`
   renders 45px and an `.os-field-select` 44px, while the "Save flight" button
   beside them renders 36px and a `--sm` one 32px. A form therefore stacked
   three different control heights, and every submit sat 10-14px shorter than
   the field it belonged to. Read as "the buttons are small" — and they are,
   but only RELATIVE to arena's fields; in isolation 36px is correct.

   THE ROOT CAUSE is that arena never chose a density. os-ds exposes the
   control trio (--control-h / --control-pad-x / --control-fs) and four named
   scopes; a consumer that picks none inherits the gem's default, which is
   DiveOS's dense desktop-admin 36px. arena's FIELDS meanwhile sit on the
   canonical 46px field rung, because that is what `.os-input` ships at. Two
   rungs, one form. Patching button heights per call-site is what this token
   contract exists to prevent, so the fix is to make the CHOICE, once.

   THE FIT: inside a <form>, controls align on the field baseline (46px) —
   which is precisely what the gem documents `.os-density--field` for ("a
   button sitting inline with a select or datepicker matches it without the
   per-call-site .os-btn--field twin"). Outside a form — boards, toolbars,
   card feet, drawer chrome — nothing changes: those stay at the 36px base,
   where density is a feature and a 46px filter button would be a slab.

   Scoping to `form` rather than :root is deliberate. It is the smallest
   selector that means "this is a place where controls pair with fields", it
   needs no sweep of markup to adopt, and it cannot reach a surface that has
   no fields to match. Explicit size modifiers still win: `.os-btn--sm`
   re-declares the trio on itself, so a genuinely dense action inside a form
   (an inline "×", a chip action) stays small on purpose. */
form {
  --control-h:     var(--control-h-field);
  --control-pad-x: var(--control-pad-x-field);
  --control-fs:    var(--control-fs-field);
}

:root {
  /* ─── Semantic neutrals — the SLATE fork ───────────────────────────────
     os-ds ships gray neutrals (DiveOS default). arena deliberately repointed
     them to slate (c3bc795, 2026-07-16) so the app reads as ONE cool neutral
     family: before it, gray chrome sat beside slate (status-returning) and the
     tinted --accent-soft, reading as three families at once.
     This is NOT debt to reconcile — the theme layer IS the sanctioned
     per-product override, and adopting the gem without this block silently
     reverts a deliberate decision. Verified: the gem's --canvas/--ink/--hairline
     resolve to gray-50/900/200; these re-point them to their slate twins.
     --surface stays #FFFFFF (identical in both). --status-completed-* is
     deliberately NOT included: it stays gray so it differs from returning=slate. */
  --canvas:          var(--slate-50);
  /* Editorial Calm "Paper" — a warm near-white dashboard canvas (EDITORIAL-CALM.md
     § Surface & Elevation). The guest portal frame repoints its --canvas at this so
     white EC cards read as lifted; staff surfaces keep slate-50. A token-def literal
     is the sanctioned place for a hex (same as the slate ramp above). */
  --paper:           #FCFCFA;
  --surface-alt:     var(--slate-100);
  --hairline:        var(--slate-200);
  --hairline-2:      var(--slate-100);
  --hairline-soft:   #EBEEF2; /* between slate-100 and -200; the mockups + HotelOS Mobile dividers key off it. Was UNDEFINED in-app, so unfallbacked `var(--hairline-soft)` borders (e.g. .hom-readhero__facts) silently collapsed to 0 (2026-08-18). */
  --hairline-strong: var(--slate-300);
  --ink:             var(--slate-900);
  --muted:           var(--slate-500);
  /* slate-500, NOT slate-400: the gem deliberately darkened --muted-2 to a
     4.5:1 caption contrast (os_ds semantic.css). slate-400 (#94A3B8) is ~2.6:1
     and would undo that WCAG fix; slate-500 (#64748B) holds 4.6:1. The gem's
     --muted/--muted-2 were near-identical, so collapsing them costs nothing. */
  --muted-2:         var(--slate-500);
  --text-secondary:  var(--slate-700);
  --sidebar-bg:      var(--slate-100);
  --hover-warm:      var(--slate-100);

  /* ─── HotelOS brand ramp ───────────────────────────────────────────────
     Sanctioned by os-ds primitives.css: a product "may ADD a brand ramp here
     — e.g. a --teal-* scale — then point --accent at it in its semantic layer".
     Tailwind teal. teal-700 #0F766E is the HotelOS accent (Design/Front-office/
     HotelOS Brand.html sec 07: "Teal-700 is HotelOS's one structural accent —
     sky stays with DiveOS"). */
  --teal-50:  #F0FDFA; --teal-100: #CCFBF1; --teal-400: #2DD4BF;
  --teal-600: #0D9488; --teal-700: #0F766E; --teal-800: #115E59;
  --teal-900: #134E4A;

  /* ─── Accent ───────────────────────────────────────────────────────────
     --accent-rgb carries the accent's raw channels so every alpha composes
     from one place. The gem has no such token and hardcodes rgba(3,105,161,…)
     for all six below — swapping --accent alone would leave them sky, including
     --focus-ring-color, which --shadow-focus reads (i.e. every focus ring).
     Keep --accent-rgb in sync with --accent by hand: CSS cannot decompose a hex,
     and relative-colour syntax isn't safe across our supported browsers yet. */
  --accent:             var(--teal-700);
  --accent-strong:      var(--teal-800);
  --accent-rgb:         15, 118, 110;              /* = --teal-700 #0F766E */
  --accent-soft:        rgba(var(--accent-rgb), 0.08);
  --accent-softer:      rgba(var(--accent-rgb), 0.04);
  --accent-border:      rgba(var(--accent-rgb), 0.26);
  /* --accent-light is an OPAQUE tint in the gem (var(--sky-100)), not an alpha
     wash — it fills .cal__day.is-range and the dv-fileupload dragover state,
     which composite over striped rows and need to be solid. Map it step-to-step
     onto teal-100 (sky-100's exact twin), like every other role here. */
  --accent-light:       var(--teal-100);
  --input-border-focus: rgba(var(--accent-rgb), 0.60);
  --focus-ring:         rgba(var(--accent-rgb), 0.10);
  --focus-ring-color:   rgba(var(--accent-rgb), 0.35);

  /* Info notification stays SKY. The gem sets --info: var(--accent); once
     --accent is teal that would render a teal icon/border on the sky --info-bg
     /--info-border (which we deliberately keep sky). Pin --info back to sky so
     the whole info affordance is one colour. */
  --info:               var(--sky-700);

  /* ─── Room status (HotelOS domain) ─────────────────────────────────────
     The housekeeping/occupancy state of a room, derived by Room#status from the
     `housekeeping` enum + `blocked` column. Domain status lives in the theme for
     the same reason os-ds keeps its dive --bar-* tints in semantic: it is a
     product's vocabulary, not a shared primitive.
     Values from Design/Front-office/HotelOS Arrivals - Final.html, snapped to the
     nearest gem ramp step so the palette stays on-system:
       #15803D -> green-700 (exact)   #0284C7 -> sky-600  (exact)
       #B4832B -> amber-700 (nearest) #C2410C -> amber-800 (nearest; the mockup's
       orange has no ramp)            #BE123C -> rose-700 (exact)
       #475569 -> slate-600 (exact)
     The mockup's --st-inhouse #0369A1 is dropped: no -bg pair (asymmetric,
     likely a mockup gap) and no Room::STATUS behind it.
     NB: the app's LABEL for vacant is "Vacant", not the mockup's "Ready" —
     Room::STATUSES is the source of truth for naming. */
  --st-vacant:   var(--green-700);  --st-vacant-bg:   var(--green-50);
  --st-occupied: var(--sky-600);    --st-occupied-bg: var(--sky-50);
  --st-dirty:    var(--amber-700);  --st-dirty-bg:    var(--amber-50);
  --st-dueout:   var(--amber-800);  --st-dueout-bg:   var(--amber-100);
  --st-blocked:  var(--rose-700);   --st-blocked-bg:  var(--rose-50);
  --st-reserved: var(--slate-600);  --st-reserved-bg: var(--slate-100);

  /* ─── Guest-surface "sand" ramp (HotelOS domain) ───────────────────────
     The AUDIENCE cue: guest-facing arrival surfaces (arrival wizard,
     registration card, transfers) wear a warm sand welcome hero; staff
     operational tools (front-office Overview, drawer, boards) stay cool
     teal/neutral. Same layouts, different header hue.
     Sand is the ONE tinted surface on a guest page — everything below the
     hero stays neutral (canvas / surface / surface-alt), which is what keeps
     --accent meaning "brand + action" rather than decoration.
     These are deliberately HEADER-LOCAL: the app's semantic neutrals are cool
     slate, and cool muted text on a warm ground reads accidental. Using the
     warm ramp inside the hero makes it commit to warm. Teal stays the accent
     on top of it ("sand & sea"). Raw hex (not ramp steps) because os-ds ships
     no warm neutral ramp; introduce one upstream and these become aliases.
     Decided 2026-07-26 over hand-built mockups (see DECISIONS.md). */
  --sand:          #FCF4DC;  /* hero fill — flat solid, never a gradient */
  --sand-ink:      #423A22;  /* display title on sand */
  --sand-muted:    #7B7157;  /* sub-copy / ref no. on sand */
  --sand-label:    #8A7F63;  /* eyebrows + group labels on sand */
  --sand-hairline: #EBE2CB;  /* chip/tab borders on sand */
  --sand-divider:  #E4DAC0;  /* group dividers on sand */
  --sand-track:    #EBE1C6;  /* progress-bar track on sand */

  /* NB: the "lifts onto the tinted hero" elevation is the GEM's
     --elevation-overlay — do NOT add a local float shadow. The mockups
     hand-tuned one, but measured against the gem value it differs by ~1%
     luminance in the shadow band (max 56/765 on the worst pixel), so it did
     not justify breaking os-ds's two-elevation rule. Two levels only:
     --elevation-overlay for cards overlapping the hero, else flat + hairline. */
}

/* ── Arena-only primitives (migrated out of arena_ds.css, 2026-07-19) ────────
   The 21 tokens below are the ONLY ones arena_ds's :root still carried that
   os-ds does not ship AND something actually consumes. The rest of that block
   was deleted: 18 duplicated os-ds tokens (inert — the gem loads after
   arena_ds, so the gem's value already won) and 36 with zero consumers
   anywhere in app/ lib/ config/ test/ or the gem.

   Safe to declare here (after os_ds) rather than before it: every token below
   is arena-only, so there is no gem declaration to accidentally override.
   Deliberately NOT moved: --gutter and the --space-N / --text-N duplicates —
   the gem intentionally overrides those (e.g. --gutter becomes a responsive
   clamp), and re-declaring them after os_ds would silently flip that behaviour.
   (Do NOT write those globs with a star immediately before a slash here: that
   sequence closes this comment early and silently kills the :root block below.
   That exact typo shipped once and blanked all 21 tokens app-wide.)

   These are candidates to either fold into the os-ds scale or retire as usage
   drops — see tasks/ao-star-audit.md. */
:root {
  /* Moved with the tokens: os-ds declares no color-scheme, and dropping it
     would hand form controls / scrollbars back to the OS dark preference. */
  color-scheme: light;

  /* weights — --fw-semibold alone is used 43x across the app */
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* type steps os-ds doesn't ship */
  --text-base: 0.875rem;
  --display-sm: 1.75rem;
  --display-md: 2.25rem;

  /* line-height + tracking */
  --lh-tight: 1.1;
  --lh-normal: 1.5;
  --ls-tight: -0.01em;
  --ls-wide: 0.02em;
  --ls-wider: 0.06em;

  /* the eyebrow role, composed from the above */
  --role-eyebrow-size: var(--text-2xs);
  --role-eyebrow-weight: var(--fw-bold);
  --role-eyebrow-spacing: var(--ls-wider);

  /* spacing / radius / shadow / motion not in the os-ds scale */
  --space-7: 2rem;
  --radius-xs: 4px;
  --shadow-xs: 0 1px 2px rgba(13, 27, 42, 0.06);
  --shadow-lg: 0 12px 28px rgba(13, 27, 42, 0.12), 0 4px 10px rgba(13, 27, 42, 0.06);
  --dur-fast: 120ms;
  --dur-base: 200ms;

  /* Rep greeter PLACARD — the near-black public greeting surface (rep-board.html,
     E11). A distinct brand surface, not a repurposed neutral: a bluer near-black
     than --ink and a light teal for the tracked "WELCOME" eyebrow / brand accent.
     Minted here (the theme layer) so the placard CSS stays token-clean. */
  --placard-bg: #0B1220;
  --placard-teal: #5EEAD4;
  /* Champagne gold for the placard's greeting accent (eyebrow + hairlines) — a
     touch lighter than the mark's #B6A357 so it stays luminous on the near-black,
     and the metallic gold reads more luxurious than the mint teal for a premium-
     resort greeting. The mark keeps its own #B6A357 artwork. */
  --placard-gold: #C9B681;
  --placard-ink: #F4F6FB;        /* name / mark on the dark placard */
  /* LIGHT placard variant (greeter toggles it for a bright lobby) — a warm ivory
     ground, a deeper gold that holds contrast on light, and the deep placard navy
     as the ink. Luxury-light, not stark white. */
  --placard-bg-light: #F5F1E8;
  --placard-gold-light: #97824A;
  --placard-ink-light: #0B1220;
  /* The greeter placard's guest NAME is set in Italiana — an elegant high-contrast
     display serif (title case), self-hosted at app/assets/fonts/italiana-400.woff2.
     Falls back to an elegant serif if the face never loads (offline kiosk). ONLY the
     placard name uses it — it is a SCOPED token (`--font-placard`), NOT the global
     `--font-display` (that stays the gem's Inter; overriding it here rendered every
     app heading in Italiana — the #283 leak, fixed). */
  --font-placard: 'Italiana', 'Cormorant Garamond', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
  /* Rep placard + name-card DISPLAY sizes (rep-board.html, owner-locked) — off the
     base type scale by design (a greeter placard is a display surface). The greeter
     holds a TABLET, so the name is sized tablet-first and fluid: clamp() scales it
     from phone (~34px) up to a large tablet held portrait (~92px) with no media
     query. Minted here so the surfaces reference tokens, not literals. */
  --placard-name: clamp(2.5rem, 10vw, 6.5rem); /* fluid Italiana hero name (40px..104px); the lighter display serif carries a larger size */
  --placard-name-land: 74px; /* legacy — landscape now rides the fluid clamp above */
  --namecard-name: 21px;     /* Board Direction B name card */
  --placard-eyebrow-size: clamp(11px, 1.5vw, 15px); /* tracked WELCOME eyebrow + name-card meta */
  --placard-hint-size: clamp(12.5px, 1.5vw, 15px);  /* placard hint + board hint */
  --namecard-search-size: 15px; /* the "Name…" filter input */
  --seg-count-size: 12px;       /* mono count pill in the direction switcher */
}
