/* ============================================================
   Ztor 2.0 — Design Tokens
   Source of truth: Figma file PjfXW29QsWoPUSaFvYC0Wb (Foundations)
   ============================================================ */

:root {
  /* ─────────────────────────────────────────
     COLOR — Primitives
     ───────────────────────────────────────── */

  /* Brand accent ramp. Named by ROLE, not hue, on purpose: the brand colour
     is still in flux, so a future recolour is a values-only edit RIGHT HERE
     (these --brand-* lines) — no consumer, no alias, no rebuild to touch.
     Currently orange, anchored on #ffa33f at 500; tints/shades mirror the
     prior ramp's lightness curve. */
  --brand-50:  #fff5e5;
  --brand-100: #ffe7c7;
  --brand-200: #ffcf94;
  --brand-300: #ffba6b;
  --brand-400: #ffab52;
  --brand-500: #ffa33f;   /* brand */
  --brand-600: #f37e12;
  --brand-700: #be600e;
  --brand-800: #85410a;
  --brand-900: #4f2708;
  --brand-ink: #271302;   /* text on brand bg */
  --brand-rgb: 255, 163, 63;  /* brand #ffa33f as r,g,b — use rgba(var(--brand-rgb), α)
                                 for glows/borders/glass so a recolour stays values-only here.
                                 Replaced ~128 hardcoded old-amber rgba refs, 2026-06-29. */
  --success-rgb: 34, 197, 94; /* success #22c55e as r,g,b — same pattern as --brand-rgb
                                 (color-mix fallback for 12% tinted pills etc.) */
  --error-rgb: 239, 68, 68;   /* error #ef4444 as r,g,b — same pattern (12% tinted
                                 chips/pills, e.g. 排除地區 chip is-on 態) */

  /* Legacy aliases → --brand-*. The old hue-based name (~200 existing refs
     across CSS + inline HTML, plus main-repo cherry-picks) keeps resolving,
     so renaming the source-of-truth above is zero-risk. New code should use
     --brand-*; these can be dropped once all var(--yellow-*) refs migrate. */
  --yellow-50:  var(--brand-50);
  --yellow-100: var(--brand-100);
  --yellow-200: var(--brand-200);
  --yellow-300: var(--brand-300);
  --yellow-400: var(--brand-400);
  --yellow-500: var(--brand-500);
  --yellow-600: var(--brand-600);
  --yellow-700: var(--brand-700);
  --yellow-800: var(--brand-800);
  --yellow-900: var(--brand-900);
  --yellow-ink: var(--brand-ink);

  /* Neutral */
  --neutral-50:  #fafafa;
  --neutral-100: #f5f5f5;
  --neutral-200: #e5e5e5;
  --neutral-300: #d4d4d4;
  --neutral-400: #a3a3a3;
  --neutral-500: #737373;
  --neutral-600: #525252;
  --neutral-700: #1e1e1e;
  --neutral-800: #131313;
  --neutral-900: #0a0a0a;  /* canvas dark */
  --neutral-white: #ffffff;
  --neutral-black: #000000;

  /* Content-vertical accents — the colour-coded category pills
     (.section-eyebrow--tag). Two PRIMARY pillars (film/music) carry the loud,
     opposed pair (blue/red); two SECONDARY verticals (AI/events) take the
     quiet pair (orange/green); functional sections stay charcoal (no colour).
     White label on every fill. Re-theme verticals here. */
  --cat-film:    #ff6a00;   /* 影視    — orange · PRIMARY pillar (warm-tonal with music) */
  --cat-music:   #ff3b30;   /* 音樂    — red    · PRIMARY pillar     */
  --cat-origin:  #014aff;   /* 原力/AI — blue   · secondary (cool = AI; freed when film took orange) */
  --cat-events:  #00c853;   /* 活動/同場加映 — green · secondary      */
  --cat-neutral: #565656;   /* 功能/跨類 — charcoal (not a vertical)  */

  /* Skeleton-loader surface — sits just above the dark canvas. */
  --skeleton-surface: #161616;

  /* Score-orb liquid tiers — removed 2026-06-25 (Dolly). Once a
     psychological grade scale (rust=poor / honey=caution / leaf=good /
     prism=exceptional) harmonized to the brand hue; later flattened to one
     black fill, then replaced entirely by the conic RING
     (16-ztor-score.css). The --score-liquid-* tokens rendered nowhere and
     were dead. */

  /* Score numeral ink — legacy from the liquid-glass orb (design decision
     2026-06-11), when the tier lived in the number. The current RING version
     (16-ztor-score.css) colours the ARC, not the numeral, so the old
     top/mid/low inks rendered nowhere and were removed (2026-06-25 design
     call, Dolly). Only --score-ink-high survives: refine-library still inks
     the library meta-score green with it.
       high = #30d158, Apple's dark-mode system green — colored text on
              near-black; true green, saturated (not pastel-cheap #4ade80). */
  --score-ink-high: #30d158;

  /* Score RING (conic arc) mid tier — a bright pure yellow, deliberately NOT
     the brand orange. Since the brand is now orange (#ffa33f), a 50–69 score
     drawn in orange both blends into orange surfaces and reads as "the brand
     = mediocre". Yellow keeps the gauge a clean red→yellow→green traffic
     light and stays distinct from the brand on both dark and orange stripes. */
  --score-ring-mid: #ffe600;

  /* Status */
  --success-500: #22c55e;
  --success-700: #15803d;
  /* Warning went yellow 2026-07-08 (design call, Dolly): the old #fb923c sat
     ~10° off the brand orange and read as "brand", not "caution". #fed200 is
     the warning icon's leading gradient stop (assets/icons/warning.svg), so
     icon and text always match. NO warning-700: dark yellow always turns
     muddy olive — on light stripes, render warnings as a #fed200 badge with
     --warning-ink text, never as dark-yellow text. */
  --warning-500: #fed200;
  --warning-ink: #5c4300;  /* text on yellow bg */
  --error-500:   #ef4444;
  --error-700:   #b91c1c;
  --error-ink:   #2a0a0a;  /* text on red bg */
  --info-500:    #3b82f6;
  --info-700:    #1d4ed8;
  /* Highlight（rose）＝「請看這裡」：NEW/HOT/推薦/精選/喜歡，與 Error 紅可同畫面
     共存。移植自 Figma DS Primitives Highlight ramp（2026-07-13，Dolly 指定
     「喜歡」用 DS highlight 時發現 tokens.css 尚未移植，照 Warning 前例補上）。 */
  --highlight-500: #f43f5e;
  --highlight-700: #be123c;
  --highlight-ink: #2a0a12;  /* text on rose bg */

  /* Chart / data-viz series (2026-07-08, Hana's proposal, accepted) — meaning
     comes from the LEGEND, never from the hue. Data graphics ONLY; never for
     chips, tags, or status (must not drift into a 4th status colour). Assign
     --chart-1..n in order; rows with real semantics keep semantic tokens
     (income --success-500, expense --error-500). 400-weight brightness,
     tuned for the dark canvas. --chart-1/-2 map to the 1.0 donut green/purple. */
  --chart-1: #4ade80;       /* green  */
  --chart-2: #a78bfa;       /* violet */
  --chart-3: #38bdf8;       /* sky    */
  --chart-4: #f472b6;       /* pink   */
  --chart-neutral: #737373; /* "other / remainder" slices (= neutral-500) */

  /* White Alpha — standard transparency stops for overlays / borders / glass */
  --white-alpha-4:  rgba(255, 255, 255, 0.04);
  --white-alpha-8:  rgba(255, 255, 255, 0.08);
  --white-alpha-16: rgba(255, 255, 255, 0.16);
  --white-alpha-24: rgba(255, 255, 255, 0.24);

  /* ─────────────────────────────────────────
     COLOR — Semantic (Dark mode)
     ───────────────────────────────────────── */

  --bg-primary:   var(--neutral-900);   /* page bg */
  --bg-secondary: var(--neutral-800);   /* surface (raised section) */
  --bg-tertiary:  var(--neutral-700);   /* card / elevated panel */
  --bg-card:      var(--bg-tertiary);   /* semantic alias */

  --text-primary:   rgba(255, 255, 255, 0.95);
  --text-secondary: rgba(255, 255, 255, 0.65);
  --text-tertiary:  rgba(255, 255, 255, 0.45);
  --text-disabled:  rgba(255, 255, 255, 0.35);

  --border-subtle:  rgba(255, 255, 255, 0.04);
  --border-default: rgba(255, 255, 255, 0.12);
  --border-strong:  rgba(255, 255, 255, 0.22);

  --interactive-primary:    var(--yellow-500);
  --interactive-on-primary: var(--yellow-ink);

  /* Glass overlay tokens (used by Ghost/IconButton) */
  --glass-bg-default:  rgba(255, 255, 255, 0.10);
  --glass-bg-hover:    rgba(255, 255, 255, 0.18);
  --glass-bg-pressed:  rgba(255, 255, 255, 0.26);
  --glass-bg-disabled: rgba(255, 255, 255, 0.04);

  --glass-stroke-default:  rgba(255, 255, 255, 0.20);
  --glass-stroke-hover:    rgba(255, 255, 255, 0.32);
  --glass-stroke-pressed:  rgba(255, 255, 255, 0.45);
  --glass-stroke-disabled: rgba(255, 255, 255, 0.08);

  /* GLASS effect web equivalent (Figma GLASS effect ≈ backdrop-filter) */
  --glass-blur: blur(20px) saturate(1.4);

  /* ── Liquid-glass material — SINGLE SOURCE shared by the mobile bottom-nav
     pill (43-bottom-nav.css) AND the stuck filter shelf (45-sticky-tabs.css).
     Byte-identical to the original .botnav__list recipe — do NOT "tidy" the
     numbers; both surfaces must render the same frost. Geometry (radius,
     shadows, pseudo-element ring) stays local to each component; only the
     reusable MATERIAL lives here. Framework-migration foundation — inert
     until 43/44/45 markup is wired onto a page. */
  --glass-fill:
    linear-gradient(135deg,
      rgba(130, 170, 255, 0.06) 0%,
      rgba(255, 255, 255, 0.03) 46%,
      rgba(255, 163, 63, 0.055) 100%),
    rgba(20, 21, 27, 0.52);
  --glass-backdrop: blur(17px) saturate(1.7) brightness(1.06);
  --glass-border:   0.8px solid rgba(255, 255, 255, 0.10);
  /* specular sheen — pill sweeps it as an arc, the shelf as a top hairline cap */
  --glass-sheen:
    linear-gradient(180deg,
      rgba(225, 238, 255, 0.18) 0%,
      rgba(255, 255, 255, 0.04) 32%,
      transparent 55%);
  /* depth shadow — soft cool top highlight + faint warm catch + two ambient drops */
  --glass-shadow:
    inset 0 1px 0.5px rgba(225, 238, 255, 0.30),
    inset 0 -1px 3px rgba(255, 186, 122, 0.06),
    0 3px 12px rgba(0, 0, 0, 0.26),
    0 10px 28px rgba(0, 0, 0, 0.20);
  /* iridescent rim — spectral ring (paint via the mask-composite trick in component CSS) */
  --glass-rim:
    conic-gradient(from 130deg,
      rgba(120, 180, 255, 0.55),
      rgba(180, 130, 255, 0.45),
      rgba(255, 160, 90, 0.45),
      rgba(120, 220, 220, 0.45),
      rgba(120, 180, 255, 0.55));

  /* ─────────────────────────────────────────
     MOTION
     One easing curve for the whole site — a fast-out deceleration
     (the element meets the cursor, then settles). Use for all
     hover/press/reveal transitions instead of the browser default
     `ease`. Durations stay per-component (120–250ms typical).

     BREAKPOINTS (reference — CSS vars can't drive @media):
       1280px  header condensation stage 1
       1024px  header condensation stage 2, tablet adjustments
        768px  site-wide mobile breakpoint (single source: the
               MOBILE TWEAKS block at the END of components.css)
     ───────────────────────────────────────── */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);

  /* ── Framework-migration reveal system — additive only (--ease-out above is
     UNCHANGED, still the site-wide default). New curves + a duration/travel/
     stagger/sequence scale for the shared reveal module (assets/reveal.js) and
     the nav scroll system (assets/sticky-tabs.js). Inert until pages read
     these via the JS/CSS that consumes them. */
  --ease-settle:     cubic-bezier(0.22, 1, 0.36, 1);  /* heavier tail: long cascades (footer tagline) */
  --ease-emphasized: cubic-bezier(0.4, 0, 0.2, 1);    /* exits / header hide — strong acceleration */

  /* Nav scroll-system durations (sticky-tabs.js + 45-sticky-tabs.css). The behavioural
     thresholds (STEP/SHOW_AT/REVEAL_AT px) live as named constants at the top of the JS. */
  --dur-nav-show:  200ms;   /* header reveal / community-bar base */
  --dur-nav-hide:  250ms;   /* header hide + the stuck shelf riding up with it */
  --dur-nav-morph: 380ms;   /* plain → glass material morph as a row sticks */

  /* Duration scale — by element weight, deliberately non-uniform */
  --dur-xs:  360ms;   /* eyebrow, link — small, read instantly */
  --dur-sm:  440ms;   /* title, sub, tabs — header spine */
  --dur-md:  520ms;   /* cards, media — heaviest pixels, calmest move */
  --dur-tag: 460ms;   /* footer tagline chars */

  /* Travel scale — premium subtle (10–30px); desktop / mobile */
  --reveal-y-sm:   12px;  --reveal-y-sm-m:  8px;   /* eyebrow, link, tagline char */
  --reveal-y-md:   16px;  --reveal-y-md-m: 12px;   /* title, sub, tabs */
  --reveal-y-lg:   20px;  --reveal-y-lg-m: 14px;   /* cards, media */

  /* Stagger — peers within a role group (ms); desktop / mobile */
  --stagger-base:  60ms;  --stagger-base-m: 38ms;
  --stagger-tag:   26ms;  --stagger-tag-m:  16ms;

  /* Role-sequence — delay from section trigger to each group (ms) */
  --seq-eyebrow:  0ms;
  --seq-title:   90ms;
  --seq-sub:    160ms;
  --seq-media:  210ms;
  --seq-cta:    260ms;

  /* ─────────────────────────────────────────
     TYPOGRAPHY
     ───────────────────────────────────────── */

  /* Font stacks — Latin tier first so mixed CJK+EN runs render English / 數字
     in Satoshi (Fontshare, render-blocking link id=ztor-satoshi in each page
     head), then fall through to Inter, and finally to the CJK face for Chinese
     glyphs (browsers walk the stack per-glyph — Satoshi 無 CJK 字元，中文自然
     落到 LINE Seed/Noto，等效 unicode-range 釘死拉丁）。
     2026-07-30 Dolly 拍板：全站拉丁一律 Satoshi（原 Proxima Nova/Typekit 退役）。
     Display tier:  brand UI — Hero / H1–H4 / Button LG / Nav.
     Text tier:     reading & secondary UI. */
  --font-cjk-display: 'Satoshi', 'Inter',
                      'LINE Seed TW', 'Noto Sans TC',
                      'PingFang TC', 'Microsoft JhengHei', sans-serif;
  --font-cjk-text:    'Satoshi', 'Inter',
                      'Noto Sans TC',
                      'PingFang TC', 'Microsoft JhengHei', sans-serif;
  /* ^ Text tier stack 保留 Noto（給 <16px 與 Light 閱讀 style 用）。
     2026-06-17：Dolly 定雙 tier — Display=LINE Seed、Text=Noto（LINE Seed 字重不足）。
     2026-06-26：Dolly 改規範「≥16px 中文一律 LINE Seed」→ 根字體 html,body 與
     .t-h5/.t-body/.t-body-lg 改走 --font-cjk-display；<16px（.t-body-sm/.t-caption/
     .t-eyebrow）與 Light 閱讀 style（.t-body-reading/.t-body-preview）仍用此 Noto stack。
     代價：16px+ 的 Medium(500) 中文因 LINE Seed 無 500 會 fallback 成 Regular(400)，略細。 */
  --font-latin:       'Satoshi', 'Inter',
                      system-ui, -apple-system, sans-serif;

  /* Font weights */
  --fw-thin:      100;
  --fw-light:     300;
  /* Regular = 400 per Dolly DS 規範（2026-06-17 改回）。L 曾設 500,稱 16px
     Noto 400 在暗底 shimmer;但實測一般文案 400 無虞,且需與 Medium(500)
     拉開階層(Regular≠Medium),故回 400。 */
  --fw-regular:   400;
  --fw-medium:    500;
  --fw-semibold:  600;
  --fw-bold:      700;
  --fw-extrabold: 800;
  --fw-black:     900;

  /* Font sizes */
  --fs-display:  76px;
  --fs-h1:       48px;
  --fs-h2:       42px;
  --fs-feature-title: 36px;
  --fs-h3:       24px;
  --fs-h4:       20px;
  --fs-h5:       16px;
  --fs-body-lg:  18px;
  --fs-body:     16px;
  --fs-body-sm:  14px;
  --fs-caption:  12px;

  /* Line heights */
  --lh-display:  83px;
  --lh-h1:       57px;
  --lh-h2:       50px;
  --lh-feature-title: 43px;
  --lh-h3:       31px;
  --lh-h4:       26px;
  --lh-h5:       24px;
  --lh-body-lg:  30px;
  --lh-body:     27px;
  --lh-body-sm:  23px;
  --lh-caption:  18px;
  --lh-label:    15px;

  /* Letter spacing */
  --ls-display: -2px;
  --ls-h1:      -1px;
  --ls-h2:      -1px;
  --ls-h3:      -0.5px;
  --ls-h4:       0;
  --ls-h5:       0;
  --ls-body:     0;
  --ls-body-lg:  0;
  --ls-body-sm:  0;
  --ls-caption:  0;
  --ls-label:    1.2px;

  /* ─────────────────────────────────────────
     SPACING (4px base scale)
     ───────────────────────────────────────── */

  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-8:  32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-14: 56px;
  --space-16: 64px;
  --space-20: 80px;
  --space-24: 96px;
  --space-32: 128px;
  --space-40: 160px;

  /* ─────────────────────────────────────────
     RADIUS
     ───────────────────────────────────────── */

  --radius-none: 0;
  --radius-xs:   2px;
  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-xl:   16px;
  --radius-2xl:  24px;
  --radius-pill: 9999px;

  /* ─────────────────────────────────────────
     LAYOUT
     ───────────────────────────────────────── */

  --container-max:        1280px;
  --container-wide:       1440px;
  --container-padding-x:  48px;
  --header-height:        64px;
}

