/* ============================================================================
 * DTN — TOKEN BRIDGE
 *
 * Maps the skin's private palette onto the template's SEMANTIC tokens, so
 * standard components adopt the skin without knowing it exists.
 *
 * ── Why this file exists ─────────────────────────────────────────────────────
 *
 * A skin used to be able to style only markup it owned. `dtn-skin.css` is 959
 * lines of bespoke component selectors (`.dtn-skin .hero-content`,
 * `.dtn-skin .preorder-panel`) with exactly ONE element-level rule and ZERO
 * `--color-*` declarations. So DTN spoke `--dtn-lime` while every standard
 * component spoke `--color-primary`, and the two vocabularies never met.
 *
 * The visible consequence: /blog rendered on the generic white template with a
 * DTN logo bolted on, on a live client site, while `data-skin-id="dtn"` was
 * stamped on <html> claiming the skin was active. Found 2026-08-16, one day
 * before the client was walked through that exact page.
 *
 * The fix is not more selectors. The template already forbids hardcoded colors
 * and mandates semantic tokens, so REDEFINING those tokens under the skin's
 * scope is enough — every standard component inherits for free.
 *
 * ── Why `html[data-skin-id="dtn"]` and not `.dtn-skin` ───────────────────────
 *
 * Two reasons, both load-bearing:
 *
 * 1. SPECIFICITY. BaseLayout injects the configured brand palette at `:root`
 *    (specificity 0,1,0). `html[data-skin-id]` is 0,1,1 and therefore wins,
 *    deterministically, without depending on stylesheet order — which Astro
 *    controls and we do not.
 *
 * 2. NO WRAPPER ELEMENT. Scoping to an attribute on the root means the bridge
 *    needs no wrapper, so it cannot disturb the routes the skin already owns.
 *    (Verified: neither DTN stylesheet contains a `>` selector off the scoped
 *    root, so nested scopes could not have broken rules either — but not needing
 *    the nesting at all is strictly better.)
 *
 *    ⚠️ This file originally shipped (2026-08-16) on the claim that BaseLayout
 *    "ALREADY stamps `data-skin-id` on <html>". It did not — it stamped it on
 *    <body>. So the selector matched NOTHING and this bridge was a no-op on the
 *    live site for a day: CSS in the bundle, attribute in the HTML, palette
 *    parity test green, 1349 tests green, page still white. The attribute was
 *    moved to <html> on 2026-08-17 and `check:skin-bridge-anchor` now compares
 *    the two sides so the pair cannot drift apart silently again.
 *
 * ── Scope of the rollout ─────────────────────────────────────────────────────
 *
 * ⚠️ This file is currently imported by the /blog routes ONLY, deliberately.
 *
 * Loading it in BaseLayout would apply it to every unowned DTN route at once —
 * about twelve pages — and it is a full light→dark inversion
 * (background #ffffff → #050505, text #1a1a1a → #ffffff). That is the intended
 * end state, and it is NOT safe to fire blind, because the repo's
 * "never hardcode Tailwind colors" rule is DOCUMENTED BUT NOT ENFORCED: there
 * is no guard, and 8 files carry hardcoded light-mode colors today
 * (Footer.astro, ImageGallery.astro, Preferences.tsx, two filter components,
 * three others). Those will not follow the token flip.
 *
 * The generalisation is specced separately. Its prerequisite is the missing
 * guard, not this file. Moving the import to BaseLayout is then a one-line
 * change and nothing here needs editing.
 * ========================================================================== */

/* The skin's faces. Loaded HERE as well as at the top of dtn-skin.css because a
 * route the skin does not own never loads that file — so mapping `--font-heading`
 * to 'Bungee' without this would resolve to the `cursive` fallback and look
 * broken in a new way rather than fixed. Same URL, so the browser cache and the
 * HTTP/2 connection are shared with the owned routes.
 * `@import` must precede every rule in the file; comments above it are fine. */
@import url('https://fonts.googleapis.com/css2?family=Bungee&family=Righteous&family=Space+Grotesk:wght@400;500;600;700;800&display=swap');

