@layer tokens {
/* ═══════════════════════════════════════════════════════════════════
   TDN MAGAZINE v4 — DESIGN TOKENS
   Brand tokens are constant. Semantic tokens change with colour scheme.
   Components consume semantic tokens only, so dark mode is automatic.
   ═══════════════════════════════════════════════════════════════════ */

:root {
  /* ── Brand (constant across schemes) ───────────────────────────── */
  --tdn-red:        #e51a3e;
  --tdn-red-deep:   #b0102d;
  --tdn-red-lift:   #ff3a5e;
  --tdn-gold:       #c8922a;
  --tdn-gold-lift:  #e8b84b;
  --tdn-ink:        #0c0c0c;
  --tdn-paper:      #ffffff;

  /* Section colours — used for kickers, rules and category chips. */
  --cat-tv:        #0b62c4;
  --cat-film:      #7b2d8b;
  --cat-music:     #007850;
  --cat-streaming: #b8431f;
  --cat-animation: #6a4bd0;
  --cat-theatre:   #a3175a;
  --cat-sports:    #16606b;
  --cat-default:   var(--tdn-red);

  /* ── Semantic surface + text (light) ───────────────────────────── */
  --bg:             #ffffff;
  --bg-sunken:      #f6f6f8;
  --bg-raised:      #ffffff;
  --surface:        #ffffff;
  --surface-alt:    #fafafb;
  --surface-hover:  #f2f2f5;
  --fg:             #0c0c0c;
  --fg-soft:        #33333a;
  --fg-muted:       #5d5d67;
  --fg-faint:       #8b8b95;
  --rule:           #e4e4e9;
  --rule-soft:      #eeeef2;
  --rule-strong:    #0c0c0c;
  --accent:         var(--tdn-red);
  --accent-hover:   var(--tdn-red-deep);
  --accent-contrast:#ffffff;
  --focus:          #0b62c4;

  /* ── Type ──────────────────────────────────────────────────────── */
  --font-display: 'TDN Serif', 'DM Serif Display', 'Playfair Display', Georgia, 'Times New Roman', serif;
  --font-head:    'TDN Condensed', 'Barlow Condensed', 'Arial Narrow', system-ui, sans-serif;
  --font-ui:      'TDN Sans', 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono:    ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  /* Fluid scale. Each step interpolates 360px → 1400px viewport. */
  --step--2: clamp(0.694rem, 0.68rem + 0.06vw,  0.72rem);
  --step--1: clamp(0.833rem, 0.81rem + 0.10vw,  0.875rem);
  --step-0:  clamp(1rem,     0.97rem + 0.14vw,  1.063rem);
  --step-1:  clamp(1.2rem,   1.14rem + 0.28vw,  1.35rem);
  --step-2:  clamp(1.44rem,  1.33rem + 0.5vw,   1.72rem);
  --step-3:  clamp(1.728rem, 1.55rem + 0.84vw,  2.2rem);
  --step-4:  clamp(2.074rem, 1.79rem + 1.34vw,  2.8rem);
  --step-5:  clamp(2.488rem, 2.03rem + 2.14vw,  3.6rem);
  --step-6:  clamp(2.986rem, 2.26rem + 3.4vw,   4.8rem);

  --lh-flat:   1.05;
  --lh-tight:  1.14;
  --lh-snug:   1.28;
  --lh-normal: 1.5;
  --lh-read:   1.68;

  --tracking-kicker: 0.09em;
  --tracking-nav:    0.075em;

  /* ── Space (4px base) ──────────────────────────────────────────── */
  --s-1: 0.25rem; --s-2: 0.5rem;  --s-3: 0.75rem; --s-4: 1rem;
  --s-5: 1.25rem; --s-6: 1.5rem;  --s-8: 2rem;    --s-10: 2.5rem;
  --s-12: 3rem;   --s-16: 4rem;   --s-20: 5rem;   --s-24: 6rem;

  /* Fluid section rhythm */
  --gap-card:    clamp(1rem, 0.7rem + 1.2vw, 1.5rem);
  --gap-section: clamp(2.25rem, 1.4rem + 3.2vw, 4rem);

  /* ── Shell ─────────────────────────────────────────────────────── */
  --measure:        68ch;
  --width-page:     1240px;
  --width-text:     44rem;
  --gutter:         clamp(1rem, 0.55rem + 2vw, 1.75rem);
  --header-h:       56px;
  --header-h-mobile:60px;

  /* Resolved height of the fixed chrome, so nothing has to hardcode
     56 / 60 / 32 / 46 again. v4.0.2 had those numbers written out in
     five places and two of them disagreed, which is how the offline
     banner ended up parked inside the viewport. */
  --chrome-h: var(--header-h);
  --admin-h:  0px;

  /* ── Shape + depth ─────────────────────────────────────────────── */
  --radius-xs: 3px;  --radius: 6px; --radius-lg: 12px; --radius-pill: 999px;
  --shadow-1: 0 1px 2px rgb(12 12 12 / 0.05);
  --shadow-2: 0 1px 2px rgb(12 12 12 / 0.05), 0 8px 24px rgb(12 12 12 / 0.06);
  --shadow-3: 0 2px 4px rgb(12 12 12 / 0.07), 0 18px 44px rgb(12 12 12 / 0.10);
  --ring: 0 0 0 3px color-mix(in srgb, var(--focus) 45%, transparent);

  /* ── Motion ────────────────────────────────────────────────────── */
  --ease:      cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out:  cubic-bezier(0.22, 1, 0.36, 1);
  --t-fast:    120ms;
  --t-base:    220ms;
  --t-slow:    400ms;

  /* WCAG 2.2 SC 2.5.8 — minimum target size for pointer inputs. */
  --target-min: 24px;
  --target-comfortable: 44px;

  color-scheme: light;
}

/* Fixed-chrome offsets, resolved once.
   --chrome-total is composed on <body> deliberately, NOT on :root. A
   var() inside a custom property is substituted against the element
   that declares it, so composing this on :root would freeze --admin-h
   at 0px and body.admin-bar could never affect it. */
@media (width <= 48rem) {
  :root { --chrome-h: var(--header-h-mobile); }
}
body { --admin-h: 0px; }
body.admin-bar { --admin-h: 32px; }
@media screen and (width <= 782px) {
  body.admin-bar { --admin-h: 46px; }
}
body { --chrome-total: calc(var(--chrome-h) + var(--admin-h)); }

/* Section accent resolution. <body> carries a category slug class from
   tdn_body_class(), so every descendant picks up the right rule colour
   without a single per-category component override. The default is
   declared first so the specific slugs below win on source order. */
body { --cat: var(--cat-default); }
body.cat-tv                { --cat: var(--cat-tv); }
body.cat-film              { --cat: var(--cat-film); }
body.cat-music             { --cat: var(--cat-music); }
body.cat-streaming         { --cat: var(--cat-streaming); }
body.cat-animation         { --cat: var(--cat-animation); }
body.cat-theatre-musicals  { --cat: var(--cat-theatre); }
body.cat-sports            { --cat: var(--cat-sports); }

/* Cards can also scope their own accent, so a Film card inside a TV
   archive still reads as Film. tdn_card_accent_attr() prints these. */
[data-cat="tv"]        { --cat: var(--cat-tv); }
[data-cat="film"]      { --cat: var(--cat-film); }
[data-cat="music"]     { --cat: var(--cat-music); }
[data-cat="streaming"] { --cat: var(--cat-streaming); }
[data-cat="netflix"], [data-cat="disney"], [data-cat="hulu"] { --cat: var(--cat-streaming); }
[data-cat="animation"] { --cat: var(--cat-animation); }
[data-cat="theatre-musicals"] { --cat: var(--cat-theatre); }
[data-cat="sports"], [data-cat="wwe"] { --cat: var(--cat-sports); }
}