/* ─────────────────────────────────────────
   TYPOGRAPHY UTILITY CLASSES
   17 styles matching Figma Foundations
   ───────────────────────────────────────── */

.t-display {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  font-weight: var(--fw-bold);
}

.t-h1 {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
  font-weight: var(--fw-bold);
}

.t-h2 {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  font-weight: var(--fw-bold);
}

.t-feature-title {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-feature-title);
  line-height: var(--lh-feature-title);
  letter-spacing: var(--ls-h2);
  font-weight: var(--fw-bold);
}

.t-h3 {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
  font-weight: var(--fw-bold);
}

.t-h4 {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  font-weight: var(--fw-bold);
}

.t-h5 {
  font-family: var(--font-cjk-display); /* 16px Bold → LINE Seed (≥16px rule) */
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  font-weight: var(--fw-bold);
}

.t-body-lg {
  font-family: var(--font-cjk-display); /* 18px Regular → LINE Seed (≥16px rule) */
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  font-weight: var(--fw-regular);
}

.t-body {
  font-family: var(--font-cjk-display); /* 16px Regular → LINE Seed (≥16px rule) */
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-regular);
}

.t-body-sm {
  font-family: var(--font-cjk-text);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  font-weight: var(--fw-regular);
}

/* reading/preview 雖 ≥16px，但字重是 Light(300)；LINE Seed TW 無 300（最近只有
   Thin 100）會渲染太細，故這兩個閱讀 style 例外保留 Noto。 */
