/* ============================================================================
   Sanam — BASE DUSK GROUND (the platform-wide ENFORCED default ground).

   ROOT-CAUSE FIX (the recurring "old template / page renders light" issue).
   ---------------------------------------------------------------------------
   Before this sheet, Dusk was OPT-IN per standalone page: a page only rendered
   dark if it individually carried <body class="dusk"> AND loaded a Dusk sheet.
   Any page that forgot to opt in rendered on platform.css's warm-cream F2 ground
   — light + off-brand — and fixing one page never covered the next un-migrated
   one, so the bug kept resurfacing. There was no shared base enforcing Dusk.

   This sheet IS that shared base. It is loaded by EVERY served standalone page
   (right after platform.css, before any page-specific sheet) and makes Dusk the
   DEFAULT GROUND every page inherits — so a page CANNOT render light by default,
   with NO per-page opt-in required:

     * It declares the canonical --d-* Dusk token block on :root ONCE, so the
       Dusk palette is ALWAYS available to every page (operator_dusk.css / hub.css
       still declare their own scoped copies for back-compat; this is the shared,
       always-present source).
     * It paints the Dusk ground (dark oud bg + cream ink + color-scheme:dark +
       the warm grain) onto the BARE <body> — i.e. `body:not(.public-warm)` —
       which covers BOTH a page that opted in with class="dusk" AND a NEW page
       that wrote a plain <body> and forgot to. Either way: Dusk, for free.

   The ONE deliberate exception is the warm F2 PUBLIC face (the buyer storefront,
   the public KB, the page-space 404). Those are INTENTIONALLY warm/cream (the
   "most human/alive" front door travellers see — platform.css §"Buyer storefront
   dial"). They opt OUT explicitly + visibly with <body class="public-warm">, so a
   warm public page is a deliberate, greppable choice — never an accidental light
   page. Anything that is NOT public-warm is Dusk by construction.

   Enforced by tests/test_theme_enforced.py, which renders EVERY served HTML route
   and asserts each is Dusk-grounded (or an explicitly-allowlisted public-warm
   page) AND that no live page loads the retired light styles.css. A page that
   renders light now FAILS the build — this class can never resurface silently.

   Design law kept: a re-skin is a TOKEN SWAP, never a structural edit; logical
   CSS properties throughout (one sheet, LTR + RTL); copper does the work;
   negatives stay in Oud (amber), never red; numbers never jitter; AA on the dark
   ground; prefers-reduced-motion respected.
   ========================================================================== */

/* ---- the canonical Dusk token block (always present, every page) ------------ */
/* The single shared source for the --d-* Dusk palette. operator_dusk.css and
   hub.css keep their own body.dusk-scoped copies (back-compat / no behaviour
   change); declaring them here on :root too means a NEW page that loads only
   platform.css + base_dusk.css already has the full Dusk palette to consume. */
