/* Kry UI Kit bundle for kry-elementor-bridge — auto-generated */

/* === FOUNDATION === */
/* ============================================================
   Kry UI — FOUNDATION layer
   Primitive HSL variables (the "atoms of color").
   Override these in brand preset → cả palette shift theo math.
   v0.4 — 2026-05-20
   ============================================================ */

:root {
  /* ============ BRAND PRIMITIVES (override per brand) ============ */
  /* Primary brand color — what brand "feels like" */
  --brand-primary-h: 12;       /* hue: 12 = coral · 28 = nâu trầm · 140 = sage · 252 = violet */
  --brand-primary-s: 50%;      /* saturation */
  --brand-primary-l: 60%;      /* lightness — base value */

  /* Secondary accent */
  --brand-accent-h: 95;
  --brand-accent-s: 18%;
  --brand-accent-l: 39%;

  /* Tertiary highlight */
  --brand-highlight-h: 38;
  --brand-highlight-s: 50%;
  --brand-highlight-l: 65%;

  /* Semantic status colors (rarely overridden per brand)
     v0.4.2 (2026-05-20) — darkened L values for WCAG AA text-on-light + text-on-soft-bg.
     Old L (success=40, danger=60, warning=50, info=53) failed AA when used as `color:` on
     cream OR on their own --*-soft bg (e.g. .badge-* → ratios 2.7-4.4 / need 4.5).
     New L (success=27, danger=44, warning=28, info=30):
       - PASS as text on cream (#fcfbf7)            → 4.8-5.5 :1
       - PASS as bg with white text                 → 5.0-5.5 :1
       - PASS as text on own --*-soft (alpha 0.2)   → 4.7-5.3 :1
     Soft bg alpha reduced 0.3 → 0.2 (in semantic.css) so it stays visually soft. */
  --status-success-h: 158;
  --status-success-s: 64%;
  --status-success-l: 27%;

  --status-danger-h: 0;
  --status-danger-s: 75%;
  --status-danger-l: 44%;

  --status-warning-h: 38;
  --status-warning-s: 92%;
  --status-warning-l: 28%;

  --status-info-h: 195;
  --status-info-s: 86%;
  --status-info-l: 30%;

  /* Neutral text/border base (warm tone tied to brand hue for harmony) */
  --neutral-h: var(--brand-primary-h);
  --neutral-s: 8%;

  /* ============ AESTHETIC: WARM ============ */
  /* Cream + soft accents. For consumer/landing/editorial/PWA. */
  --warm-bg-h: 40;
  --warm-bg-s: 50%;
  --warm-bg-l: 96%;          /* very light cream */
  --warm-surface-l: 98%;     /* card surface (lighter than bg) */
  --warm-surface2-l: 94%;    /* page accent / linen */
  --warm-border-l: 87%;
  --warm-rule-l: 83%;

  /* Warm text (uses neutral hue for harmony)
     v0.5 (Iter 7 A, 2026-05-20) — AAA bump:
       --warm-ink-2-l: 35 → 30 (AAA 7:1 normal text on cream across all 7 brand hues).
         Old 35% only reached 6.17-6.95 (AA 4.5 yes, AAA 7 no). New 30% → 7.55-8.24 worst-case.
         Side benefit: widens hierarchy gap text-2(30) ↔ text-3(38) from 3% → 8%.
       --warm-ink-3-l kept 38 (muted = large-text role, target 4.5:1, already passes 5.21-6.28).
       Verified via _a11y/contrast-aaa-iter7.js. */
  --warm-ink-l: 17%;         /* primary text */
  --warm-ink-2-l: 30%;       /* secondary — AAA 7:1 on cream */
  --warm-ink-3-l: 38%;       /* muted (large-text role) — AAA-large 4.5:1 on cream */

  /* ============ AESTHETIC: DARK ============ */
  /* Near-black with vivid accents. For dashboard/tool/dev. */
  --dark-bg-h: 240;
  --dark-bg-s: 20%;
  --dark-bg-l: 5%;           /* near-black */
  --dark-surface-l: 9%;
  --dark-surface2-l: 12%;
  --dark-sidebar-l: 7%;
  --dark-border-l: 18%;
  --dark-border-soft-l: 13%;

  --dark-text-h: 220;
  --dark-text-s: 13%;
  --dark-text-l: 91%;
  /* v0.5 (Iter 7 A, 2026-05-20) — AAA bump:
     --dark-text-2-l: 65 → 68 (AAA 7:1 on every dark surface incl. surface-2 L=12).
       Old 65% hit 6.84 on surface-2 (AA yes, AAA no). New 68% → 7.52-8.46.
       Side benefit: widens hierarchy gap text-2(68) ↔ text-3(62) from 3% → 6%.
     --dark-text-3-l kept 62 (muted = large-text role). */
  --dark-text-2-l: 68%;      /* secondary — AAA 7:1 on dark */
  --dark-text-3-l: 62%;      /* muted (large-text role) — AAA-large 4.5:1 on dark */

  /* Dark vivid accents (independent from brand for tech-y feel)
     v0.4.2: L kept 68% — balanced between (a) white text on `bg-violet` (4.35:1, just passes AA)
     and (b) text-on-dark-bg use. For chips/badges using `bg-dark-violet/20 text-dark-violet`,
     the visible bg is dark-violet blended onto near-black — use lighter chip text (token below). */
  --dark-violet-h: 252;
  --dark-violet-s: 100%;
  --dark-violet-l: 68%;

  --dark-cyan-h: 188;
  --dark-cyan-s: 86%;
  --dark-cyan-l: 53%;

  --dark-emerald-h: 158;
  --dark-emerald-s: 84%;
  --dark-emerald-l: 39%;

  --dark-amber-h: 38;
  --dark-amber-s: 92%;
  --dark-amber-l: 50%;

  --dark-danger-h: 0;
  --dark-danger-s: 84%;
  --dark-danger-l: 60%;

  /* ============ MESH GRADIENT PARAMS ============ */
  /* Warm mesh (4 hues for organic feeling) */
  --mesh-warm-1-h: 18;       /* peach */
  --mesh-warm-2-h: 340;      /* rose */
  --mesh-warm-3-h: 35;       /* amber */
  --mesh-warm-4-h: 120;      /* sage */

  /* Dark mesh */
  --mesh-dark-1-h: 265;      /* violet */
  --mesh-dark-2-h: 195;      /* cyan */
  --mesh-dark-3-h: 155;      /* emerald */
  --mesh-dark-4-h: 280;      /* deep violet */

  /* ============ TYPOGRAPHY — modular scale 1.25× (major third) ============ */
  --type-base: 16px;
  --type-ratio: 1.25;

  --type-xs:   12px;                                              /* enforce WCAG min */
  --type-sm:   14px;
  --type-md:   var(--type-base);                                  /* 16 */
  --type-lg:   calc(var(--type-base) * var(--type-ratio));        /* 20 */
  --type-xl:   calc(var(--type-base) * 1.5);                      /* 24 */
  --type-2xl:  calc(var(--type-base) * 1.875);                    /* 30 */
  --type-3xl:  calc(var(--type-base) * 2.25);                     /* 36 */
  --type-4xl:  calc(var(--type-base) * 3);                        /* 48 */
  --type-5xl:  calc(var(--type-base) * 3.75);                     /* 60 */
  --type-6xl:  calc(var(--type-base) * 4.5);                      /* 72 */
  --type-7xl:  calc(var(--type-base) * 6);                        /* 96 */
  --type-8xl:  calc(var(--type-base) * 8);                        /* 128 */

  /* Display scale beyond --type-8xl — deck hero numbers, magazine display */
  --type-mega: clamp(120px, 12vw, 180px);
  --type-hero: clamp(180px, 16vw, 240px);

  /* Editorial prose column widths */
  --prose-width:        680px;   /* optimal reading column */
  --prose-width-narrow: 580px;   /* mobile / tight */
  --prose-width-wide:   760px;   /* generous */

  --lh-tight:    1.1;
  --lh-snug:     1.25;
  --lh-normal:   1.5;
  --lh-relaxed:  1.65;
  --lh-loose:    1.75;

  /* Editorial line-heights */
  --lh-prose:       1.7;   /* body editorial — longer measure */
  --lh-pull-quote:  1.3;   /* big pull-quote */

  --tracking-tighter: -0.05em;
  --tracking-tight:   -0.025em;
  --tracking-normal:  0;
  --tracking-wide:    0.05em;
  --tracking-wider:   0.1em;
  --tracking-widest:  0.2em;

  /* ============ FONT FAMILIES ============ */
  /* Web font + metric-matched fallback (Inter Fallback / Source Serif 4 Fallback declared in fonts/fonts.css)
     prevents CLS during async font load — fallback shows immediately with adjusted metrics so swap to
     web font is invisible. Pattern follows Next.js next/font and web.dev guidance. */
  --font-sans:    'Inter', 'Inter Fallback', system-ui, -apple-system, sans-serif;
  --font-display: 'Plus Jakarta Sans', 'Inter', 'Inter Fallback', sans-serif;
  /* Source Serif 4 = winner cho VN double-diacritic stack (ư̛+sắc, ơ̛+huyền, etc.)
     Test report: 00-templates/ui-kit/_font-test/test-vn-isolate.png — render dấu sắc tight & integrated, không floating
     Fallback Lora (Google v2 also có VN subset, render OK nhưng acute hơi cao) */
  --font-serif:   'Source Serif 4', 'Source Serif 4 Fallback', 'Lora', Georgia, serif;
  --font-serif-heavy: 'Source Serif 4', 'Source Serif 4 Fallback', 'Fraunces', 'Lora', Georgia, serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

  /* ============ SPACING — 4px rhythm ============ */
  --space-unit: 4px;
  --space-0:  0;
  --space-1:  calc(var(--space-unit) * 1);    /* 4 */
  --space-2:  calc(var(--space-unit) * 2);    /* 8 */
  --space-3:  calc(var(--space-unit) * 3);    /* 12 */
  --space-4:  calc(var(--space-unit) * 4);    /* 16 */
  --space-5:  calc(var(--space-unit) * 5);    /* 20 */
  --space-6:  calc(var(--space-unit) * 6);    /* 24 */
  --space-8:  calc(var(--space-unit) * 8);    /* 32 */
  --space-10: calc(var(--space-unit) * 10);   /* 40 */
  --space-12: calc(var(--space-unit) * 12);   /* 48 */
  --space-16: calc(var(--space-unit) * 16);   /* 64 */
  --space-20: calc(var(--space-unit) * 20);   /* 80 */
  --space-24: calc(var(--space-unit) * 24);   /* 96 */
  --space-32: calc(var(--space-unit) * 32);   /* 128 */

  /* ============ RADIUS ============ */
  /* Legacy aliases (--r-*) — kept for backwards compat */
  --r-sm:   4px;
  --r-md:   8px;
  --r-lg:   12px;
  --r-xl:   16px;
  --r-2xl:  24px;
  --r-3xl:  32px;
  --r-full: 9999px;

  /* Canonical radius scale (--radius-*) */
  --radius-none: 0;
  --radius-xs:   4px;    /* badge, chip */
  --radius-sm:   6px;    /* input, small button */
  --radius-md:   8px;    /* default button, card */
  --radius-lg:   12px;   /* card, modal */
  --radius-xl:   16px;   /* hero card, sheet */
  --radius-2xl:  24px;   /* bottom sheet, large card */
  --radius-3xl:  32px;
  --radius-full: 9999px; /* pill, avatar */

  /* ============ BORDER WIDTH ============ */
  --border-0:    0;
  --border-1:    1px;    /* default */
  --border-2:    1.5px;  /* emphasized — input focus, selected */
  --border-3:    2px;    /* heavy — error state, active selection */
  --border-4:    3px;    /* indicator bars */

  /* ============ MOTION — v0.5 Iter 40A (2026-05-20) ============
     Motion system codified from:
       - Material 3 Motion (m3.material.io/styles/motion/easing-and-duration/tokens-specs)
       - Apple HIG Motion (developer.apple.com/design/human-interface-guidelines/motion)
       - Polaris Motion Tokens (polaris-react.shopify.com/tokens/motion)
       - IBM Carbon Motion (carbondesignsystem.com/elements/motion/overview)
       - Tailwind v4 ease utilities
       - web.dev prefers-reduced-motion guidance
       - WCAG 2.2 SC 2.3.3 Animation from Interactions
     Each token's choice has a research-backed reason (see motion/MOTION.md). */

  /* Legacy aliases (--dur-* / --ease-*) — kept for backwards compat */
  --dur-fast:    150ms;
  --dur-base:    250ms;
  --dur-slow:    400ms;

  /* ─── Duration scale (6-step Fibonacci-like progression) ───
     Closely matches Material 3 Short→Long progression but uses 5 active steps + 1 hero. */
  --duration-instant:    0ms;     /* no-animation snap (a11y reduced-motion fallback) */
  --duration-fast:       120ms;   /* micro feedback: hover, tap, button press */
  --duration-normal:     200ms;   /* default transition: color/bg/border swap, tooltip */
  --duration-slow:       320ms;   /* modal, drawer, sheet entry */
  --duration-slower:     480ms;   /* page transition, large surface change */
  --duration-deliberate: 800ms;   /* emphasized hero moment, onboarding, full route */

  /* ─── Easing curves ───
     Curated from M3 + Apple + Polaris. Each curve has 1 canonical use-case. */
  --ease-linear:       linear;                                    /* constant speed — spinners, progress bars */
  --ease-out:          cubic-bezier(0.16, 1, 0.3, 1);             /* M3 emphasized-decel — most exits (enter from off-screen, modal fade-in) */
  --ease-in:           cubic-bezier(0.7, 0, 0.84, 0);             /* M3 emphasized-accel — most entries (leaving viewport, modal fade-out) */
  --ease-in-out:       cubic-bezier(0.65, 0, 0.35, 1);            /* symmetric — accordion, tab switch */
  --ease-spring:       cubic-bezier(0.34, 1.56, 0.64, 1);         /* playful overshoot — success confirm, like/save tap */
  --ease-snap:         cubic-bezier(0.4, 0, 0.2, 1);              /* Material standard — utility default (color/bg swap) */
  --ease-emphasized:   cubic-bezier(0.2, 0, 0, 1);                /* M3 emphasized — hero, page, full-route */

  /* Backwards-compat aliases (deprecated — prefer canonical above) */
  --ease-out-soft:     var(--ease-snap);
  --ease-bounce:       cubic-bezier(0.68, -0.55, 0.265, 1.55);    /* legacy overshoot — use --ease-spring */

  /* ─── Displacement scale ───
     Translation distance for slide-in/out patterns. Matches spacing rhythm. */
  --motion-distance-sm: 4px;     /* tooltip nudge, icon shift */
  --motion-distance-md: 8px;     /* dropdown menu */
  --motion-distance-lg: 16px;    /* toast, drawer (mobile sheet) */
  --motion-distance-xl: 32px;    /* page transition, full hero */

  /* ─── Choreography tokens ───
     Pre-composed transition strings. Apply on the property you're animating.
     Pattern: `transition: var(--motion-fade-in);` */
  --motion-fade-in:    opacity var(--duration-normal) var(--ease-out);
  --motion-fade-out:   opacity var(--duration-fast) var(--ease-in);
  --motion-slide-up:   transform var(--duration-normal) var(--ease-out);
  --motion-slide-down: transform var(--duration-fast) var(--ease-in);
  --motion-scale-in:   transform var(--duration-normal) var(--ease-out);
  --motion-scale-out:  transform var(--duration-fast) var(--ease-in);
  --motion-blur-in:    filter var(--duration-slow) var(--ease-out);
  --motion-color:      color var(--duration-fast) var(--ease-snap);
  --motion-bg:         background-color var(--duration-fast) var(--ease-snap);
  --motion-shadow:     box-shadow var(--duration-normal) var(--ease-out);

  /* ─── Stagger delay ───
     Used for list-item entry animation (set per child via :nth-child(n) * var). */
  --motion-stagger-delay: 50ms;   /* 50ms between items — feels orchestrated not slow */

  /* Compound transitions — legacy, kept for back-compat. New code prefers --motion-* */
  --trans-color:    color var(--duration-fast) var(--ease-out);
  --trans-bg:       background-color var(--duration-fast) var(--ease-out);
  --trans-border:   border-color var(--duration-fast) var(--ease-out);
  --trans-all-fast: all var(--duration-fast) var(--ease-out);
  --trans-all-norm: all var(--duration-normal) var(--ease-out);

  /* ============ Z-INDEX ============ */
  --z-base:     0;
  --z-raised:   10;
  --z-dropdown: 30;
  --z-sticky:   40;
  --z-fixed:    50;
  --z-overlay:  60;
  --z-modal:    70;
  --z-toast:    80;
  --z-tooltip:  90;
}