.t-body-reading {
  font-family: var(--font-cjk-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-light);
}

.t-body-preview {
  font-family: var(--font-cjk-text);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  font-weight: var(--fw-light);
}

.t-caption {
  font-family: var(--font-cjk-text);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: var(--fw-regular);
}

.t-eyebrow {
  font-family: var(--font-cjk-text);
  font-size: var(--fs-caption);
  line-height: var(--lh-label);
  letter-spacing: var(--ls-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
}

.t-nav {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  font-weight: var(--fw-regular);
}

.t-button-lg {
  font-family: var(--font-cjk-display);
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  font-weight: var(--fw-bold);
}

.t-button-md {
  font-family: var(--font-cjk-text);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  font-weight: var(--fw-medium);
}

.t-button-sm {
  font-family: var(--font-cjk-text);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: var(--fw-medium);
}

/* ─────────────────────────────────────────
   GLOBAL RESET / BASE
   ───────────────────────────────────────── */

*, *::before, *::after {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg-primary);
  color: var(--text-primary);
  /* 2026-06-26 Dolly：根字體中文改 LINE Seed（≥16px 一律 LINE Seed）。Latin/數字
     仍走 Proxima（display stack 第一順位）。<16px 的 text style + light 閱讀 style
     另以 --font-cjk-text 釘回 Noto，見下方 .t-body-sm/.t-caption/.t-body-reading。 */
  font-family: var(--font-cjk-display);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Sticky footer：main 自己撐到「視窗高 − header 高」，內部 flex column，
   footer 用 margin-top:auto 推到底。內容少的短頁（如活動頁）下方留白落在
   main 內，footer 不浮上來。footer 位於 main 內部（全站結構一致）。
   main 自帶 min-height，不依賴 body 是否為 flex 容器。 */
main {
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - var(--header-height));
}

