/* ─────────────────────────────────────────
   DESIGN TOKENS — EEST NJT Racing Circuit
   "Race to Victory" Brand System
   Single Source of Truth
───────────────────────────────────────── */
:root {
  /* Brand — Racing Palette (Race to Victory) */
  --racing-yellow:   #FFD700;
  --racing-plum:     #2A0018;
  --racing-grey:     #9C9EA2;
  --magenta:         #D40079;

  /* Aliases */
  --primary:         #D40079;
  --primary-dark:    #A30060;
  --primary-light:   #E6007A;
  --gold:            #FFD700;
  --gold-dim:        rgba(255,215,0,0.15);

  /* Steel Palette (EEST Corporate) */
  --steel-400:       #94a3b8;
  --steel-500:       #64748b;
  --steel-600:       #475569;

  /* Neutrals */
  --black:           #2A0018;
  --black-card:      #1A0510;
  --black-deep:      #150010;
  --black-true:      #0F0F0F;

  /* Text */
  --text-white:      #FFFFFF;
  --text-white-80:   rgba(255,255,255,0.8);
  --text-white-60:   rgba(255,255,255,0.6);
  --text-white-40:   rgba(255,255,255,0.4);
  --text-dark:       #1e1e1e;

  /* Backgrounds */
  --bg-dark:         #2A0018;
  --bg-gradient:     linear-gradient(45deg, #D40079, #FFD700);
  --bg-gradient-v:   linear-gradient(180deg, #000000 0%, rgba(42,0,24,0.95) 50%, #000000 100%);
  --hero-overlay:    linear-gradient(180deg, rgba(42,0,24,0.9) 0%, rgba(0,0,0,0.7) 100%);

  /* Gradients */
  --magenta-gradient:   linear-gradient(45deg, #D40079, #FFD700);
  --btn-primary-bg:     linear-gradient(135deg, #FFD700, #FFC107);
  --btn-hover-bg:       linear-gradient(135deg, #FFD700, #D40079);
  --btn-secondary-bg:   linear-gradient(135deg, rgba(255,255,255,0.15), rgba(255,255,255,0.25));
  /* --btn-media-scrim — the THIRD token in the A18 button-contrast contract (see the
     block above `.btn-cta` in layout.css). `--btn-secondary-bg` is a white 15→25% wash:
     it LIGHTENS whatever is behind it, so a `--outline` / `--secondary` / `--glass`
     button sitting on a hero photo or a playing video has no floor under its field —
     measured 2.41–4.23:1 against white ink on track-info and activities (Gate 2 N1).
     No ink choice survives an unknown field, so the fix is a floor, not an ink swap:
     this plum layer is painted UNDERNEATH the wash on all three translucent variants.
     `--racing-plum #2A0018` @ 88% — over the dark plum base it is visually inert
     (plum on plum); over media it is the whole fix. 88% is the worst-case number, not
     a taste number: against a PURE WHITE field under the heaviest wash the variants use
     (`--outline:hover`, white 30%) it composites to 5.4:1 vs white ink; 80% lands on
     4.50 with no headroom. HOUSE-RULES §10 — darken the surface, never lighten the ink. */
  --btn-media-scrim:    linear-gradient(rgba(42,0,24,0.88), rgba(42,0,24,0.88));
  --section-gradient:   linear-gradient(180deg, #000000 0%, rgba(42,0,24,0.95) 50%, #000000 100%);

  /* Borders & Shadows */
  --border-gold:     rgba(255,215,0,0.15);
  --border-white:    rgba(255,255,255,0.1);
  --shadow-card:     0 1px 3px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.15);
  --shadow-hover:    0 20px 40px rgba(212,0,121,0.3);
  --shadow-elevated: 0 12px 40px rgba(0,0,0,0.3), 0 4px 12px rgba(0,0,0,0.2);
  --shadow-btn:      0 4px 12px rgba(0,0,0,0.15), 0 1px 3px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.1);
  --shadow-btn-hover: 0 8px 25px rgba(255,215,0,0.4), 0 3px 8px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.2);
  --shadow-glow-yellow: 0 0 8px rgba(255,215,0,0.7);

  /* Radius */
  --radius:          8px;
  --radius-md:       12px;
  --radius-lg:       16px;
  --radius-pill:     50px;

  /* Status */
  --green:           #2a7a4b;
  --green-bg:        rgba(42,122,75,0.15);
  --amber:           #d4940a;

  /* Typography */
  --font-display:    'Prompt', 'Titillium Web', Impact, sans-serif;
  --font-heading:    'Prompt', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body:       'Bai Jamjuree', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-en-body:    'Bai Jamjuree', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  /* Mono RETIRED sitewide (GOAL-V3 §Decisions): Roboto Mono WOFF2 is NOT self-hosted, so
     var(--font-mono) previously fell back to system Courier (phantom-mono defect). Telemetry/spec
     contexts now render in Prompt with their own letter-spacing. Documented in CONVENTIONS. */
  --font-mono:       'Prompt', 'Titillium Web', sans-serif;

  /* Layout */
  --max-w:           1400px;
  --content-w:       1200px;
  --transition:      0.3s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-spring: 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  --header-h:        80px;
  /* A14 — the ONE top pad for a hero that pulls itself up under the fixed header.
     A hero with `margin-top: calc(var(--header-h) * -1)` starts its content at
     (padding-top − header-h) from the VIEWPORT top, so `padding-top: var(--header-h)`
     puts content at y=0, under the header: measured breadcrumbs at top=5…63 and
     `elementFromPoint` returning `.site-header__*` on 30 of 180 route×lang×width
     combos. The pad has to cancel the negative margin AND clear the header.
     Every negative-margin hero consumes this token; do not hand-roll the sum. */
  --hero-pad-top: calc(var(--header-h) * 2 + 16px);
  --section-pad:     80px;
  --section-pad-mob: 48px;

  /* ─────────────────────────────────────────
     TYPE SCALE — clamp() tokens (SSOT)
     Convention: one token per role; sweep the ~30 ad-hoc clamp()s onto these.
     Format: --text-<role>: clamp(min, fluid, max);
  ───────────────────────────────────────── */
  /* Hero headline — the biggest type on a page. ONE clamp for every route's H1.
     GOAL-V4 §G1/§G6 (operator decision, 2026-08-15): cap raised 72px → 88px, ONCE, on the
     TOKEN — never on a component. Root cause it closes: components.css hardcoded
     clamp(52px,7vw,96px) on .njt-hero__title, so index/gallery/about/contact/racing-team
     rendered 33% larger than the-circuit flagship (which was already on this token) and the
     hierarchy inverted. Consumers: .njt-hero__title, .tc-hero__title, .ce-hero__title.
     If a route ever needs a different size, change THIS line — do not re-hardcode a clamp. */
  --text-display-xl: clamp(40px, 5.5vw, 88px);
  --text-display:    clamp(28px, 3vw, 44px);   /* section titles (njt-section__title register) */
  --text-h3:         clamp(20px, 2vw, 28px);   /* card titles / sub-heads */
  --text-eyebrow:    13px;                      /* eyebrow / overline — fixed, never fluid */
  --text-body:       clamp(15px, 1.05vw, 17px);/* body copy */
  --text-small:      clamp(13px, 0.9vw, 14px); /* meta / captions */
  --text-micro:      0.65rem;                   /* HARD FLOOR — never render UI text below this (LESSONS: sub-9px) */

  /* ─────────────────────────────────────────
     LEADING — LANGUAGE-AWARE (operator directive, 2026-08-17: "enhance line height
     for both title of Thai & English language"). ONE token per role; the VALUE
     changes with `html[lang]`, so a component says `line-height: var(--lh-display)`
     once and each language gets its correct leading instead of a compromise.

     Why two values and not one. Measured with Canvas `actualBoundingBox*` on the
     REAL published heading strings of all 18 routes, Prompt 900 italic (see
     `loop-docs/verification/v4-op-directives-index.md` for the census):
       • Thai  display ink height = **1.393 em** max (the compound "ขึ้น-ลงสไตล์ยุโรป"
         — double upper stack AND a lower vowel in one unbreakable run), p99 1.353,
         p95 1.302. Stacked sara/tone marks sit above AND below the baseline.
       • Latin display ink height = **0.982 em** max ("Rising", "Beginner").
     Both figures are from the LIVE render of all 18 routes (892 display-scale
     elements, 370 Thai / 522 Latin), not from a synthetic string.
     At the old flat `line-height: 1.2` a Thai display heading's ink is 0.157 em
     TALLER than its own line box: consecutive lines physically overlap (the
     diacritic collision + top clipping charged as Gate-7 V4R1-3). Latin at 1.2 has
     0.218 em of clearance — it never collided; it just read cramped, which is the
     other half of the operator's note.
       --lh-display TH 1.45 → clears the 1.393 max with 0.057 em of real gap.
       --lh-display EN 1.26 → +5 % optical relief, still a display voice.
     1.45 reads "loose" as a number and is not: Thai ink is simply 1.4× taller than
     Latin ink at the same font-size, so the optical gap is ~5 px at an 88 px hero.
     Raising Latin to the Thai value would make English headings limp; that is the
     "compromise that serves neither" this token exists to avoid.

     --lh-value is the tight numeral/stat lockup register (HUD values, prices,
     years, hours). Latin digits legitimately set solid, so it stays near 1.1;
     Thai in the same slot ("2.63 กม.", "อยู่ระหว่างก่อสร้าง", "ต่อ 10 นาที")
     does not, so it lifts. Consumers are enumerated in components.css §38.
     Do NOT hardcode a heading line-height in a page file — put it on these.
  ───────────────────────────────────────── */
  --lh-display: 1.10;   /* display / heading register — Latin (tightened 1.26→1.10, operator 2026-08-22) */
  --lh-heading: 1.18;   /* sub-head + card-title register — Latin (tightened 1.32→1.18) */
  --lh-value:   1.1;    /* numeral & stat lockups — Latin */

  /* ── Spacing Scale (4px base — replaces the 20+ ad-hoc gap/pad values) ── */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* ─────────────────────────────────────────
     GLASS SURFACES — 3 composable recipes (re-base all card classes onto these).
     Compose: background + backdrop-filter: blur(--blur-*) + border: --surface-border.
     Or use the .surface-glass / .surface-solid / .surface-feature helper classes (components.css).
  ───────────────────────────────────────── */
  --surface-glass:   rgba(0,0,0,0.4);                                                /* default card — pair with --blur-card + --surface-border */
  --surface-solid:   var(--black-card);                                              /* opaque card (course / pricing / faq) */
  --surface-feature: linear-gradient(160deg, rgba(42,0,24,0.88), rgba(21,0,16,0.94));/* feature / plum card — pair with --blur-card */
  --surface-border:  1px solid rgba(255,255,255,0.1);                                /* canonical hairline on glass */

  /* ── Backdrop Blur — 3 tokens (collapses the 14 ad-hoc backdrop-filter values) ── */
  --blur-chip:   8px;                          /* chips / pills — used as blur(var(--blur-chip)) */
  --blur-card:   12px;                         /* cards / panels — used as blur(var(--blur-card)) */
  --blur-chrome: blur(20px) saturate(180%);    /* header / drawer / dropdown — a COMPLETE backdrop-filter value */

  /* ─────────────────────────────────────────
     MOTION — one language (adopt the §E spec).
     Reveal = opacity + translateY(24px); stagger step 80ms, max 4 steps.
     Ambient loops = decorative only, ≥8s, pause off-screen.
  ───────────────────────────────────────── */
  --dur-fast:    150ms;
  --dur-base:    300ms;
  --dur-reveal:  400ms;                          /* HARD CAP for entrance reveals */
  --ease-out:    cubic-bezier(0.4, 0, 0.2, 1);   /* matches the easing inside --transition */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* playful accents only */

  /* ─────────────────────────────────────────
     SANCTIONED ACCENTS (GOAL-V3 §Decisions) — the ONLY accents outside the brand trio.
     Everything else maps to --magenta / --gold / --racing-plum. Do not add ad-hoc hex.
  ───────────────────────────────────────── */
  --magenta-300:  #FF4DB3;   /* bright magenta highlight — sanctioned successor to the rogue #FF4DB3 hardcodes (dark surfaces only) */
  --tier-gold:    #C9A351;   /* sponsor/tier GOLD plate accent (warmer than signage --gold, for tier lockups) */
  --tier-bronze:  #B08D57;   /* sponsor/tier BRONZE accent */
  --line-green:   #06C755;   /* official LINE brand green. NON-TEXT ONLY on a dark surface: icon
                                colour, hairline, border (8.45:1 as an icon on plum). As a FILLED
                                surface under white text it measures 2.26:1 — see --line-green-aa. */
  --line-green-aa: #047A3A;  /* A20: the darkened LINE green for a FILLED button with white text
                                (5.45:1). Not covered by CONVENTIONS #8, which governs --signal-green.
                                pricing.css had this hex inline since R3; it is a token now so the
                                next LINE button cannot be built on the failing value. */
  --signal-green: #2E7D46;   /* success / status green — AA on dark plum; replaces neon #00E676 / #4ADE80 for text & status */
  --map-filter:   invert(0.92) hue-rotate(175deg) saturate(0.7) brightness(0.9) contrast(0.95); /* ONE dark-map recipe — IFRAME/map-TILES ONLY. Never apply to a photographic poster (inverting a real photo = negative image, taste Gate 1 #1); posters get a dark rgba scrim instead. */

  /* ── Light-Zone set (for any light/paper section — spec sheets, print-like blocks) ── */
  --paper:    #F5F2EC;   /* warm paper base */
  --ink:      #1A0510;   /* primary ink on paper (AAA) */
  --ink-soft: #4A4148;   /* secondary ink on paper (AA) */

  /* ─────────────────────────────────────────
     ICON MASKS — Lucide, inline data-URI (replaces emoji/dingbat ::before content; HOUSE-RULES §6).
     MASK use (single-colour icon): content:''; width; height; background-color:<color>;
       -webkit-mask: var(--icon-check) center / contain no-repeat; mask: same;
     IMAGE use (icon inside a coloured badge): background-image: var(--icon-check-gold); no-repeat; center.
  ───────────────────────────────────────── */
  --icon-check:      url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='3'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M20%206%209%2017l-5-5'/%3E%3C/svg%3E");
  --icon-check-gold: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23FFD700'%20stroke-width='3'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M20%206%209%2017l-5-5'/%3E%3C/svg%3E");
  --icon-award:      url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='8'%20r='6'/%3E%3Cpath%20d='M15.477%2012.89%2017%2022l-5-3-5%203%201.523-9.11'/%3E%3C/svg%3E");
  --icon-zap:        url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M4%2014a1%201%200%200%201-.78-1.63l9.9-10.2a.5.5%200%200%201%20.86.46l-1.92%206.02A1%201%200%200%200%2013%2010h7a1%201%200%200%201%20.78%201.63l-9.9%2010.2a.5.5%200%200%201-.86-.46l1.92-6.02A1%201%200%200%200%2011%2014z'/%3E%3C/svg%3E");
  --icon-badge:      url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M3.85%208.62a4%204%200%200%201%204.78-4.77%204%204%200%200%201%206.74%200%204%204%200%200%201%204.78%204.78%204%204%200%200%201%200%206.74%204%204%200%200%201-4.77%204.78%204%204%200%200%201-6.75%200%204%204%200%200%201-4.78-4.77%204%204%200%200%201%200-6.76Z'/%3E%3Cpath%20d='m15%209-6%206'/%3E%3Cpath%20d='M9%209h.01'/%3E%3Cpath%20d='M15%2015h.01'/%3E%3C/svg%3E");

  /* ── Radius: pill is ONE token (collapse 100px / 999px / 9999px → --radius-pill) ── */
  /* --radius-pill defined above (50px) is the single pill radius. */

  /* ─────────────────────────────────────────
     BREAKPOINTS — ONE canonical grid (sweep off-by-one twins 767/991/1023/1199 to these):
       1200  desktop → laptop
       1024  laptop  → tablet
        768  tablet  → mobile
        640  mobile-lg
        480  mobile-sm
     (CSS custom properties can't be used in @media queries — this comment is the SSOT convention.)
  ───────────────────────────────────────── */
}

/* ─────────────────────────────────────────
   THAI LEADING STATE — the language hook.
   `js/navigation.js` setLang() writes `documentElement.lang = th|en` on every
   toggle, and all 18 routes ship `<html lang="th">` in source, so this selector is
   live from the first paint (no FOUC) and flips instantly with the TH/EN buttons.
   Specificity (0,1,1) beats `:root` (0,1,0), so these win by design.
   This is the ONLY place Thai leading values are written. Nothing else in the build
   may branch a line-height on language — add a consumer in components.css §38 instead.
───────────────────────────────────────── */
html[lang="th"] {
  --lh-display: 1.40;   /* tightened 1.45→1.40 (operator 2026-08-22); still clears the 1.393 em Thai display ink-box */
  --lh-heading: 1.40;   /* tightened 1.45→1.40; diacritic-safe floor for Thai heading register */
  --lh-value:   1.3;
}

/* ── Global Reset ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; scroll-padding-top: var(--header-h); overflow-x: clip; }
body {
  font-family: var(--font-body);
  color: var(--text-white);
  background: var(--bg-dark);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* overflow-x: clip (NOT hidden). `hidden` makes body a scroll container and kills
     every position:sticky sitewide (vspec pinning, pricing/activities sub-navs, news rail).
     `clip` guards horizontal overflow identically without creating a scroll container.
     html already carries overflow-x:clip (line 184). Root cause of V3-R2 N1. */
  overflow-x: clip;
}
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; transition: color var(--transition); }
button { cursor: pointer; font-family: inherit; }
h1, h2, h3, h4 { font-family: var(--font-heading); }

/* ── Text Effects ── */
.text-gradient {
  background: linear-gradient(45deg, #D40079, #FFD700);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.shadow-text {
  text-shadow: 2px 2px 4px rgba(0,0,0,0.5), 0 0 20px rgba(255,215,0,0.3);
}

/* ── Animations ── */
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes raceIn {
  from { opacity: 0; transform: translateX(-100%); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes bounce {
  0%, 20%, 50%, 80%, 100% { transform: translateY(0) translateX(-50%); }
  40% { transform: translateY(-12px) translateX(-50%); }
  60% { transform: translateY(-6px) translateX(-50%); }
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}
@keyframes racingPulse {
  0%   { opacity: 1; }
  50%  { opacity: 0.7; }
  100% { opacity: 1; }
}
@keyframes chevronFlow {
  0%   { transform: translateX(0); }
  100% { transform: translateX(10px); }
}
@keyframes countUp {
  from { opacity: 0; transform: scale(0.5); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes tickerScroll {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}
@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* ── Scroll Reveal Utility ──────────────────────────────────────────────────────
   A7 (round 2). THE DEFECT, and it is not in this rule — it is in how `transition`
   composes. `.reveal` is applied to the SAME element as a component class
   (`class="insight-news-card reveal"`), and that component declares its own
   `transition:` SHORTHAND for its hover affordances. Equal specificity (0,1,0),
   later file → the shorthand REPLACES the entrance transition wholesale. The element
   still inherits `opacity: 0` from here, so it renders invisible and then snaps to 1
   in a single frame when `.is-visible` lands. Measured on the shipped build: 2 of the
   16 routes that carry `.reveal` targets showed before=0, after=1 and **zero**
   intermediate opacity samples over a 630 ms window (insight, news-events).

   THE FIX. An `animation` cannot be wiped by a `transition` shorthand — they are
   independent properties — so the FADE moves onto a keyframe animation and can no
   longer be cancelled by a component. Two deliberate restrictions:
     · the keyframes touch ONLY opacity. If they animated `transform` too, the
       `both` fill-mode would pin `transform` at the animation's end value and
       silently kill every hover-lift on a `.reveal` card (animation origin outranks
       a normal declaration).
     · `transform` therefore stays on the transition. A component that overrides the
       transition also owns that element's motion, so the slide degrades to "no slide"
       rather than to "invisible" — the entrance still reads.
   ────────────────────────────────────────────────────────────────────────────── */
.reveal {
  opacity: 0; transform: translateY(24px);
  transition: opacity 0.4s ease, transform 0.4s ease; /* entrance ≤400ms (Batch 3 Gate 6) */
}
.reveal.is-visible {
  opacity: 1; transform: translateY(0);
  animation: njt-reveal-fade 0.4s ease both;
}
@keyframes njt-reveal-fade { from { opacity: 0; } to { opacity: 1; } }
/* Delays must exist on BOTH engines or a staggered card fades on time and slides late. */
.reveal-delay-1 { transition-delay: 0.1s; animation-delay: 0.1s; }
.reveal-delay-2 { transition-delay: 0.2s; animation-delay: 0.2s; }
.reveal-delay-3 { transition-delay: 0.3s; animation-delay: 0.3s; }
.reveal-delay-4 { transition-delay: 0.4s; animation-delay: 0.4s; }
@media (prefers-reduced-motion: reduce) {
  /* navigation.js already force-marks every target `.is-visible` at bind time under
     reduced motion; suppress the fade so it is genuinely instant, not a 400ms fade. */
  .reveal, .reveal.is-visible { transition: none; animation: none; transform: none; }
}

/* ── Container ── */
.container {
  max-width: var(--content-w);
  margin: 0 auto;
  padding: 0 24px;
}
.container--wide {
  max-width: var(--max-w);
  padding-left: 32px;  /* HOUSE-RULES §9: match header gutter (was inherited 24px) */
  padding-right: 32px;
}

/* ── Texture Overlays ── */
.texture-grid {
  background-image:
    linear-gradient(rgba(255,215,0,0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,215,0,0.03) 1px, transparent 1px);
  background-size: 50px 50px;
}
.texture-dots {
  background-image: radial-gradient(circle at 1px 1px, rgba(255,255,255,0.05) 1px, transparent 0);
  background-size: 40px 40px;
}
.racing-stripe {
  height: 4px;
  background: linear-gradient(to right, transparent, var(--gold), transparent);
  opacity: 0.2;
}
.glow-orb {
  position: absolute;
  width: 384px;
  height: 384px;
  border-radius: 50%;
  background: rgba(255,215,0,0.08);
  filter: blur(120px);
  pointer-events: none;
}
.glow-orb--magenta {
  background: rgba(212,0,121,0.08);
}

/* ── Chevron Arrow CTA ── */
.chevron-arrow::after {
  content: ' \00BB\00BB\00BB';
  color: var(--gold);
  animation: chevronFlow 1s infinite alternate;
  display: inline-block;
}