/* === SEMANTIC === */
/* ============================================================
   Kry UI — SEMANTIC layer
   Role-based colors that compose foundation HSL primitives.
   Components use these (--bg, --primary) NOT raw HSL values.
   v0.4 — 2026-05-20
   ============================================================ */

@import url('./foundation.css');

:root {
  /* ============ PRIMARY (brand-driven) ============
     v0.4.1 (2026-05-20) — HSL math hardened against L ∈ [20%,70%], S ∈ [10%,90%].
       Previous unbounded calc() let primary-soft hit L=85% (invisible on warm-bg L=96%)
       and primary-on hardcoded white failed WCAG AA on light primaries (BetterBuy 2.9:1).
       Fix strategy:
         - clamp() lightness for soft/bg variants → ceiling 82% so chip vs warm-bg keeps ≥14% L delta
         - primary-on uses CSS relative color syntax → flips to dark text when primary L ≥ 50%
         - accent-deep caps S at 70% to prevent neon when L is also deep
       Backwards compat: brands with primary L ≤ 55% (annhien, khi, xanh, a-kryphan, haogood)
       compute identical values as before. Only L ≥ 60% brands (BetterBuy, AI Tools) clamp. */
  --primary:           hsl(var(--brand-primary-h) var(--brand-primary-s) var(--brand-primary-l));
  --primary-deep:      hsl(var(--brand-primary-h) var(--brand-primary-s) calc(var(--brand-primary-l) - 10%));
  --primary-hover:     hsl(var(--brand-primary-h) var(--brand-primary-s) calc(var(--brand-primary-l) - 5%));
  --primary-active:    hsl(var(--brand-primary-h) var(--brand-primary-s) calc(var(--brand-primary-l) - 15%));
  --primary-soft:      hsl(var(--brand-primary-h) var(--brand-primary-s) clamp(45%, calc(var(--brand-primary-l) + 25%), 82%));
  --primary-bg:        hsl(var(--brand-primary-h) var(--brand-primary-s) clamp(50%, calc(var(--brand-primary-l) + 30%), 85%) / 0.15);
  --primary-ring:      hsl(var(--brand-primary-h) var(--brand-primary-s) var(--brand-primary-l) / 0.3);
  /* --primary-on — text color on top of --primary fills.
     v0.4.2 (2026-05-20): replaced sign()-based auto-flip math (Chrome resolves CSS
     `sign()` inside hsl() calc to 0 → result hsl(0 0% 50%) grey → falls back to
     parent --text). Now default = white (works for any brand with primary L ≤ 50%).
     Brands with primary L > 50% MUST override --primary-on in their brand.css to
     dark text (e.g. hsl(0 0% 15%)). See brands/_template.brand.css. */
  --primary-on:        hsl(0 0% 100%);

  /* ============ ACCENT ============
     accent-deep clamps S ≤ 70% to prevent neon (AI Tools cyan 80% S on cream landing). */
  --accent:            hsl(var(--brand-accent-h) var(--brand-accent-s) var(--brand-accent-l));
  --accent-deep:       hsl(var(--brand-accent-h) min(var(--brand-accent-s), 70%) calc(var(--brand-accent-l) - 10%));
  --accent-soft:       hsl(var(--brand-accent-h) var(--brand-accent-s) clamp(45%, calc(var(--brand-accent-l) + 25%), 85%));

  --highlight:         hsl(var(--brand-highlight-h) var(--brand-highlight-s) var(--brand-highlight-l));
  --highlight-soft:    hsl(var(--brand-highlight-h) var(--brand-highlight-s) calc(var(--brand-highlight-l) + 15%));

  /* ============ STATUS ============
     v0.4.2 (2026-05-20): --*-soft alpha reduced 0.3 → 0.2 so text-on-soft (badge/helper)
     passes AA when foundation status-l is tight (27-44). Soft bg stays visually subtle. */
  --success:           hsl(var(--status-success-h) var(--status-success-s) var(--status-success-l));
  --success-soft:      hsl(var(--status-success-h) var(--status-success-s) calc(var(--status-success-l) + 40%) / 0.2);
  --success-on:        hsl(0 0% 100%);

  --danger:            hsl(var(--status-danger-h) var(--status-danger-s) var(--status-danger-l));
  --danger-soft:       hsl(var(--status-danger-h) var(--status-danger-s) calc(var(--status-danger-l) + 25%) / 0.2);
  --danger-on:         hsl(0 0% 100%);

  --warning:           hsl(var(--status-warning-h) var(--status-warning-s) var(--status-warning-l));
  --warning-soft:      hsl(var(--status-warning-h) var(--status-warning-s) calc(var(--status-warning-l) + 35%) / 0.2);

  --info:              hsl(var(--status-info-h) var(--status-info-s) var(--status-info-l));
  --info-soft:         hsl(var(--status-info-h) var(--status-info-s) calc(var(--status-info-l) + 30%) / 0.2);

  /* ============ WARM AESTHETIC SEMANTIC ============ */
  --warm-bg:           hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-bg-l));
  --warm-surface:      hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-surface-l));
  --warm-surface-2:    hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-surface2-l));
  --warm-border:       hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-border-l));
  --warm-rule:         hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-rule-l));

  --warm-text:         hsl(var(--neutral-h) var(--neutral-s) var(--warm-ink-l));
  --warm-text-2:       hsl(var(--neutral-h) var(--neutral-s) var(--warm-ink-2-l));
  --warm-text-3:       hsl(var(--neutral-h) var(--neutral-s) var(--warm-ink-3-l));

  /* ============ DARK AESTHETIC SEMANTIC ============ */
  --dark-bg:           hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-bg-l));
  --dark-surface:      hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-surface-l));
  --dark-surface-2:    hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-surface2-l));
  --dark-sidebar:      hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-sidebar-l));
  --dark-border:       hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-border-l));
  --dark-border-soft:  hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-border-soft-l));

  --dark-text:         hsl(var(--dark-text-h) var(--dark-text-s) var(--dark-text-l));
  --dark-text-2:       hsl(var(--dark-text-h) var(--dark-text-s) var(--dark-text-2-l));
  --dark-text-3:       hsl(var(--dark-text-h) var(--dark-text-s) var(--dark-text-3-l));

  --dark-violet:       hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l));
  --dark-violet-soft:  hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.15);
  --dark-cyan:         hsl(var(--dark-cyan-h) var(--dark-cyan-s) var(--dark-cyan-l));
  --dark-cyan-soft:    hsl(var(--dark-cyan-h) var(--dark-cyan-s) var(--dark-cyan-l) / 0.15);
  --dark-emerald:      hsl(var(--dark-emerald-h) var(--dark-emerald-s) var(--dark-emerald-l));
  --dark-emerald-soft: hsl(var(--dark-emerald-h) var(--dark-emerald-s) var(--dark-emerald-l) / 0.15);
  --dark-amber:        hsl(var(--dark-amber-h) var(--dark-amber-s) var(--dark-amber-l));
  --dark-amber-soft:   hsl(var(--dark-amber-h) var(--dark-amber-s) var(--dark-amber-l) / 0.15);
  --dark-danger:       hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l));
  --dark-danger-soft:  hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l) / 0.15);

  /* ============ SHADOW (warm = soft, dark = glow) ============ */
  --shadow-xs:  0 1px 2px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.04);
  --shadow-sm:  0 2px 4px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.05), 0 1px 2px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.04);
  --shadow-md:  0 4px 12px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.06), 0 2px 4px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.04);
  --shadow-lg:  0 8px 24px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.08), 0 4px 8px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.04);
  --shadow-xl:  0 16px 48px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.10), 0 6px 16px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.06);
  --shadow-2xl: 0 24px 64px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.14), 0 8px 24px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.08);

  --glow-primary:  0 0 0 1px var(--primary-ring), 0 6px 20px hsl(var(--brand-primary-h) var(--brand-primary-s) var(--brand-primary-l) / 0.3);
  --glow-violet:   0 0 0 1px hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.4), 0 6px 20px hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.3);
  --glow-emerald:  0 0 0 1px hsl(var(--dark-emerald-h) var(--dark-emerald-s) var(--dark-emerald-l) / 0.4), 0 6px 20px hsl(var(--dark-emerald-h) var(--dark-emerald-s) var(--dark-emerald-l) / 0.3);

  /* ============ ELEVATION SYSTEM ============ */
  /* Composed = subtle border + layered shadow for depth perception.
     Use case mapping:
       0 = flat content
       1 = list row hover, ghost button hover
       2 = card default, button raised
       3 = dropdown, popover, tooltip
       4 = modal, drawer
       5 = command palette, toast (highest) */
  --elevation-0: none;
  --elevation-1:
    0 1px 0 hsl(var(--neutral-h) var(--neutral-s) 20% / 0.04) inset,
    0 1px 2px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.05);
  --elevation-2:
    0 1px 0 hsl(var(--neutral-h) var(--neutral-s) 100% / 0.5) inset,
    0 2px 4px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.06),
    0 1px 2px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.04);
  --elevation-3:
    0 4px 12px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.08),
    0 2px 4px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.04);
  --elevation-4:
    0 12px 32px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.12),
    0 4px 8px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.06);
  --elevation-5:
    0 24px 64px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.16),
    0 8px 24px hsl(var(--neutral-h) var(--neutral-s) 20% / 0.08);
}