html[data-skin-id='dtn'] {
  --dtn-font-display: 'Bungee', cursive;
  --dtn-font-heading: 'Righteous', cursive;
  --dtn-font-body: 'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif;

  /* ── The palette itself ────────────────────────────────────────────────────
   * Declared here as well as in dtn-skin.css, and that is deliberate rather
   * than sloppy. `dtn-skin.css` declares `--dtn-*` under `.dtn-skin`, an
   * element that does NOT exist on a route the skin does not own — so on /blog
   * every `var(--dtn-black)` below would resolve to nothing and the bridge
   * would silently do half its job: tokens unset, page unstyled, no error.
   *
   * The alternative (moving the block, or widening dtn-skin.css's selector)
   * edits CSS the five owned routes depend on, hours before those routes are
   * demoed. Duplication that a test guards beats a live edit that nothing does.
   * `dtn-bridge.palette.test.ts` fails if the two blocks disagree. */
  --dtn-lime: #9acd32;
  --dtn-lime-bright: #bfff00;
  --dtn-lime-dark: #7cb342;
  --dtn-charcoal: #1c1c1c;
  --dtn-black: #050505;
  --dtn-white: #ffffff;
  --dtn-slate: #8e9eae;
  --dtn-muted: rgba(255, 255, 255, 0.72);
  --dtn-border: rgba(255, 255, 255, 0.1);

  /* Surfaces. DTN is a dark brand; the configured palette is light, which is
     what made /blog look like a different website. */
  --color-background: var(--dtn-black);
  --color-surface: var(--dtn-charcoal);
  --color-surface-raised: var(--dtn-charcoal);
  --color-surface-overlay: var(--dtn-charcoal);

  /* Type. `--color-text-subtle` intentionally reuses the slate rather than
     fading the muted value again — a second alpha layer over a near-black
     background lands under 3:1 and stops being readable. */
  --color-text: var(--dtn-white);
  --color-text-muted: var(--dtn-muted);
  --color-text-subtle: var(--dtn-slate);

  /* Brand. Lime is DTN's action colour; it is what `text-primary` hovers and
     `bg-primary` buttons must resolve to for a link to read as clickable. */
  --color-primary: var(--dtn-lime);
  --color-primary-light: var(--dtn-lime-bright);
  --color-primary-dark: var(--dtn-lime-dark);
  --color-accent: var(--dtn-lime);

  --color-border: var(--dtn-border);
  --color-border-strong: var(--dtn-slate);

  /* Type family, so headings on standard routes match the skin's display face
     instead of the config's serif default. */
  --font-heading: var(--dtn-font-display);
  --font-body: var(--dtn-font-body);
}

/* ── Header offset ────────────────────────────────────────────────────────────
 *
 * `.dtn-skin .site-header` is `position: fixed`, so it is out of flow and the
 * first line of page content renders UNDERNEATH it. The routes the skin owns
 * handle this in their own layouts; the standard routes do not, and on
 * /blog the <h1> sat at 64px under a 71px header — measured on prod, not
 * assumed.
 *
 * Scoped to `main#main-content`, which only BaseLayout emits, so this cannot
 * reach an owned route (those render the shell as the whole body and never
 * produce that element). `--dtn-header-h` is the single source of the height;
 * change it here if the header ever resizes.
 */
html[data-skin-id='dtn'] {
  --dtn-header-h: 71px;
}

html[data-skin-id='dtn'] main#main-content {
  padding-top: var(--dtn-header-h);
}

/* ── Why there are no component/surface rules below this line ─────────────────
 *
 * The first draft of this file carried a surface correction for the generic
 * footer: `Footer.astro` is `bg-primary text-white`, correct semantics, and with
 * `--color-primary: lime` it painted the whole footer lime with white text on it
 * (~1.6:1, unreadable). The fix looked obvious — re-surface the footer here.
 *
 * It would have been a no-op. As of 2026-08-17 the blog routes render the SKIN's
 * own header and footer via `<SkinChrome>` (see src/skins/skin-chrome.ts), so the
 * generic footer is no longer on the page for this tenant at all, and a rule
 * targeting it would match nothing while looking like a fix. Same failure shape
 * as the one that created this file.
 *
 * The rule for anyone extending this: a token bridge remaps TOKENS. If a
 * component's surface role does not survive the palette inversion, the answer is
 * either the skin's own component (preferred — it is the design, not an
 * approximation of it) or a system layer added deliberately with a route that
 * actually renders the generic component. Not a rule bolted on here on the
 * assumption that it does.
 */