/* Reserve the scrollbar gutter so navigating between a tall page (scrollbar
   shown) and a short one (no scrollbar) doesn't shift centred content — the
   "jump" on page change. No-op on overlay-scrollbar systems (e.g. macOS). */
html {
  scrollbar-gutter: stable;
}

a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
img { max-width: 100%; display: block; }

/* Text selection — brand yellow with ink text, replacing the browser
   default magenta/blue. */
::selection {
  background: var(--yellow-500);
  color: var(--yellow-ink);
}
::-moz-selection {
  background: var(--yellow-500);
  color: var(--yellow-ink);
}

/* ─────────────────────────────────────────
   LAYOUT UTILITIES
   ───────────────────────────────────────── */

.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding-left: var(--container-padding-x);
  padding-right: var(--container-padding-x);
}

.container--wide {
  max-width: var(--container-wide);
}

.full-bleed {
  width: 100%;
}

/* ─────────────────────────────────────────
   SECTION RHYTHM
   Each homepage chapter sits inside a .section.
   Backgrounds alternate page <-> surface for cinematic zebra rhythm.
   ───────────────────────────────────────── */

.section {
  position: relative;
  padding-block: clamp(64px, 9vw, 100px);
}

.section--tight { padding-block: clamp(48px, 6vw, 80px); }
.section--loose { padding-block: clamp(96px, 12vw, 160px); }