/* ============================================================
   AESTHETIC MODE — apply class to <body> or root container
   ============================================================ */

.aesthetic-warm {
  --bg:           var(--warm-bg);
  --surface:      var(--warm-surface);
  --surface-2:    var(--warm-surface-2);
  --border:       var(--warm-border);
  --rule:         var(--warm-rule);
  --text:         var(--warm-text);
  --text-2:       var(--warm-text-2);
  --text-3:       var(--warm-text-3);
  --text-on-primary: var(--primary-on);
  --shadow:       var(--shadow-md);
  --shadow-lg-alias: var(--shadow-lg);
  color: var(--text);
  background: var(--bg);
  /* color-scheme hint: tells UA to render form controls / scrollbar
     in light mode (matches warm cream surface). Iter 5 B (2026-05-20). */
  color-scheme: light;
}

.aesthetic-dark {
  --bg:           var(--dark-bg);
  --surface:      var(--dark-surface);
  --surface-2:    var(--dark-surface-2);
  --border:       var(--dark-border);
  --rule:         var(--dark-border);
  --text:         var(--dark-text);
  --text-2:       var(--dark-text-2);
  --text-3:       var(--dark-text-3);
  --text-on-primary: var(--primary-on);
  --shadow:       var(--shadow-md);
  --shadow-lg-alias: var(--shadow-lg);
  color: var(--text);
  background: var(--bg);
  /* color-scheme hint: tells UA to render form controls / scrollbar
     in dark mode (matches near-black surface). Iter 5 B (2026-05-20). */
  color-scheme: dark;
}

/* ============================================================
   KEYBOARD FOCUS — global :focus-visible (Iter 5 A, 2026-05-20)
   Every interactive must show a visible focus ring when reached via
   keyboard. We expose --focus-ring token so brand presets / dark mode
   can tune contrast. Default uses --primary at 0.6 alpha → readable on
   both warm cream + near-black dark surfaces.
   Rules:
     1. *:focus-visible           → 2px outline + 2px offset
     2. *:focus:not(:focus-visible) → no outline (kills sticky default on click)
     3. .skip-link                → hidden until focused (a11y best practice)
   ============================================================ */

:root {
  --focus-ring: hsl(var(--brand-primary-h) var(--brand-primary-s) var(--brand-primary-l) / 0.65);
  --focus-ring-offset: 2px;
  --focus-ring-width: 2px;
}

.aesthetic-dark {
  /* On dark surfaces, full-saturation primary may bloom. Bump alpha
     for crisper edge against near-black bg. */
  --focus-ring: hsl(var(--brand-primary-h) var(--brand-primary-s) calc(var(--brand-primary-l) + 15%) / 0.85);
}

:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-radius: 2px;
}

/* Kill default browser outline on mouse click but PRESERVE keyboard outline.
   Modern browsers handle this automatically — this is a hard backstop for
   legacy components that set `outline: none` then forgot to add a replacement. */
*:focus:not(:focus-visible) {
  outline: none;
}

/* Skip link — visually hidden until focused via Tab.
   Renders at top-left of viewport once focused. */
.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 9999;
  padding: 12px 20px;
  background: var(--primary);
  color: var(--primary-on);
  font-family: 'Inter', sans-serif;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 6px 0;
  transform: translateY(-110%);
  transition: transform 150ms ease;
}
.skip-link:focus,
.skip-link:focus-visible {
  transform: translateY(0);
  outline-offset: 2px;
}

/* ============================================================
   MESH UTILITIES — use everywhere
   ============================================================ */

