/* Self-hosted, not Google Fonts.
 *
 * The design references load both faces from the Google Fonts CDN. A Site's
 * Content-Security-Policy is default-src 'self' with no font-src, so a CDN
 * face is blocked outright and would need the policy relaxed. That would put
 * two third-party origins on the critical path, cost a flash of fallback type
 * on cold load, and hand a third party every Viewer's address on two
 * adult-adjacent Brands. Both faces are SIL Open Font License, so self-hosting
 * is permitted and costs nothing but the subsetting.
 *
 * Four files cover five weights because Google serves both families as
 * variable fonts with a wght axis, one file per subset rather than per weight.
 * Unbounded's axis is 200-900 and Instrument Sans' is 400-700, so each file
 * already contains every weight below, and the ranges here restrict matching
 * to the weights the design system actually uses. Asking for a weight outside
 * a declared range still selects the face and clamps the axis, so a stray
 * font-weight cannot silently drop to a fallback family.
 *
 * Only the latin and latin-ext subsets are kept. The other subsets Google
 * offers (cyrillic, greek, vietnamese) are dead weight here, and the non-latin
 * text these Brands do carry is CJK, which falls through to the platform faces
 * named in typography.css.
 */

@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 700 800;
  font-display: swap;
  src: url('../fonts/unbounded-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 700 800;
  font-display: swap;
  src: url('../fonts/unbounded-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../fonts/instrument-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../fonts/instrument-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* The accent trio (--acc, --acc-hi, --acc-dim) is deliberately NOT defined here.
 * It is a Brand fact, so it lives in each Site's skin.json and is emitted into a
 * generated theme.css by engine/site/skin.py. That module's own docstring says
 * why: the accent used to live in two places per Brand and had already drifted
 * (#5b8cff in theme.css against #2e7dff in 404.html). Defining it here as well
 * would rebuild exactly that.
 *
 * This file only USES the trio. For specimen pages and anything rendered outside
 * a Site build, import tokens/accent-preview.css after this file. */
:root{
/* near-black surfaces */
--surface-page:#0b0a0a;
--surface-screen:#060505;
--surface-cold:#070605;
/* white-opacity scale */
--w32:rgba(255,255,255,.32);
--w40:rgba(255,255,255,.4);
--w45:rgba(255,255,255,.45);
--w50:rgba(255,255,255,.5);
--w62:rgba(255,255,255,.62);
--w65:rgba(255,255,255,.65);
--w75:rgba(255,255,255,.75);
--w88:rgba(255,255,255,.88);
--w100:#fff;
/* semantic text */
--text-primary:#fff;
--text-body:var(--w88);
--text-secondary:var(--w62);
--text-muted:var(--w45);
--text-faint:var(--w40);
--text-ghost:var(--w32);
/* control + card surfaces (over near-black) */
--control-bg:rgba(255,255,255,.06);
--control-bg-weak:rgba(255,255,255,.05);
--control-bg-hover:rgba(255,255,255,.1);
--control-bg-dim:rgba(255,255,255,.03);
--control-border:rgba(255,255,255,.14);
--control-border-weak:rgba(255,255,255,.11);
--control-border-strong:rgba(255,255,255,.25);
--control-border-dim:rgba(255,255,255,.08);
--card-bg:rgba(255,255,255,.07);
--card-border:rgba(255,255,255,.13);
/* over-video chrome (dark glass) */
--chrome-bg:rgba(0,0,0,.35);
--chrome-bg-strong:rgba(0,0,0,.4);
--chrome-border:rgba(255,255,255,.18);
--chrome-border-weak:rgba(255,255,255,.16);
/* tracks + dots */
--track:rgba(255,255,255,.14);
--dot-off:rgba(255,255,255,.12);
/* The Clips' caption colours, as engine/bin/captionkit.py draws them: YELLOW
   is (255, 230, 0) and INK is (20, 20, 20). The app draws the Quiz entrance's
   stamp in the caption style (#336) so it reads as the Clips' own lettering
   and not as chrome, and a stamp in a yellow of its own would be the one
   caption on the Site that does not match the rest. Change them here only
   when captionkit changes. */
--caption-yellow:#ffe600;
--caption-ink:#141414;
/* sponsor slot - themable per Sponsor unit */
--sponsor-dot:#e8b96a;
--sponsor-bg:radial-gradient(150% 110% at 70% 20%, #43301a 0%, #19110a 55%, #0b0806 100%); /* @kind other */
/* Clip loading/error placeholder gradients. Production serves real 9:16 video;
   these are what shows behind a Clip that has not arrived. */
--clip-bg-1:radial-gradient(150% 110% at 72% 18%, #4a1620 0%, #1a0b10 55%, #0a0607 100%); /* @kind other */
--clip-bg-2:radial-gradient(150% 110% at 28% 22%, #3f1d33 0%, #170b14 55%, #090508 100%); /* @kind other */
--clip-bg-3:radial-gradient(150% 110% at 62% 78%, #4d2617 0%, #180d09 55%, #0a0706 100%); /* @kind other */
--texture-video:repeating-linear-gradient(115deg, rgba(255,255,255,.016) 0 2px, transparent 2px 7px); /* @kind other */
/* scrims - chrome must survive over moving video */
--scrim-top:linear-gradient(rgba(0,0,0,.55),transparent); /* @kind other */
--scrim-word:linear-gradient(transparent, rgba(0,0,0,.74) 72%); /* @kind other */
--vignette:radial-gradient(95% 45% at 50% 110%, rgba(0,0,0,.72), transparent 62%); /* @kind other */
--freeze:rgba(4,3,3,.55);
/* accent glows */
--glow-top:radial-gradient(110% 55% at 50% -10%, var(--acc-dim), transparent 65%); /* @kind other */
--glow-ask:radial-gradient(110% 60% at 50% 0%, var(--acc-dim), transparent 60%); /* @kind other */
--glow-bottom:radial-gradient(100% 45% at 50% 105%, var(--acc-dim), transparent 60%); /* @kind other */
}
/* The other Brand's placeholder gradients. The accent trio is not here for the
   reason given at the top of this file; only the gradients are, because they are
   not Brand facts a Site declares and nothing else owns them.
   data-skin is the design system's own attribute name and is kept as its API;
   this project's word for what it selects is the Brand. */
[data-skin="guys"]{
--clip-bg-1:radial-gradient(150% 110% at 72% 18%, #241a4d 0%, #100b1e 55%, #07050c 100%); /* @kind other */
--clip-bg-2:radial-gradient(150% 110% at 28% 22%, #16264a 0%, #0b101d 55%, #05070c 100%); /* @kind other */
--clip-bg-3:radial-gradient(150% 110% at 62% 78%, #33184a 0%, #130a1c 55%, #08050c 100%); /* @kind other */
}
:root{
/* families */
--font-display:'Unbounded',sans-serif;
--font-ui:'Instrument Sans',system-ui,-apple-system,sans-serif;
--font-mono:ui-monospace,Menlo,monospace;
/* CJK fallbacks appended to display for taught words */
--cjk-ko:'Apple SD Gothic Neo'; /* @kind font */
--cjk-zh:'PingFang SC'; /* @kind font */
--cjk-yue:'PingFang HK'; /* @kind font */
--font-word:'Unbounded','Apple SD Gothic Neo','PingFang SC','PingFang HK',sans-serif;
/* display scale (Unbounded 700/800) */
--display-word:800 62px/1.04 var(--font-word);
--display-quiz:800 54px/1.05 var(--font-word);
--display-count:800 148px/1 var(--font-display);
--display-streak:800 116px/1 var(--font-display);
--display-stat:800 44px/1 var(--font-display);
--display-end:800 40px/1.15 var(--font-display);
--display-wordmark:800 38px/1.08 var(--font-display);
--display-lang:700 23px/1 var(--font-word);
/* The Quiz entrance's stamp (#336): 퀴즈 시간! on two lines at the size the
   design board sets. Bigger than --display-word because it is not a Word to
   read but an event to notice, and the stroke and shadow it wears are written
   in em against it so they scale with it rather than being sized twice. */
--display-stamp:800 108px/.98 var(--font-word);
/* The Fork's two words (#337), "Watch again" and "Quiz me", on two lines each
   at the board's size. Word-sized rather than stamp-sized because they are
   things to tap, and they wear the stamp's stroke and shadow in em so the
   three read as one hand. */
--display-fork:800 32px/1.04 var(--font-word);
--brand-chrome:700 11px var(--font-display);
/* eyebrow style: 11-12px 600 uppercase, tracked */
--eyebrow:600 11px var(--font-ui);
--eyebrow-lg:600 12px var(--font-ui);
--track-eyebrow:.16em;
--track-eyebrow-wide:.2em;
--track-eyebrow-widest:.24em;
--track-roman:.18em;
/* body/UI */
--ui-body:400 17px/1.5 var(--font-ui);
--ui-gloss:400 18px var(--font-ui);
--ui-tagline:400 15px/1.5 var(--font-ui);
--ui-button:600 16px var(--font-ui);
--ui-choice:600 17px var(--font-ui);
--ui-pill:600 13px var(--font-ui);
--ui-caption:400 11px var(--font-ui);
}
:root{
/* radii */
--r-control:16px;
--r-card:18px;
--r-row:20px;
--r-pill:999px;
--r-canvas:52px;
/* spacing */
--gutter:24px;
--gutter-wide:30px;
--gutter-cold:28px;
--gap-controls:10px;
--gap-stack:12px;
/* The phone canvas is the design references' own furniture: they draw every
   screen inside a 390x844 rounded frame so it reads as a phone on a desktop.
   Screens ship full-bleed. These are here for specimen pages only. */
--canvas-w:390px;
--canvas-h:844px;
/* over-video paddings */
--pad-wordblock:60px 24px 42px;
--pad-chrome:20px;
}
:root{
/* --ease-feed and --dur-feed are for cards and overlays that appear in place:
   the Capture, Progress, the Quiz overlay. They are NOT the Feed's swipe. The
   Feed uses native CSS scroll-snap, because a fixed easing curve cannot be
   flicked through three Clips and cannot match iOS's own momentum. The design
   references drive a transform carousel at this duration because they are
   desktop prototypes that also take the wheel and arrow keys. */
--ease-feed:cubic-bezier(.2,.85,.25,1); /* @kind other */
--dur-feed:550ms; /* @kind other */
/* Prototype only. The shipped Clip progress bar binds to the video element's
   own playback position, because Clips have real and varying durations and a
   fixed animation desynchronises from the first one that is not 8s long.
   Kept because <ClipProgressBar animate> uses it on specimen pages. */
--dur-clip:8s; /* @kind other */
--dur-pop:350ms; /* @kind other */
--transition-control:all .18s; /* @kind other */
/* The Quiz entrance (#336): one duration for every layer, so the flash, the
   sweeps, the rays and the stamp are read as one hit and not as a sequence of
   effects. The Intro slide adds per-layer delays of under a tenth of it. Not
   --dur-feed: this is an event and not a card appearing in place. */
--dur-entrance:1.7s; /* @kind other */
--ease-entrance:cubic-bezier(.2,.8,.2,1); /* @kind other */
/* The Fork under the stamp (#337): the chevrons' nudge and the thumb's pulse
   run for as long as a side is unchosen, and the thumb springs back on the
   pop's duration when a drag lets go short. */
--dur-fork-nudge:1.1s; /* @kind other */
--dur-fork-pulse:1.6s; /* @kind other */
/* The Wipe out of the Fork (#338): two skewed panels leave to the left on a
   hard in-out curve, and the question and its Choices arrive from the right
   on the entrance's own curve, each row a beat after the last. */
--dur-wipe:.55s; /* @kind other */
--ease-wipe:cubic-bezier(.7,0,.3,1); /* @kind other */
--dur-wipe-arrive:.45s; /* @kind other */
}
@keyframes bar8{from{width:0%}to{width:100%}}
@keyframes floaty{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}
@keyframes pop{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}
/* The Quiz entrance's layers (#336). Every one of them ends where the Intro
   slide's base style already puts it (the flash at nothing, the sweeps run off
   the right edge, the rays and sparks gone, the video at rest, the stamp on),
   so a renderer that runs no animation shows the finished screen: the design
   board's white flash had no rest state and left the whole board white in an
   editor that runs none. Colours are not here; a sweep takes the Brand's
   accent from the element it runs on. */
@keyframes entrance-flash{0%{opacity:0}6%{opacity:1}30%{opacity:0}100%{opacity:0}}
@keyframes entrance-sweep{0%{transform:translateX(-140%) skewX(-18deg)}38%,100%{transform:translateX(140%) skewX(-18deg)}}
@keyframes entrance-zoom{0%{transform:scale(1.35)}45%{transform:scale(1.02)}100%{transform:scale(1)}}
@keyframes entrance-rays{0%{opacity:0;transform:rotate(0deg) scale(.4)}18%{opacity:.9}70%{opacity:.35}100%{opacity:0;transform:rotate(40deg) scale(1.5)}}
@keyframes entrance-stamp{0%{opacity:0;transform:scale(3) rotate(-14deg)}22%{opacity:1;transform:scale(.92) rotate(-5deg)}30%{transform:scale(1.08) rotate(-5deg)}38%,100%{opacity:1;transform:scale(1) rotate(-5deg)}}
@keyframes entrance-spark{0%,10%{opacity:0;transform:scale(0) rotate(0deg)}30%{opacity:1;transform:scale(1.2) rotate(90deg)}60%{opacity:1;transform:scale(.9) rotate(140deg)}100%{opacity:0;transform:scale(0) rotate(220deg)}}
/* The Fork (#337) rises on the entrance's own clock, held below until the
   stamp has landed, and ends at rest like every layer above. The nudge and
   the pulse loop: they are the invitation to go sideways, and stop the moment
   a side is taken. The pulse's ring is white on the element, so no colour
   sits here. */
@keyframes fork-rise{0%,55%{opacity:0;transform:translateY(40px)}100%{opacity:1;transform:none}}
@keyframes fork-nudge-right{0%,100%{transform:translateX(0)}50%{transform:translateX(7px)}}
@keyframes fork-nudge-left{0%,100%{transform:translateX(0)}50%{transform:translateX(-7px)}}
@keyframes fork-pulse{0%,100%{box-shadow:0 0 0 0 var(--w40)}50%{box-shadow:0 0 0 14px transparent}}
/* The Wipe (#338). A panel covers the screen at 0% and ends off its left
   edge, which is where the Feed's base style already puts it, so a renderer
   that runs no animation shows the question and no panel. The arrival ends at
   rest for the same reason. Colours are not here; a panel takes the Brand's
   accent or the caption yellow from the element it runs on. */
@keyframes wipe-leave{0%{transform:translateX(0) skewX(-14deg)}100%{transform:translateX(-170%) skewX(-14deg)}}
@keyframes wipe-arrive{0%{opacity:0;transform:translateX(60px)}100%{opacity:1;transform:none}}
/* The Landing: the marketing front door at /, one template for both Brands.
 *
 * Recreated from the design handoff of 2026-08-08 (#220), pixel-values kept as
 * the reference gave them. The reference is inline-styled; this file exists
 * because the Sites ship style-src 'self' and no inline style may survive.
 * Everything themable reads the tokens; the accent trio arrives from the
 * generated theme.css, and both Brands' trios from landing-theme.css so the
 * sister section can flip skin mid-page.
 *
 * build.sh concatenates the design-system token files above this one into the
 * served landing.css, so every var() here is defined by the time it is read.
 */

body { margin: 0; background: var(--surface-page); color: var(--text-primary); font-family: var(--font-ui); }
.l-page { min-height: 100vh; overflow-x: clip; }
.l-shell { max-width: 1160px; margin: 0 auto; padding-left: clamp(20px, 5vw, 40px); padding-right: clamp(20px, 5vw, 40px); }
.l-page a { text-decoration: none; }

/* nav. sticky needs no ancestor overflow-x:hidden; .l-page uses clip for that
   exact reason (the reference calls it out). */
.l-nav { position: sticky; top: 0; z-index: 50; background: rgba(11, 10, 10, .78); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--control-border-dim); }
.l-nav-row { display: flex; justify-content: space-between; align-items: center; padding-top: 16px; padding-bottom: 16px; }
.l-brand { display: flex; align-items: center; gap: 11px; }
.l-brand-name { font: 700 14px var(--font-display); letter-spacing: .05em; }

/* the CSS flame: a square with one corner kept, rotated. There is no logo
   file anywhere, on purpose. */
.l-flame { width: 15px; height: 15px; flex: none; background: var(--acc); border-radius: 0 50% 50% 50%; transform: rotate(45deg); }
.l-flame-pill { width: 9px; height: 9px; }
.l-pill-sm .l-flame-pill { width: 8px; height: 8px; }

/* buttons, matching the design system's Button variants */
.l-btn { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; cursor: pointer; transition: var(--transition-control); }
.l-btn-primary { min-width: 180px; padding: 16px 26px; border-radius: var(--r-control); background: var(--acc); border: none; color: #fff; font: var(--ui-button); }
.l-btn-primary:hover { background: var(--acc-hi); }
.l-btn-outline { padding: 15px 26px; border-radius: var(--r-pill); background: transparent; border: 1px solid var(--acc); color: var(--acc-hi); font: 600 15px var(--font-ui); }
.l-btn-outline:hover { background: var(--acc); color: #fff; }

/* section scaffolding */
.l-section { border-top: 1px solid var(--control-border-dim); position: relative; }
.l-section .l-shell { position: relative; padding-top: clamp(64px, 10vw, 110px); padding-bottom: clamp(64px, 10vw, 110px); }
.l-glow { position: absolute; inset: 0; pointer-events: none; }
.l-glow-top { background: var(--glow-top); }
.l-glow-ask { background: var(--glow-ask); }
.l-glow-bottom { background: var(--glow-bottom); }

/* type */
.l-h1 { margin: 0; font: 800 clamp(34px, 4.8vw, 58px)/1.08 var(--font-display); letter-spacing: -.01em; text-wrap: pretty; }
.l-h2 { margin: 0; font: 800 clamp(29px, 3.6vw, 40px)/1.15 var(--font-display); letter-spacing: -.01em; text-wrap: pretty; }
.l-h2-wide { max-width: 820px; font: 800 clamp(27px, 3.4vw, 36px)/1.25 var(--font-display); }
.l-h2-final { margin: 0; font: 800 clamp(32px, 4.2vw, 46px)/1.15 var(--font-display); letter-spacing: -.01em; text-wrap: pretty; }
.l-body { margin: 0; font: var(--ui-body); color: var(--text-secondary); text-wrap: pretty; }
.l-measure { max-width: 560px; }
.l-measure-sm { max-width: 460px; }
.l-measure-xs { max-width: 440px; }
.l-eyebrow { font: var(--eyebrow); letter-spacing: var(--track-eyebrow-wide); text-transform: uppercase; color: var(--acc-hi); }
.l-eyebrow-lg { font: var(--eyebrow-lg); letter-spacing: var(--track-eyebrow-widest); text-transform: uppercase; color: var(--acc-hi); }
.l-micro { font: 500 13px var(--font-ui); color: var(--text-muted); }
.l-mono { font: 400 11px var(--font-mono); color: var(--text-ghost); letter-spacing: .04em; }

/* stacks and grids */
.l-stack { display: flex; flex-direction: column; gap: 22px; }
.l-stack-lg { display: flex; flex-direction: column; gap: 56px; }
.l-grid-2 { display: grid; gap: clamp(40px, 6vw, 80px); align-items: center; }
.l-grid-quiz { grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr)); }
.l-grid-progress { grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr)); }
.l-grid-langs { grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); }
.l-grid-sister { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }

/* hero */
.l-hero { position: relative; }
.l-hero .l-shell { position: relative; padding-top: 64px; padding-bottom: 110px; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); gap: clamp(40px, 6vw, 64px); align-items: center; }
.l-hero-copy { display: flex; flex-direction: column; gap: 26px; }
.l-hero-sub { margin: 0; max-width: 480px; font: 400 19px/1.55 var(--font-ui); color: var(--text-secondary); text-wrap: pretty; }
.l-hero-cta { display: flex; align-items: center; gap: 18px; margin-top: 6px; }
.l-hero-phone { display: flex; justify-content: center; }

/* The phone canvas: the design references' own furniture, drawn at 390x844
   and scaled to fit. The only shadow on the whole page. */
.l-phone-box { width: 312px; height: 676px; flex: none; }
.l-canvas { width: 390px; height: 844px; transform: scale(.8); transform-origin: top left; border-radius: var(--r-canvas); overflow: hidden; position: relative; background: var(--clip-bg-1); box-shadow: 0 0 0 1px rgba(255, 255, 255, .09), 0 40px 90px rgba(0, 0, 0, .65); }

/* the clip video and the overlay set that must survive above it */
.l-clip { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* The hero's swipe. --dur-feed and --ease-feed are the reference's own
   transform-carousel pair, which motion.css reserves for exactly this kind of
   desktop prototype: the shipped Feed scroll-snaps, this mock is scripted. The
   outgoing clip keeps playing as it leaves, the next slides in from below,
   and .l-snap repositions without animating so a video can be re-staged
   off-screen between swipes. */
.l-hero-clip { transform: translateY(0); transition: transform var(--dur-feed) var(--ease-feed); will-change: transform; }
.l-hero-clip.l-below { transform: translateY(100%); }
.l-hero-clip.l-above { transform: translateY(-100%); }
.l-hero-clip.l-snap { transition: none; }

/* Re-triggered per swipe: the incoming word data pops the way anything
   appearing does. */
.l-wordblock.l-pop { animation: pop var(--dur-pop) ease both; }
.l-vignette { position: absolute; inset: 0; background: var(--vignette); pointer-events: none; }
.l-bar { position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--track); z-index: 5; }
.l-bar-fill { height: 100%; width: 0; background: var(--acc); }
.l-bar-62 { width: 62%; }
.l-chrome { position: absolute; top: 0; left: 0; right: 0; padding: 20px; display: flex; justify-content: space-between; align-items: center; pointer-events: none; background: var(--scrim-top); z-index: 6; }
.l-chrome-sm { padding: 16px 18px; }
.l-chrome-brand { font: var(--brand-chrome); letter-spacing: .05em; color: #fff; }
.l-pill { display: flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: var(--r-pill); background: var(--chrome-bg); border: 1px solid var(--chrome-border); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); color: #fff; font: var(--ui-pill); }
.l-pill-sm { gap: 7px; padding: 7px 12px; font: 600 12px var(--font-ui); }
.l-pill-dot { color: var(--text-faint); }
.l-wordblock { position: absolute; left: 0; right: 0; bottom: 0; padding: 60px 24px 42px; background: var(--scrim-word); }
.l-wordblock-sm { padding: 50px 22px 30px; }
.l-word-no { margin-bottom: 10px; }
.l-wordblock-sm .l-word-no { margin-bottom: 8px; }
.l-word { font: var(--display-word); color: #fff; letter-spacing: -.01em; }
.l-word-sm { font: 800 44px/1.05 var(--font-word); }
.l-roma { margin-top: 10px; font: 600 14px var(--font-ui); letter-spacing: var(--track-roman); text-transform: uppercase; color: var(--acc-hi); }
.l-roma-sm { margin-top: 8px; font: 600 13px var(--font-ui); }
.l-gloss { margin-top: 5px; font: var(--ui-gloss); color: var(--text-body); }
.l-gloss-sm { margin-top: 4px; font: 400 16px var(--font-ui); }

/* manifesto stats */
.l-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: clamp(24px, 4vw, 40px); max-width: 820px; }
.l-stat-value { font: var(--display-stat); color: #fff; }
.l-stat-label { margin-top: 8px; font: var(--eyebrow); letter-spacing: var(--track-eyebrow); text-transform: uppercase; color: var(--text-muted); }

/* quiz beat */
.l-quiz-demo { display: flex; flex-direction: column; gap: 10px; }
.l-quiz-label { font: 600 12px var(--font-ui); letter-spacing: var(--track-eyebrow); text-transform: uppercase; color: var(--text-muted); margin-bottom: 4px; }
.l-choice { display: flex; align-items: center; justify-content: space-between; padding: 16px 18px; border-radius: var(--r-control); font: var(--ui-choice); }
.l-choice-correct { background: var(--acc); border: 1px solid transparent; color: #fff; }
.l-choice-dimmed { background: var(--control-bg-dim); border: 1px solid var(--control-border-dim); color: var(--text-faint); }
.l-choice-mark { font-size: 14px; opacity: .85; }
.l-reaction { margin-top: 8px; display: flex; align-items: center; gap: 12px; padding: 13px 16px; border-radius: var(--r-card); background: var(--card-bg); border: 1px solid var(--card-border); }
.l-reaction-text { flex: 1; min-width: 0; }
.l-reaction-title { font: 600 13px var(--font-ui); color: var(--acc-hi); }
.l-reaction-body { font: 400 13px/1.4 var(--font-ui); color: var(--w65); }
.l-reaction-hint { font: 600 10px var(--font-ui); letter-spacing: .12em; color: var(--text-faint); white-space: nowrap; }

/* avatars: presenter gradients until production supplies stills */
.l-avatar { width: 40px; height: 40px; border-radius: 50%; flex: none; background: var(--clip-bg-1); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .15); }
/* the roster's avatars are Faces now (#294); the gradient stays as the ground under them */
img.l-avatar { object-fit: cover; }
.l-avatar-2 { background: var(--clip-bg-2); }
.l-avatar-3 { background: var(--clip-bg-3); }

/* progress beat */
.l-progress-card { position: relative; padding: 44px 40px 36px; border-radius: var(--r-card); background: var(--surface-screen); border: 1px solid var(--card-border); overflow: hidden; }
.l-progress-inner { position: relative; display: flex; flex-direction: column; gap: 26px; }
.l-stat-hero-value { font: var(--display-count); color: var(--acc); letter-spacing: -.02em; }
.l-stat-hero .l-stat-label { margin-top: 8px; }
.l-dots { display: flex; gap: 7px; }
.l-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--dot-off); }
.l-dot-on { background: var(--acc); }

/* languages */
.l-langs { display: flex; flex-direction: column; gap: 12px; }
.l-lang { display: flex; align-items: center; justify-content: space-between; width: 100%; box-sizing: border-box; padding: 18px 22px; background: var(--control-bg-weak); border: 1px solid var(--control-border-weak); border-radius: var(--r-row); color: #fff; text-align: left; transition: var(--transition-control); }
.l-lang:hover { background: var(--control-bg-hover); border-color: var(--acc); }
.l-lang-names { display: flex; flex-direction: column; gap: 3px; }
.l-lang-native { font: 700 23px/1 var(--font-display); }
.l-cjk-ko .l-lang-native, .l-lang-native.l-cjk-ko { font-family: 'Unbounded', var(--cjk-ko), sans-serif; }
.l-lang-native.l-cjk-zh { font-family: 'Unbounded', var(--cjk-zh), sans-serif; }
.l-lang-native.l-cjk-yue { font-family: 'Unbounded', var(--cjk-yue), sans-serif; }
.l-lang-en { font: 500 12px var(--font-ui); letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); }
.l-lang-arrow { color: var(--acc); font-size: 20px; }

/* sister brand */
.l-sister { overflow: hidden; }
.l-roster { display: flex; align-items: center; gap: 14px; margin-top: 4px; }
.l-roster-avatars { display: flex; }
.l-roster-avatars .l-avatar + .l-avatar { margin-left: -10px; }
.l-roster-names { font: 600 12px var(--font-ui); letter-spacing: var(--track-eyebrow); text-transform: uppercase; color: var(--text-muted); }
.l-roster-cta { margin-top: 10px; }
.l-clipcard { position: relative; width: 340px; max-width: 100%; height: 480px; justify-self: center; border-radius: var(--r-card); overflow: hidden; background: var(--clip-bg-2); border: 1px solid var(--card-border); }

/* final cta */
.l-final .l-shell { padding-top: clamp(80px, 12vw, 130px); padding-bottom: clamp(80px, 11vw, 120px); display: flex; flex-direction: column; align-items: center; gap: 28px; text-align: center; }

/* footer */
.l-footer .l-shell { padding-top: 30px; padding-bottom: 30px; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 20px; }
.l-made { font: 400 12px var(--font-ui); color: var(--text-ghost); }