/* ── SECTION BACKGROUNDS + THEMES moved out ───────────────────────────────
   The zebra background classes (.section-bg-page / .section-bg-surface) and
   all their foreground contrast rules now live in their own file:
       section-themes.css   (linked after components.css on every page)
   Keep section-background work there — do NOT re-add it here. ──────────── */

/* ─────────────────────────────────────────
   SECTION EYEBROW
   Yellow brand label that opens each homepage section.
   ───────────────────────────────────────── */

.section-eyebrow {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-cjk-text);
  font-size: var(--fs-caption);
  line-height: 1.33;
  letter-spacing: 0.12em;
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  color: var(--yellow-500);
}

/* ─────────────────────────────────────────
   SECTION HEADER
   Pattern: [chapter-eyebrow] → [title row: title/sub on left, link on right]
   Used at the top of every chapter on the homepage.
   ───────────────────────────────────────── */

.section-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-10);
}

.section-header__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-8);
  flex-wrap: wrap;
}

.section-header__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.section-header__title {
  font-family: var(--font-cjk-display);
  font-weight: var(--fw-bold);
  font-size: clamp(28px, 3.4vw, 42px);
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  margin: 0;
}

.section-header__sub {
  font-family: var(--font-cjk-text);
  font-weight: var(--fw-regular);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
  max-width: 520px;
  margin: 0;
}