/* Brand-relative mesh layers — gradients that follow brand-primary/accent/highlight
   hue instead of fixed coral palette. Fallback chain: accent → primary, highlight → primary.
   Use for editorial / deck backgrounds that must swap with brand. */
:root {
  --brand-mesh-1: radial-gradient(
    ellipse 60% 40% at 30% 20%,
    hsl(var(--brand-primary-h) var(--brand-primary-s) 70% / 0.12) 0%,
    transparent 60%
  );
  --brand-mesh-2: radial-gradient(
    ellipse 40% 60% at 80% 70%,
    hsl(var(--brand-accent-h, var(--brand-primary-h)) var(--brand-accent-s, 50%) 65% / 0.10) 0%,
    transparent 65%
  );
  --brand-mesh-3: radial-gradient(
    ellipse 50% 50% at 50% 90%,
    hsl(var(--brand-highlight-h, var(--brand-primary-h)) 60% 75% / 0.08) 0%,
    transparent 70%
  );
}

.mesh-warm {
  background-color: var(--warm-bg);
  background-image:
    radial-gradient(at 8% 12%,  hsl(var(--mesh-warm-1-h) 90% 78% / 0.55) 0px, transparent 50%),
    radial-gradient(at 88% 8%,  hsl(var(--mesh-warm-2-h) 70% 82% / 0.50) 0px, transparent 50%),
    radial-gradient(at 92% 72%, hsl(var(--mesh-warm-3-h) 85% 75% / 0.50) 0px, transparent 50%),
    radial-gradient(at 12% 88%, hsl(var(--mesh-warm-4-h) 30% 78% / 0.45) 0px, transparent 50%);
}

.mesh-warm-subtle {
  background-color: var(--warm-bg);
  background-image:
    radial-gradient(at 8% 12%,  hsl(var(--mesh-warm-1-h) 90% 78% / 0.25) 0px, transparent 50%),
    radial-gradient(at 92% 88%, hsl(var(--mesh-warm-3-h) 85% 75% / 0.25) 0px, transparent 50%);
}

.mesh-dark {
  background-color: var(--dark-bg);
  background-image:
    radial-gradient(at 15% 22%, hsl(var(--mesh-dark-1-h) 85% 55% / 0.32) 0px, transparent 50%),
    radial-gradient(at 78% 18%, hsl(var(--mesh-dark-2-h) 92% 55% / 0.22) 0px, transparent 50%),
    radial-gradient(at 88% 78%, hsl(var(--mesh-dark-3-h) 88% 50% / 0.18) 0px, transparent 50%),
    radial-gradient(at 20% 85%, hsl(var(--mesh-dark-4-h) 80% 45% / 0.22) 0px, transparent 50%);
}

.mesh-dark-subtle {
  background-color: var(--dark-bg);
  background-image:
    radial-gradient(at 15% 22%, hsl(var(--mesh-dark-1-h) 85% 55% / 0.15) 0px, transparent 50%),
    radial-gradient(at 85% 78%, hsl(var(--mesh-dark-3-h) 88% 50% / 0.10) 0px, transparent 50%);
}

.grid-lines-dark {
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
  background-size: 40px 40px;
}

.tab-num { font-variant-numeric: tabular-nums; }

/* ============================================================
   RESPONSIVE GUARD — mobile overflow fix (Iteration 3 P1, BUG-002)
   v0.4.1 — 2026-05-20
   Scope: viewport ≤ 480px ONLY. Desktop/tablet untouched.
   Strategy:
     PR1 — Body padding ramp: caps hardcoded `padding: 32px 24px` / `80px 24px`
           down to 16px on mobile (chrome eat ~64-160px → ~32px)
     PR2 — Card padding cap: caps `padding: var(--space-10)` (40px) cards
           down to var(--space-6) (24px) on mobile
     PR3 — Universal overflow-x clip + long-string break

   Audit ref: _screenshots/_mobile-overflow-AUDIT.md
   Note on !important: tokens layer loads before per-block styles, so
   without !important the per-block hardcoded padding wins. Audit
   explicitly accepted !important as scope-bounded by @media query.
   ============================================================ */

@media (max-width: 480px) {
  /* PR1 — body padding cap. Affects 18 blocks declaring `body { padding: 32px 24px }` or `padding: 80px 24px`. */
  body {
    padding-left: 16px !important;
    padding-right: 16px !important;
  }

  /* PR1.b — page wrap/container side padding cap (testimonials, footer, hero use wider .wrap) */
  .wrap,
  .container,
  .demo-wrap,
  .page-wrap {
    padding-left: max(0px, env(safe-area-inset-left)) !important;
    padding-right: max(0px, env(safe-area-inset-right)) !important;
    max-width: 100% !important;
  }

  /* PR2 — card padding cap. Affects 14 blocks using `.card { padding: var(--space-10) }` (40px). */
  .card,
  .panel-card,
  .stage {
    padding: var(--space-6) !important; /* 24px instead of 40px */
  }

  /* PR3.a — REMOVED (Iter4 B3, 2026-05-20):
     `overflow-x: clip` on body was MASKING real element overflow during
     scan-based audits (rect.right > 375 hidden from scrollWidth metric).
     Re-introduced false-pass states. Per-block fixes (min-width:0, padding
     caps, etc.) now own the responsibility of preventing element bleed.
     Keeping max-width on html only for safety. */
  html { max-width: 100vw; }

  /* PR3.b — long unbreakable strings (IDs, emails, codes) wrap on mobile. */
  pre, code, kbd, .mono, .kbd, .id, .email {
    overflow-wrap: anywhere;
    word-break: break-word;
  }
}

/* ============================================================
   REDUCED MOTION — respect prefers-reduced-motion: reduce
   Iter 5 B — 2026-05-20
   Short-circuits ALL CSS animations / transitions / smooth scroll
   for users with vestibular sensitivity or motion preference.
   Scope: universal selector so it cascades over per-block rules
   (animations live in 30+ block files, single override at tokens
   layer is the only sustainable approach).
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   FORCED COLORS — Windows High Contrast mode (Iter 10 I, 2026-05-20)
   When OS forces system colors (Windows High Contrast, Edge "use system
   colors"), browsers replace most colors with system tokens (CanvasText,
   Canvas, ButtonText, LinkText, etc.). Brand HSL math becomes invisible.
   Strategy:
     1. Map semantic tokens to system colors so components inherit correctly
     2. Force visible focus outline (CanvasText always contrasts Canvas)
     3. Ensure buttons keep border even if bg disappears (icon-only buttons
        would otherwise blend into Canvas)
     4. forced-color-adjust: auto is the default — we let UA override colors
        but lock structural decisions (border presence, outline width)
   Reference: MDN forced-colors, Microsoft Edge accessibility docs.
   ============================================================ */

@media (forced-colors: active) {
  :root {
    --primary:        CanvasText;
    --primary-on:     Canvas;
    --primary-hover:  CanvasText;
    --primary-active: CanvasText;
    --primary-soft:   Canvas;
    --primary-bg:     Canvas;
    --primary-ring:   CanvasText;
    --accent:         CanvasText;
    --accent-deep:    CanvasText;
    --accent-soft:    Canvas;
    --bg:             Canvas;
    --surface:        Canvas;
    --surface-2:      Canvas;
    --border:         CanvasText;
    --rule:           CanvasText;
    --text:           CanvasText;
    --text-2:         CanvasText;
    --text-3:         CanvasText;
    --focus-ring:     CanvasText;
  }

  /* Focus ring must always be visible — system color, no alpha. */
  :focus-visible {
    outline: 2px solid CanvasText !important;
    outline-offset: 2px !important;
  }

  /* Buttons get visible border so icon-only / ghost variants don't vanish
     into Canvas. ButtonText is system token that always contrasts ButtonFace. */
  button,
  .button,
  .btn,
  [role="button"],
  input[type="button"],
  input[type="submit"],
  input[type="reset"] {
    border: 1px solid ButtonText !important;
  }

  /* Links use LinkText system color for proper visited/active state. */
  a {
    color: LinkText;
  }
  a:visited {
    color: VisitedText;
  }
}

/* ============================================================
   REDUCED DATA — prefers-reduced-data: reduce (Iter 10 I, 2026-05-20)
   User opted into data-saver (Chrome Lite mode, Edge efficiency mode,
   slow-connection auto-detect). Skip decorative gradients + non-critical
   imagery to save bandwidth + render time. Content stays intact.
   Scope: only `[class*="gradient"]`, `.hero-gradient`, `.blur-bg`, mesh
   utilities, and `[data-decorative]` images. Real content NOT affected.
   ============================================================ */

@media (prefers-reduced-data: reduce) {
  /* Skip decorative gradient backgrounds — collapse to flat surface. */
  .hero-gradient,
  .blur-bg,
  [class*="gradient-bg"],
  .mesh-warm,
  .mesh-warm-subtle,
  .mesh-dark,
  .mesh-dark-subtle,
  .grid-lines-dark {
    background-image: none !important;
  }

  /* Hide decorative images explicitly marked. */
  img[data-decorative="true"],
  .decorative-img,
  .hero-img-decorative {
    display: none !important;
  }

  /* Disable expensive filters that force GPU compositing. */
  [class*="blur"],
  .glass,
  .frosted {
    backdrop-filter: none !important;
    filter: none !important;
  }
}

/* ============================================================
   REDUCED TRANSPARENCY — prefers-reduced-transparency: reduce
   Iter 10 I, 2026-05-20
   macOS "Reduce transparency" + iOS / Windows equivalent. User finds
   blur / translucency disorienting or hard to read. Strategy:
     1. Disable backdrop-filter blur globally
     2. Replace translucent surfaces with solid --surface
     3. Bump alpha to 1.0 on rgba/hsla overlay layers via opacity reset
   Scope: opt-in via class hooks (`.glass`, `.frosted`, `[class*="blur"]`).
   Brand mesh gradients stay since they don't use transparency for legibility.
   ============================================================ */