:root {
  --d-bg: #161009; --d-bg2: #1A130D; --d-panel: #241A12; --d-card: #2E2218;
  --d-card-2: #352719; --d-card-3: #291E14;
  --d-line: #3A2B1E; --d-line-2: #4A3727; --d-line-3: #58402A;
  --d-cream: #F4EDE2; --d-tan: #D2BB9B; --d-ink: #BDA384; --d-ink-2: #C8AC8C;

  /* ===== THE JOURNEY · the 8-token LAND palette (canon §13) =====
     A re-skin is a TOKEN SWAP: the token NAMES are unchanged across the
     platform, only their VALUES move to the land palette. Copper LEADS (the
     ridge + primary actions); Saffron is the Northern Star / the ONE resting
     highlight; Sea + Green are FILL colours (their `-lit` siblings are the only
     forms allowed as small text on the dark ground — AA). */
  --d-copper: #B87333;            /* Dallah Copper — lead, ridge, primary actions */
  --d-copper-2: #9A6638;          /* copper depth (dividers, pressed) */
  --d-copper-press: #E8B068;      /* copper pressed bright */
  --d-copper-lit: #CC9248;        /* copper raised into light — copper TEXT (AA) */
  --d-saff: #C8850A;              /* Saffron / Northern Star ✦ / focus ring / "needs you" */
  --d-star-lit: #E6AE45;          /* saffron raised into light (text/glow, AA) */
  --d-green: #6F8260;             /* Asir Green — healthy / on-track (FILL) */
  --d-green-lit: #9DB389;         /* asir green raised for TEXT on dark (AA) */
  --d-sea: #3E6F74;               /* Farasan Sea — cool / informational (FILL) */
  --d-sea-lit: #5E9AA0;           /* farasan sea raised for TEXT on dark (AA) */
  --d-oud: #7A4B2E;               /* Oud — deep warm structure, dividers, depth */
  --d-tan-warm: #C4A882;          /* Camel Tan — warm neutral surfaces, hairlines */
  /* the landed-loss amber — negatives stay in OUD, never red. */
  --d-loss: #E0A07A;
  --d-shadow: 0 18px 40px rgba(0,0,0,.42);
  --d-shadow-2: 0 30px 56px rgba(0,0,0,.5);

  /* ===== THE MOTION-TOKEN CONTRACT (UI/UX Round 1) =====================
     ONE shared vocabulary of timing + easing for every interaction across all
     four fronts + both themes — so motion reads as ONE hand, never per-file
     drift. The shared utils (buttons, cards, the canonical .rv reveal, the
     universal hover-lift, toggles, the theme cross-fade) all migrate to these.
       --mo-fast : a snap (presses, small chrome)
       --mo      : the default interaction beat (hover-lift, reveal hand-off)
       --mo-slow : a settle (reveals, larger surface changes)
       --ease-out: the calm decelerate (the canonical easing)
       --ease-spring: a single restrained overshoot (the star/affordance settle)
     Declared on :root so BOTH Dusk and Paper Desert read the SAME values — the
     contract is timing, not colour, so day mode never needs to re-declare it. */
  --mo-fast: 150ms;
  --mo: 220ms;
  --mo-slow: 300ms;
  --ease-out: cubic-bezier(.2, .8, .2, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
}

/* ---- the ENFORCED default ground: Dusk for every page that is NOT public-warm */
/* This is the load-bearing rule. platform.css paints `body` warm cream; this
   overrides it to the Dusk ground for every non-public-warm body — so a page
   that forgets class="dusk" still lands on Dusk instead of the old light cream.
   Pages that DID opt in (body.dusk + operator_dusk.css/hub.css) are unaffected:
   they already declared the same dark ground, this just makes it the default. */
body:not(.public-warm) {
  background: var(--d-bg);
  color: var(--d-cream);
  -webkit-font-smoothing: antialiased;
  /* flip native form chrome (date pickers, number spinners, <select>) to dark so
     they never render dark-on-dark / light-on-dark and become invisible. */
  color-scheme: dark;
}

/* the same faint warm grain the operator portal + hub use, applied to the
   default Dusk ground (so a bare-body Dusk page gets the depth too). The
   already-dusk surfaces re-declare an identical body.dusk::before; this default
   covers a page that did not. Kept reduced-motion-safe (it is a static gradient,
   no animation). */
body:not(.public-warm)::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  opacity: .4; mix-blend-mode: overlay;
  background-image: radial-gradient(rgba(230,174,69,.05) 1px, transparent 1px);
  background-size: 3px 3px;
}

/* selection + base link colour on the default Dusk ground (the scoped Dusk
   sheets already set these under body.dusk; this carries a bare-body page). */
body:not(.public-warm) ::selection { background: #CC924855; }

/* ---- THE THEME-SWITCH CROSS-FADE (UI/UX Round 1, #6) -----------------------
   When the user flips Dusk <-> Paper Desert, the ground used to swap instantly
   (a hard flash). A short ~200ms cross-fade on the body's background + ink lets
   the page settle into the new theme. The tokens themselves switch instantly
   (cards/chrome are too many to transition cheaply), but fading the GROUND under
   them reads as a calm dissolve, not a snap. Gated to no-preference so a
   reduced-motion user gets the instant swap (no transition). */
@media (prefers-reduced-motion: no-preference) {
  body:not(.public-warm) {
    transition: background-color var(--mo) var(--ease-out), color var(--mo) var(--ease-out);
  }
}