/* "查看所有 →" right-side link */
.section-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-cjk-text);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  color: var(--yellow-500);
  white-space: nowrap;
  /* Invisible hit-area expansion: padding grows the tap target to ~44px,
     the matching negative margin cancels the layout shift, so the link
     looks identical but is far easier to hit. Visual weight unchanged
     on purpose — the section's CTA is its content, not this exit. */
  padding: 12px 14px;
  margin: -12px -14px;
  border-radius: var(--radius-pill);
  transition: gap 150ms ease;
}

.section-link:hover { gap: var(--space-3); }

.section-link__arrow {
  width: 16px;
  height: 16px;
  display: inline-block;
  /* Flat arrow: a single clean glyph masked in the link's OWN colour
     (currentColor) — brand-orange on dark stripes, ink on light. Dropped the
     glass material (specular + extrusion) — at 16px it read as a muddy blob
     / stray highlight. Bonus: recolours with the brand automatically, so
     there's no baked SVG to re-bake when --brand-* changes. */
  background-color: currentColor;
  -webkit-mask: url('assets/icons/arrow_right.svg') center / contain no-repeat;
          mask: url('assets/icons/arrow_right.svg') center / contain no-repeat;
  /* The "beckon" loop lives below, gated behind .is-beckoning — a per-link
     IntersectionObserver (index.html / screening-room.html) adds the class
     when THE LINK enters the viewport, removes it when fully off-screen.
     So the knock plays the moment you arrive at a section, every visit.
     Without JS the arrow is simply still — motion is enhancement. */
}