@media (prefers-reduced-transparency: reduce) {
  [class*="blur"],
  .glass,
  .frosted,
  .glassmorphism,
  .backdrop-blur,
  [style*="backdrop-filter"] {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: var(--surface) !important;
    opacity: 1 !important;
  }

  /* Modal/dialog overlays — keep dim but remove blur. */
  .modal-overlay,
  .dialog-overlay,
  [role="dialog"]::backdrop {
    backdrop-filter: none !important;
    background: hsl(var(--neutral-h) var(--neutral-s) 10% / 0.7) !important;
  }
}

/* ============================================================
   LEGACY ALIASES — backwards compat (Iter 13 P, 2026-05-20)
   Discovered Iter 12 O audit: 148 undefined var refs.
   Strategy A: declare aliases here instead of mass-renaming HTML.
   Use canonical names in NEW code:
     --text / --text-2 / --text-3   (NOT --ink-*)
     --primary / --accent / --highlight  (NOT --coral / --sage / --amber)
     --bg / --surface              (NOT --cream-base / --cream-paper)
   ============================================================ */
:root {
  /* --ink-* → --text-* (36 + 14 + 14 = 64 refs in page-D-editorial) */
  --ink-primary:   var(--text);
  --ink-secondary: var(--text-2);
  --ink-tertiary:  var(--text-3);
  --ink-muted:     var(--text-3);

  /* Editorial palette legacy (13 + 4 + 2 refs in page-D-editorial.html) */
  --coral:       hsl(12 70% 55%);
  --sage:        hsl(140 25% 50%);
  --amber:       hsl(38 60% 60%);
  --cream-base:  hsl(40 30% 96%);
  --cream-paper: hsl(40 30% 92%);

  /* Spacing alias — --space-7 falls between --space-6 (24px) and --space-8 (32px) */
  --space-7: 28px;
}

/* ============================================================
   PRINT STYLESHEET
   Reset dark/colored backgrounds to white, hide nav/interactive
   chrome, expand <details>, show link URLs, avoid breaking cards.
   Iter 12 N — 2026-05-20
   ============================================================ */
@media print {
  /* Reset background dark/colored → white for ink savings + legibility */
  :root,
  body,
  body.aesthetic-warm,
  body.aesthetic-dark {
    --bg: white !important;
    --surface: white !important;
    --surface-2: white !important;
    --text: black !important;
    --text-2: #333 !important;
    --text-3: #666 !important;
    --border: #ccc !important;
    background: white !important;
    color: black !important;
  }

  /* Hide navigation / interactive chrome — printed page doesn't need it */
  nav,
  .nav,
  .navbar,
  .topbar,
  .sidebar,
  .tab-bar,
  .floating,
  .sticky-bottom,
  button.icon-only,
  .skip-link,
  .toggle,
  .switcher,
  [role="tablist"],
  [aria-hidden="true"] {
    display: none !important;
  }

  /* Expand all <details> for printing — user shouldn't lose hidden content */
  details {
    display: block !important;
  }
  details > *:not(summary) {
    display: block !important;
  }
  details[open] > *:not(summary),
  details > summary ~ * {
    display: block !important;
  }

  /* Show link URL after anchor text for external links */
  a[href^="http"]::after,
  a[href^="https"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    color: #555;
    word-break: break-all;
  }
  /* Skip URL print for in-page anchors and mailto/tel links */
  a[href^="#"]::after,
  a[href^="mailto:"]::after,
  a[href^="tel:"]::after {
    content: "" !important;
  }

  /* Avoid page break inside cards / sections / figures */
  .card,
  .kpi-card,
  section,
  article,
  figure,
  blockquote,
  pre,
  table {
    break-inside: avoid;
    page-break-inside: avoid;
  }

  /* Headings shouldn't be orphaned at page bottom */
  h1, h2, h3, h4, h5, h6 {
    break-after: avoid;
    page-break-after: avoid;
  }

  /* Force black text on color-tinted elements for print clarity */
  .eyebrow,
  .primary,
  .text-primary,
  .text-accent,
  [class*="text-violet"],
  [class*="text-cyan"],
  [class*="text-emerald"] {
    color: black !important;
  }

  /* Hide visual decoration — gradients/meshes/blurs don't print well */
  .mesh-warm,
  .mesh-dark,
  [class*="gradient"],
  .blur-bg,
  [class*="backdrop-blur"] {
    background-image: none !important;
    backdrop-filter: none !important;
  }

  /* Page margin — 1cm gives breathing room on A4 */
  @page {
    margin: 1cm;
  }
}

/* ============================================================
   REDUCED MOTION — WCAG 2.2 SC 2.3.3 Animation from Interactions
   Respects user OS-level setting; replaces transitions with
   instant snaps and disables non-essential animation. Iter 40A.

   Source: web.dev/articles/prefers-reduced-motion
           w3.org/WAI/WCAG22/Understanding/animation-from-interactions

   Escape hatch: add `.motion-essential` class to elements where
   the animation conveys meaning (e.g. loading spinner, progress
   bar, content-loaded transition). These are exempt per WCAG —
   "unless the animation is essential to the functionality".
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Restore EXPLICIT essential transitions only when marked via class.
     Example: `<div class="spinner motion-essential">` preserves rotation. */
  .motion-essential,
  .motion-essential *,
  .motion-essential *::before,
  .motion-essential *::after {
    animation-duration: revert !important;
    animation-iteration-count: revert !important;
    transition-duration: revert !important;
  }
}

/* === BRAND DEFAULT === */
/* ============================================================
   Kry UI — DEFAULT BRAND preset (FALLBACK only)
   ------------------------------------------------------------
   Role: "unbranded fallback" — used by archetype starter pages
   (pages/page-A..F, starter/archetypes/*) that ship WITHOUT a
   committed brand. Coral warm, a11y-tuned (L=48% so white-on-fill
   passes WCAG AA 4.73:1).

   ⚠️  PRODUCTION code should NOT link this file. Use the canonical
       per-brand preset:
           <link rel="stylesheet" href="brands/<slug>.brand.css">
       (annhien | khi | betterbuy | xanh | a-kryphan | haogood | ai-tools)

   Canonical brand registry: ADR-004 (DESIGN-DECISIONS.md).
   Disambiguation model:     ADR-011 (DESIGN-DECISIONS.md).

   v0.5.1 — 2026-05-20 (Iter 15 T — F3 blocker resolved)
   ============================================================ */

:root {
  /* PRIMARY — brand "main" color (button fill, link, accent)
     v0.4.2 (2026-05-20): L darkened 60→48% so white text on coral fill passes WCAG AA
     (was 3.21:1 → now 4.73:1). Affects landing pages using brand-default (page-C-landing,
     templates/, starter/, _previews/, atoms/molecules/organisms/index). Coral hue & saturation
     preserved — visual: slightly deeper coral, still warm friendly. */
  --brand-primary-h: 12;    /* 0-360 — coral */
  --brand-primary-s: 50%;
  --brand-primary-l: 48%;

  /* ACCENT — secondary, used sparingly */
  --brand-accent-h: 95;     /* sage */
  --brand-accent-s: 18%;
  --brand-accent-l: 39%;

  /* HIGHLIGHT — warm touches (amber, gold) */
  --brand-highlight-h: 38;
  --brand-highlight-s: 50%;
  --brand-highlight-l: 65%;
}

/* ============================================================
   BRAND PRESET REFERENCE — copy this comment khi tạo brand mới
   ============================================================
   Brand presets em đề xuất (anh confirm hue trước khi build):

   An Nhien (nâu trầm hương)     primary-h: 28, s: 40%, l: 38%
   KHI Wellness (sage chữa lành)  primary-h: 140, s: 25%, l: 38%
   BetterBuy (coral DTC)          primary-h: 12, s: 50%, l: 60% (= default)
   Xanh Marketing (xanh lá)       primary-h: 142, s: 45%, l: 45%
   A-Kryphan (charcoal calm)      primary-h: 220, s: 15%, l: 30%
   HaoGood NZL (deep navy)        primary-h: 220, s: 55%, l: 35%
   AI Tools (violet tech)         primary-h: 252, s: 85%, l: 60%

   Mỗi brand chỉ cần override 3-9 dòng — toàn bộ palette tự shift.
   ============================================================ */
    html, body { font-family: 'Inter', sans-serif; -webkit-font-smoothing: antialiased; }
    .serif-italic { font-family: 'Lora', serif; font-style: italic; }
    .jakarta { font-family: 'Plus Jakarta Sans', sans-serif; }
    .tighter { letter-spacing: -0.04em; }
    .tightest { letter-spacing: -0.055em; }

    /* Semantic warm utility aliases — mapped to tokens */
    .bg-cream { background-color: var(--warm-bg); }
    .bg-cream-2 { background-color: var(--warm-surface); }

    .text-ink { color: var(--warm-text); }
    .text-ink-2 { color: var(--warm-text-2); }
    .text-ink-3 { color: var(--warm-text-3); }
    .text-coral { color: var(--primary-deep); }
    .text-sage { color: var(--accent); }
    .text-sage-light { color: var(--accent-deep); }
    .text-amber-warm { color: var(--highlight); }

    .bg-coral { background-color: var(--primary); }
    .bg-coral-soft { background-color: var(--primary-soft); }
    .bg-sage { background-color: var(--accent); }
    .bg-sage-light { background-color: var(--accent-deep); }
    .bg-amber-warm { background-color: var(--highlight); }
    .bg-rose-blush { background-color: var(--primary-soft); }

    .border-warm { border-color: var(--warm-border); }
    .border-coral-soft { border-color: var(--primary-soft); }

    /* mesh-warm + mesh-warm-subtle are defined in semantic.css already.
       Page-specific extra: a more saturated coral-leaning mesh for CTA closing. */
    .mesh-warm-soft {
      background-color: var(--warm-bg);
      background-image:
        radial-gradient(at 20% 30%, hsl(var(--mesh-warm-1-h) 85% 80% / 0.35) 0px, transparent 50%),
        radial-gradient(at 78% 60%, hsl(var(--mesh-warm-4-h) 30% 78% / 0.30) 0px, transparent 50%),
        radial-gradient(at 50% 90%, hsl(var(--mesh-warm-2-h) 60% 82% / 0.25) 0px, transparent 50%);
    }
    .mesh-coral {
      background-color: var(--warm-bg);
      background-image:
        radial-gradient(ellipse at 30% 30%, hsl(var(--brand-primary-h) 85% 75% / 0.50) 0px, transparent 60%),
        radial-gradient(ellipse at 70% 70%, hsl(var(--mesh-warm-2-h) 65% 82% / 0.40) 0px, transparent 60%),
        radial-gradient(ellipse at 50% 50%, hsl(var(--mesh-warm-3-h) 85% 78% / 0.30) 0px, transparent 65%);
    }

    .glass-warm {
      background: hsl(var(--warm-bg-h) var(--warm-bg-s) 99% / 0.6);
      backdrop-filter: blur(18px) saturate(160%);
      -webkit-backdrop-filter: blur(18px) saturate(160%);
      border: 1px solid rgba(255, 255, 255, 0.7);
    }
    .glass-warmer {
      background: hsl(var(--warm-bg-h) var(--warm-bg-s) 98% / 0.78);
      backdrop-filter: blur(20px) saturate(180%);
      -webkit-backdrop-filter: blur(20px) saturate(180%);
      border: 1px solid rgba(255, 255, 255, 0.8);
    }

    .nav-glass {
      background: hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-bg-l) / 0.72);
      backdrop-filter: blur(18px) saturate(160%);
      -webkit-backdrop-filter: blur(18px) saturate(160%);
      border-bottom: 1px solid hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-border-l) / 0.5);
    }

    .shadow-warm {
      box-shadow: 0 1px 2px hsl(var(--neutral-h) var(--neutral-s) 15% / 0.04),
                  0 8px 24px hsl(var(--brand-primary-h) 50% 40% / 0.08),
                  0 24px 64px hsl(var(--brand-primary-h) 50% 40% / 0.06);
    }
    .shadow-soft {
      box-shadow: 0 4px 16px hsl(var(--brand-primary-h) 50% 40% / 0.08);
    }
    .shadow-coral-glow {
      box-shadow: 0 8px 28px hsl(var(--brand-primary-h) var(--brand-primary-s) var(--brand-primary-l) / 0.22),
                  0 2px 6px hsl(var(--brand-primary-h) var(--brand-primary-s) var(--brand-primary-l) / 0.12);
    }

    .blob-cup {
      background: radial-gradient(circle at 35% 30%,
        hsl(18 100% 89%) 0%,
        var(--primary-soft) 45%,
        var(--primary) 100%);
      border-radius: 62% 38% 55% 45% / 50% 60% 40% 50%;
    }
    .blob-steam {
      background: radial-gradient(ellipse at center, rgba(255,255,255,0.7) 0%, rgba(255,255,255,0) 70%);
      filter: blur(8px);
    }

    .connector-line {
      background-image: linear-gradient(to right, var(--highlight) 50%, transparent 0%);
      background-size: 12px 2px;
      background-repeat: repeat-x;
      background-position: center;
    }

    details > summary { list-style: none; }
    details > summary::-webkit-details-marker { display: none; }
    details[open] .faq-chev { transform: rotate(45deg); }
    .faq-chev { transition: transform 0.25s ease; }

/* === Page-A dashboard dark utilities === */
    html, body { font-family: 'Inter', 'Inter Fallback', sans-serif; -webkit-font-smoothing: antialiased; }
    .serif { font-family: 'Lora', 'Lora Fallback', serif; }
    .mono { font-family: 'IBM Plex Mono', monospace; }
    .tighter { letter-spacing: -0.035em; }
    .tightest { letter-spacing: -0.05em; }

    /* Surface helpers — composed from semantic vars */
    .surface { background-color: var(--dark-surface); border: 1px solid var(--dark-border); }
    .surface2 { background-color: var(--dark-surface-2); border: 1px solid var(--dark-border); }

    .glass-card {
      background: hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-surface-l) / 0.7);
      backdrop-filter: blur(20px) saturate(140%);
      -webkit-backdrop-filter: blur(20px) saturate(140%);
      border: 1px solid rgba(255, 255, 255, 0.06);
    }

    .ring-violet {
      box-shadow:
        0 0 0 1px hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.25),
        0 8px 30px -10px hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.25);
    }

    .grid-lines-soft {
      background-image:
        linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
      background-size: 48px 48px;
    }

    .kbd {
      font-family: 'IBM Plex Mono', monospace;
      font-size: 12px;
      padding: 2px 6px;
      border-radius: 4px;
      background: rgba(255,255,255,0.05);
      border: 1px solid rgba(255,255,255,0.08);
      color: var(--dark-text-2);
    }

    .badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px; font-size: 12px; font-family: 'IBM Plex Mono', monospace; }
    .badge-violet { background: hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.15); color: hsl(var(--dark-violet-h) var(--dark-violet-s) 82%); border: 1px solid hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.30); }
    .badge-cyan { background: hsl(var(--dark-cyan-h) var(--dark-cyan-s) var(--dark-cyan-l) / 0.12); color: hsl(var(--dark-cyan-h) var(--dark-cyan-s) 75%); border: 1px solid hsl(var(--dark-cyan-h) var(--dark-cyan-s) var(--dark-cyan-l) / 0.30); }
    .badge-emerald { background: hsl(var(--dark-emerald-h) var(--dark-emerald-s) var(--dark-emerald-l) / 0.14); color: hsl(var(--dark-emerald-h) var(--dark-emerald-s) 70%); border: 1px solid hsl(var(--dark-emerald-h) var(--dark-emerald-s) var(--dark-emerald-l) / 0.32); }
    .badge-danger { background: hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l) / 0.14); color: hsl(var(--dark-danger-h) var(--dark-danger-s) 78%); border: 1px solid hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l) / 0.32); }
    .badge-warning { background: hsl(var(--dark-amber-h) var(--dark-amber-s) var(--dark-amber-l) / 0.14); color: hsl(var(--dark-amber-h) var(--dark-amber-s) 70%); border: 1px solid hsl(var(--dark-amber-h) var(--dark-amber-s) var(--dark-amber-l) / 0.32); }
    .badge-neutral { background: rgba(255,255,255,0.04); color: var(--dark-text-2); border: 1px solid var(--dark-border); }

    /* Heatmap cell helper — opacity scale */
    .cell { border-radius: 4px; }