/* Ambient "beckon": the arrow alone knocks twice (6px, then a 3px echo)
   the moment its section arrives, then rests — 840ms of motion at the
   START of a 3.5s cycle (76% silence after). Knock-first matters: the
   observer adds the class on entry, so the eye sees the loop begin.
   Horizontal on purpose: it rehearses the hover's gap-widen instead of
   introducing a second motion language. Whole-link bounce is banned —
   moving text can't be read. Viewport entry IS the stagger: links arrive
   one at a time, so no per-section delays are needed.
   Percentages = absolute knock times (240/480/660/840ms) over the cycle —
   change the duration and you change the knock speed; recompute, don't
   eyeball. */
.section-link.is-beckoning .section-link__arrow {
  animation: section-link-beckon 3.5s infinite;
}

@keyframes section-link-beckon {
  0%     { transform: translateX(0);
           animation-timing-function: var(--ease-out); }
  6.9%   { transform: translateX(6px);
           animation-timing-function: cubic-bezier(0.77, 0, 0.175, 1); }
  13.7%  { transform: translateX(0);
           animation-timing-function: var(--ease-out); }
  18.9%  { transform: translateX(3px);
           animation-timing-function: cubic-bezier(0.77, 0, 0.175, 1); }
  24%    { transform: translateX(0); }
  100%   { transform: translateX(0); }
}