/* === Page-B-tool utilities === */
    /* v0.4.2: Tailwind prebuilt has .text-danger → var(--danger) hardcoded — re-map for dark UI.
       Use brighter custom danger (L=80) so it passes AA even when .opacity-70 ancestor blends
       effective color toward bg (CSS opacity inheritance can't be undone by descendants). */
    .text-danger { color: hsl(var(--dark-danger-h) var(--dark-danger-s) 80%) !important; }
    .border-danger\/40 { border-color: hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l) / 0.45) !important; }
    .border-danger\/30 { border-color: hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l) / 0.40) !important; }
    .bg-danger\/10 { background-color: hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l) / 0.16) !important; }
    .bg-danger\/15 { background-color: hsl(var(--dark-danger-h) var(--dark-danger-s) var(--dark-danger-l) / 0.20) !important; }
    .bg-danger { background-color: var(--dark-danger) !important; }

    html, body { font-family: 'Inter', sans-serif; -webkit-font-smoothing: antialiased; }
    .mono { font-family: 'IBM Plex Mono', monospace; }
    .tight2 { letter-spacing: -0.02em; }
    .tight3 { letter-spacing: -0.03em; }

    .scroll-zone::-webkit-scrollbar { width: 8px; height: 8px; }
    .scroll-zone::-webkit-scrollbar-track { background: transparent; }
    .scroll-zone::-webkit-scrollbar-thumb { background: hsl(var(--dark-bg-h) var(--dark-bg-s) var(--dark-border-soft-l)); border-radius: 4px; }
    .scroll-zone::-webkit-scrollbar-thumb:hover { background: var(--dark-border); }

    .glow-violet-soft {
      box-shadow:
        0 0 0 1px hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.4),
        0 6px 20px -6px hsl(var(--dark-violet-h) var(--dark-violet-s) var(--dark-violet-l) / 0.5);
    }

    .row-hover:hover { background-color: hsl(var(--dark-bg-h) var(--dark-bg-s) 10%); }
    .row-selected {
      background-color: hsl(var(--dark-violet-h) 30% 12%);
      box-shadow: inset 2px 0 0 0 var(--dark-violet);
    }

    .kbd {
      background-color: var(--dark-surface-2);
      border: 1px solid var(--dark-border);
      border-bottom-width: 2px;
      padding: 1px 5px;
      border-radius: 4px;
      font-family: 'IBM Plex Mono', monospace;
      font-size: 11px;
      color: var(--dark-text-2);
      line-height: 1;
    }

    .chip {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      padding: 2px 7px;
      border-radius: 4px;
      font-size: 11px;
      line-height: 1;
      height: 20px;
      font-family: 'IBM Plex Mono', monospace;
      letter-spacing: 0.02em;
      border: 1px solid;
    }

    .focus-ring:focus-within {
      box-shadow: 0 0 0 1px var(--dark-violet);
      border-color: var(--dark-violet);
    }

    .avatar-init {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 24px;
      height: 24px;
      border-radius: 999px;
      font-size: 10px;
      font-weight: 600;
      color: var(--dark-bg);
      letter-spacing: 0;
    }

    /* Mobile fallback — hide flanking sidebars, main content only.
       Two sidebars (256px + 384px) + main = 640px+, unusable < 720px viewport. */
    @media (max-width: 720px) {
      /* Override semantic.css body padding — this is a full-bleed tool layout */
      body { padding: 0 !important; }
      /* Hide BOTH left nav aside AND right detail aside */
      aside { display: none !important; }
      body > div.flex > main { width: 100% !important; }
      /* Top header has 3 sections (breadcrumb + view tabs + actions) — collapse on mobile */
      body > div.flex > div > header { gap: 6px !important; padding-left: 10px !important; padding-right: 10px !important; }
      body > div.flex > div > header > div { min-width: 0 !important; }
      /* Trim breadcrumb — hide "Active sprints" label + chevron, keep sprint title */
      body > div.flex > div > header > div:first-child > svg:nth-of-type(1),
      body > div.flex > div > header > div:first-child > span:nth-of-type(1),
      body > div.flex > div > header > div:first-child > svg:nth-of-type(2) { display: none !important; }
      body > div.flex > div > header > div:first-child > span:nth-of-type(2) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 120px; }
      /* Hide view-toggle group (Board/List/Timeline/Roadmap) — secondary nav, available via menu */
      body > div.flex > div > header > div.flex-1 { display: none !important; }
      /* Tighten action buttons; hide Filter/Sort text labels, keep icons; New issue keeps full text */
      body > div.flex > div > header > div:last-child > button { padding-left: 8px !important; padding-right: 8px !important; }
      body > div.flex > div > header > div:last-child .btn-label { display: none !important; }

      /* Iter4 B3 fix — row content fits 375 viewport:
         row = checkbox + status-dot + PUL-ID + title + chip1 (type) + chip2 (project) + avatar + date.
         At 375px, content overflows (right=414). Strategy:
         - Hide secondary chip (`.chip ~ .chip` = 2nd .chip onwards): project tag goes away
         - Hide avatar — assignment shown on detail open
         - Trim PUL-ID width (w-16=64px → w-12=48px)
         - Hide trailing date span (mono w-14) — focus is title + type chip */
      main .divide-y > div > .chip ~ .chip { display: none !important; }
      main .divide-y > div > .avatar-init { display: none !important; }
      main .divide-y > div > .mono.w-16 { width: 48px !important; font-size: 10px !important; }
      main .divide-y > div > .mono.w-14 { display: none !important; }
      /* Row padding shrink + force overflow constraint so .truncate ellipsis renders */
      main .divide-y > div { padding-left: 12px !important; padding-right: 12px !important; gap: 8px !important; overflow: hidden !important; min-width: 0 !important; }
      main .divide-y > div > span.flex-1 { min-width: 0 !important; }
    }

    /* Iter28 — B Tool 375 mobile truncate FIX
       Iter26 hide chips/avatar/date worked, but title still hard-cut (no ellipsis).
       Root cause: row's flex parent doesn't constrain width → row extends past 375vw,
       title's `flex-1 truncate` computes width from intrinsic content, not viewport.
       Fix: aggressive @media (max-width: 600px) — force max-width on row + container,
       hide ALL chips (was: only 2nd onwards) for max title breathing room,
       explicit flex-basis:0 + overflow:hidden + text-overflow:ellipsis on title. */
    @media (max-width: 600px) {
      /* Constrain outer flex container to viewport — prevent overflow propagation */
      html, body { max-width: 100vw !important; overflow-x: hidden !important; }
      body > div.flex { max-width: 100vw !important; width: 100vw !important; overflow-x: hidden !important; }
      body > div.flex > div.flex-1 { max-width: 100vw !important; width: 100vw !important; min-width: 0 !important; overflow-x: hidden !important; }
      main { max-width: 100vw !important; width: 100% !important; min-width: 0 !important; overflow-x: hidden !important; }
      /* Constrain group container (parent of .divide-y) */
      main > div { max-width: 100% !important; min-width: 0 !important; }
      main .divide-y { max-width: 100% !important; min-width: 0 !important; overflow: hidden !important; }
      /* Force every row to fit viewport exactly with hard pixel cap */
      main .divide-y > div.row-selected,
      main .divide-y > div.row-hover {
        max-width: 100% !important;
        width: 100% !important;
        min-width: 0 !important;
        overflow: hidden !important;
        box-sizing: border-box !important;
      }
      /* Hide ALL chips at 375 — content pressure too high */
      main .divide-y > div.row-selected > .chip,
      main .divide-y > div.row-hover > .chip { display: none !important; }
      /* Title span — HARD pixel max-width to force ellipsis trigger
         viewport 375 − checkbox 16 − status dot 12 − PUL-ID 48 − padding 24 − gaps 32 ≈ 243px
         Set 220 to be safe; ellipsis triggers when content > span's own width */
      main .divide-y > div.row-selected > span.flex-1.truncate,
      main .divide-y > div.row-hover > span.flex-1.truncate {
        min-width: 0 !important;
        max-width: 220px !important;
        flex: 0 1 220px !important;
        overflow: hidden !important;
        text-overflow: ellipsis !important;
        white-space: nowrap !important;
        display: inline-block !important;
      }
    }

/* === Page-D-editorial utilities === */
    /* Page-local aliases — derive from semantic tokens so brand preset shifts everything */
    :root {
      --cream-base: var(--warm-bg);
      --cream-paper: var(--warm-surface);
      --ink-primary: var(--warm-text);
      --ink-secondary: var(--warm-text-2);
      --ink-muted: var(--warm-text-3);
      --coral: var(--primary-deep);
      --sage: var(--accent-deep);
      --amber: var(--highlight);
      --rule: var(--warm-rule);
    }

    html, body {
      font-family: 'Inter', sans-serif;
      -webkit-font-smoothing: antialiased;
      color: var(--ink-primary);
      background-color: var(--cream-base);
    }

    .serif {
      font-family: 'Fraunces', serif;
      font-optical-sizing: auto;
    }
    .serif-italic {
      font-family: 'Fraunces', serif;
      font-style: italic;
      font-optical-sizing: auto;
    }
    .instrument {
      font-family: 'Lora', serif;
      font-style: italic;
    }

    .bg-cream { background-color: var(--cream-base); }
    .bg-paper { background-color: var(--cream-paper); }

    .text-ink { color: var(--ink-primary); }
    .text-ink-secondary { color: var(--ink-secondary); }
    .text-ink-muted { color: var(--ink-muted); }
    .text-coral { color: var(--coral); }
    .text-sage { color: var(--sage); }

    .bg-coral { background-color: var(--coral); }
    .bg-sage { background-color: var(--sage); }
    .bg-amber { background-color: var(--amber); }

    .border-rule { border-color: var(--rule); }
    .bg-rule { background-color: var(--rule); }

    /* Article body — generous reading */
    .article-body {
      font-family: 'Fraunces', serif;
      font-optical-sizing: auto;
      font-weight: 400;
      font-size: 1.1875rem; /* 19px */
      line-height: 1.75;
      color: var(--ink-primary);
      letter-spacing: -0.005em;
    }
    .article-body p {
      margin-bottom: 1.5rem;
    }
    .article-body p + p {
      margin-top: 0;
    }

    /* Drop cap */
    .drop-cap::first-letter {
      font-family: 'Fraunces', serif;
      font-weight: 600;
      font-style: normal;
      float: left;
      font-size: 5.5rem;
      line-height: 0.85;
      padding-top: 0.45rem;
      padding-right: 0.85rem;
      padding-bottom: 0;
      color: var(--ink-primary);
    }

    /* Pull quote */
    .pull-quote {
      font-family: 'Fraunces', serif;
      font-style: italic;
      font-weight: 400;
      font-size: clamp(2rem, 4vw, 2.75rem);
      line-height: 1.25;
      color: var(--ink-primary);
      text-align: center;
      letter-spacing: -0.015em;
    }

    /* Brand-relative gradient image placeholders — follow brand hue tokens.
       Primary = warm anchor; accent = secondary anchor; highlight = tertiary. */
    .img-hero {
      background:
        radial-gradient(ellipse at 22% 28%, hsl(var(--brand-primary-h) 85% 83% / 0.95) 0%, transparent 55%),
        radial-gradient(ellipse at 78% 18%, hsl(var(--brand-primary-h) 78% 76% / 0.90) 0%, transparent 55%),
        radial-gradient(ellipse at 65% 75%, hsl(var(--brand-highlight-h, var(--brand-primary-h)) 55% 67% / 0.85) 0%, transparent 60%),
        radial-gradient(ellipse at 15% 80%, hsl(var(--brand-primary-h) 60% 80% / 0.75) 0%, transparent 55%),
        linear-gradient(135deg,
          hsl(var(--brand-primary-h) 80% 81%) 0%,
          hsl(var(--brand-primary-h) 72% 75%) 45%,
          hsl(var(--brand-primary-h) 50% 67%) 100%);
    }
    .img-inline {
      background:
        radial-gradient(ellipse at 30% 30%, hsl(var(--brand-accent-h, var(--brand-primary-h)) 30% 82% / 0.90) 0%, transparent 55%),
        radial-gradient(ellipse at 75% 70%, hsl(var(--brand-highlight-h, var(--brand-primary-h)) 55% 88% / 0.95) 0%, transparent 60%),
        radial-gradient(ellipse at 50% 50%, hsl(var(--brand-accent-h, var(--brand-primary-h)) 22% 80% / 0.70) 0%, transparent 70%),
        linear-gradient(135deg,
          hsl(var(--brand-accent-h, var(--brand-primary-h)) 28% 86%) 0%,
          hsl(var(--brand-highlight-h, var(--brand-primary-h)) 50% 90%) 50%,
          hsl(var(--brand-highlight-h, var(--brand-primary-h)) 45% 81%) 100%);
    }
    .img-related-1 {
      background: linear-gradient(135deg,
        hsl(var(--brand-primary-h) 80% 81%) 0%,
        hsl(var(--brand-primary-h) 50% 67%) 100%);
    }
    .img-related-2 {
      background: linear-gradient(135deg,
        hsl(var(--brand-accent-h, var(--brand-primary-h)) 28% 86%) 0%,
        hsl(var(--brand-accent-h, var(--brand-primary-h)) 22% 72%) 100%);
    }
    .img-related-3 {
      background: linear-gradient(135deg,
        hsl(var(--brand-highlight-h, var(--brand-primary-h)) 50% 90%) 0%,
        hsl(var(--brand-highlight-h, var(--brand-primary-h)) 55% 64%) 100%);
    }
    .img-author {
      background: linear-gradient(135deg,
        hsl(var(--brand-primary-h) 80% 81%) 0%,
        hsl(var(--brand-primary-h) 60% 51%) 100%);
    }

    /* Tag uppercase */
    .tag {
      font-family: 'Inter', sans-serif;
      font-weight: 500;
      text-transform: uppercase;
      letter-spacing: 0.18em;
      font-size: 0.75rem; /* 12px — WCAG floor */
      color: var(--coral);
    }

    .meta {
      font-family: 'Inter', sans-serif;
      font-weight: 400;
      font-size: 0.875rem; /* 14px */
      color: var(--ink-muted);
    }

    .caption {
      font-family: 'Fraunces', serif;
      font-style: italic;
      font-weight: 300;
      font-size: 0.875rem; /* 14px */
      color: var(--ink-muted);
      word-break: break-word;
      overflow-wrap: anywhere;
      max-width: 100%;
    }

    /* H2 in article */
    .article-h2 {
      font-family: 'Fraunces', serif;
      font-style: italic;
      font-weight: 500;
      font-size: 2.25rem; /* 36px */
      line-height: 1.2;
      color: var(--ink-primary);
      margin-top: 3.5rem;
      margin-bottom: 1.75rem;
      letter-spacing: -0.015em;
    }

    /* Sticky header */
    .sticky-header {
      background-color: hsl(var(--warm-bg-h) var(--warm-bg-s) var(--warm-bg-l) / 0.92);
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
    }

    /* Coral link */
    a.coral-link {
      color: var(--coral);
      text-decoration: none;
      border-bottom: 1px solid hsl(var(--brand-primary-h) var(--brand-primary-s) calc(var(--brand-primary-l) - 10%) / 0.3);
      transition: border-color 0.15s ease;
    }
    a.coral-link:hover {
      border-bottom-color: var(--coral);
    }

    /* Newsletter input */
    .news-input {
      background-color: transparent;
      border: none;
      border-bottom: 1px solid var(--rule);
      padding: 0.625rem 0.25rem;
      font-family: 'Inter', sans-serif;
      font-size: 0.9375rem;
      color: var(--ink-primary);
      transition: border-color 0.2s;
      width: 100%;
    }
    .news-input::placeholder {
      color: var(--ink-muted);
    }
    /* Mouse click: no outline. Keyboard tab: global :focus-visible ring fires. */
    .news-input:focus:not(:focus-visible) {
      outline: none;
      border-bottom-color: var(--coral);
    }
    .news-input:focus-visible {
      border-bottom-color: var(--coral);
    }

    /* Section rule */
    .rule-thin {
      height: 1px;
      background-color: var(--rule);
    }

    /* Author avatar circle */
    .avatar-circle {
      width: 4rem;
      height: 4rem;
      border-radius: 9999px;
    }
    .avatar-circle-sm {
      width: 1.75rem;
      height: 1.75rem;
      border-radius: 9999px;
    }

/* === Page-E-deck utilities === */
    html, body { font-family: 'Inter', sans-serif; -webkit-font-smoothing: antialiased; }
    .fraunces { font-family: 'Fraunces', serif; }
    .fraunces-italic { font-family: 'Fraunces', serif; font-style: italic; font-variation-settings: "opsz" 144; }
    .instrument-italic { font-family: 'Lora', serif; font-style: italic; }
    .tighter { letter-spacing: -0.04em; }
    .tightest { letter-spacing: -0.055em; }

    /* Warm utility aliases mapped to semantic tokens */
    .bg-linen { background-color: var(--warm-surface-2); }
    .bg-cream { background-color: var(--warm-bg); }
    .bg-paper { background-color: var(--warm-surface); }

    .text-ink { color: var(--warm-text); }
    .text-ink-2 { color: var(--warm-text-2); }
    .text-ink-muted { color: var(--warm-text-3); }
    .text-coral { color: var(--primary); }
    .text-coral-deep { color: var(--primary-deep); }
    .text-sage { color: var(--accent); }
    .text-sage-light { color: var(--accent-deep); }
    .text-cream { color: var(--warm-bg); }

    .bg-coral { background-color: var(--primary); }
    .bg-coral-deep { background-color: var(--primary-deep); }
    .bg-amber-deep { background-color: var(--highlight); }
    .bg-sage { background-color: var(--accent-deep); }

    .border-warm { border-color: var(--warm-border); }

    /* mesh-warm provided by semantic.css; add page-specific variants */
    .mesh-warm-top-right {
      background-color: var(--warm-surface);
      background-image:
        radial-gradient(at 92% 8%, hsl(var(--mesh-warm-1-h) 85% 78% / 0.45) 0px, transparent 55%),
        radial-gradient(at 100% 50%, hsl(var(--mesh-warm-2-h) 60% 82% / 0.30) 0px, transparent 55%);
    }
    .mesh-quote {
      background-color: var(--warm-bg);
      background-image:
        radial-gradient(at 12% 18%, hsl(var(--mesh-warm-1-h) 88% 78% / 0.60) 0px, transparent 55%),
        radial-gradient(at 85% 22%, hsl(var(--mesh-warm-2-h) 70% 82% / 0.45) 0px, transparent 50%),
        radial-gradient(at 90% 85%, hsl(var(--mesh-warm-4-h) 30% 75% / 0.50) 0px, transparent 55%),
        radial-gradient(at 20% 90%, hsl(var(--mesh-warm-3-h) 85% 75% / 0.40) 0px, transparent 50%);
    }

    .shadow-slide {
      box-shadow:
        0 1px 2px hsl(var(--neutral-h) var(--neutral-s) 15% / 0.04),
        0 12px 30px hsl(var(--brand-primary-h) 50% 40% / 0.08),
        0 32px 80px hsl(var(--brand-primary-h) 50% 40% / 0.07);
    }

    .slide {
      aspect-ratio: 16 / 9;
    }

    .hairline {
      background-color: var(--warm-text);
      opacity: 0.18;
    }

    @media (max-width: 600px) {
      .slide {
        aspect-ratio: auto;
        min-height: 80vh;
      }
      .slide [class*="grid-cols-2"]:not([class*="md:"]) {
        grid-template-columns: 1fr !important;
        gap: 1rem;
      }
      .slide [class*="text-7xl"],
      .slide [class*="text-8xl"],
      .slide [class*="text-9xl"] {
        font-size: clamp(48px, 14vw, 96px) !important;
        line-height: 1 !important;
      }
    }

/* === Page-F-pwa utilities === */
    html, body { font-family: 'Inter', sans-serif; -webkit-font-smoothing: antialiased; }
    .serif-italic { font-family: 'Lora', serif; font-style: italic; }
    .jakarta { font-family: 'Plus Jakarta Sans', sans-serif; }
    .tighter { letter-spacing: -0.035em; }
    .tightest { letter-spacing: -0.05em; }

    /* Color tokens — warm friendly, mapped to semantic tokens */
    .bg-linen      { background-color: var(--warm-surface-2); }
    .bg-cream      { background-color: var(--warm-bg); }
    .bg-cream-2    { background-color: var(--warm-surface); }
    .text-ink      { color: var(--warm-text); }
    .text-ink-2    { color: var(--warm-text-2); }
    .text-ink-mute { color: var(--warm-text-3); }
    .border-soft   { border-color: var(--warm-border); }

    .bg-coral      { background-color: var(--primary); }
    .text-coral    { color: var(--primary); }
    .text-coral-deep { color: var(--primary-deep); }
    .bg-sage       { background-color: var(--accent); }
    .text-sage     { color: var(--accent); }
    .bg-sage-light { background-color: var(--accent-deep); }
    .text-sage-light { color: var(--accent-deep); }
    .bg-amber-warm { background-color: var(--highlight); }
    .bg-rose-blush { background-color: var(--primary-soft); }
    .bg-peach-soft { background-color: hsl(18 80% 78%); }

    /* Phone frame — physical hardware chassis (dark) — fixed regardless of brand */
    .phone-frame {
      background: linear-gradient(150deg, #3A3B36 0%, #2D2E2A 40%, #232420 100%);
      box-shadow:
        0 1px 2px rgba(0,0,0,0.18),
        0 20px 50px rgba(70, 50, 30, 0.18),
        0 50px 120px rgba(70, 50, 30, 0.14),
        inset 0 1px 0 rgba(255,255,255,0.08);
    }

    /* Soft card shadows */
    .shadow-warm {
      box-shadow: 0 1px 2px hsl(var(--neutral-h) var(--neutral-s) 15% / 0.04),
                  0 6px 18px hsl(var(--brand-primary-h) 50% 40% / 0.06);
    }
    .shadow-warm-lg {
      box-shadow: 0 2px 4px hsl(var(--neutral-h) var(--neutral-s) 15% / 0.04),
                  0 12px 32px hsl(var(--brand-primary-h) 50% 40% / 0.08);
    }

    /* Gentle gradients in cards — peach/rose/amber decorative blend, anchored to brand tones */
    .grad-weather {
      background: linear-gradient(135deg,
        hsl(18 80% 78%) 0%,
        var(--primary-soft) 60%,
        var(--highlight) 100%);
    }
    .grad-journal {
      background: linear-gradient(140deg,
        hsl(15 75% 87%) 0%,
        hsl(18 80% 78%) 60%,
        var(--primary-soft) 100%);
    }

    /* Scrollbar hide inside phone preview if needed */
    .no-scrollbar::-webkit-scrollbar { display: none; }
    .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