/* On hover the invitation goes quiet and the gap-widen does its job.
   Pause (not none) — `none` would snap a mid-knock arrow back. */
@media (hover: hover) and (pointer: fine) {
  .section-link:hover .section-link__arrow { animation-play-state: paused; }
}

/* The loop is pure decoration — remove it entirely, keep hover feedback. */
@media (prefers-reduced-motion: reduce) {
  .section-link__arrow { animation: none; }
}

/* ──────────────────────────────────────────────────────────────
   English locale type system. i18n.js sets <html lang="en"> and loads
   Satoshi (UI/body) + Afacad (display headings). Chinese is untouched.

   Roles:
     • Hero headlines, page & section titles → Afacad
     • Body, buttons, forms, navigation, prices, stats, dense UI → Satoshi

   Base = everything Satoshi (the 3 font tokens), then an explicit Afacad
   allow-list for the editorial title tier only. */
html[lang="en"] {
  --font-cjk-display: 'Satoshi', 'Inter', system-ui, -apple-system, sans-serif;
  --font-cjk-text:    'Satoshi', 'Inter', system-ui, -apple-system, sans-serif;
  --font-latin:       'Satoshi', 'Inter', system-ui, -apple-system, sans-serif;
}

/* Afacad — hero headlines + page/section titles only. Higher specificity
   than the component rules (html[lang="en"] prefix), so no !important. */
html[lang="en"] :is(
  /* hero + page/section headings */
  .hero-carousel__title,
  .page-head__title,
  .section-header__title,
  .shop-head__title,
  .lb-head__title,
  .creator-hero__name,
  .creator-sec__title,
  .rf-hero__title,
  .t-display, .t-h1, .t-h2,
  /* side navigation labels */
  .side-rail__label,
  /* card / thumbnail titles */
  .ai-mosaic__tile-title,
  .classic-card__title,
  .film-card__title,
  .community-card__title,
  .register-card__title,
  .post-card__title,
  .news-card__title,
  .activity-card__title,
  .aic-card__title,
  .work-card__title,
  .shop-card__title,
  .creator-card__name,
  .cocreation-card__title
) {
  font-family: 'Afacad', 'Satoshi', 'Inter', system-ui, -apple-system, sans-serif;
}

/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE SPACING TOKENS (framework-migration foundation)
   Semantic spacing on top of the --space-* primitive scale, redefined at the
   phone breakpoint so spacing flows from ONE place instead of being hand-tuned
   per component. Desktop and mobile get genuinely different values here.
   Inert for now: no existing rule reads these yet (.section still uses its
   own hardcoded clamp() above — wiring it to --space-section is a Phase-2
   task, not part of this migration). Components reference these once wired
   so a single edit retunes density site-wide.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --space-section: clamp(64px, 9vw, 100px);   /* .section vertical rhythm (not yet wired) */
  --gap-card: var(--space-6);                 /* card inner padding (24px) */
  --gap-rail: var(--space-6);                 /* rail / grid gap (24px) */
  --stack-md: var(--space-5);                 /* medium vertical stack (20px) */
  --stack-lg: var(--space-10);                /* section-header bottom (40px) */
}
@media (max-width: 767.98px) {
  :root {
    --space-section: clamp(40px, 10vw, 64px); /* tighter vertical rhythm on phone */
    --gap-card: var(--space-4);               /* 24 → 16 */
    --gap-rail: var(--space-4);               /* 24 → 16 */
    --stack-lg: var(--space-8);               /* 40 → 20 */
  }
}
