/* masa — Azul homepage. Expressive minimalism: minimalist structure, one maximalist moment (the mascot).
   Motion is transform/opacity only; reveals are CSS scroll-driven (progressive enhancement). */

*,*::before,*::after{box-sizing:border-box;}
/* ⚑ iPHONE WIDTH FIX (Juan, Jul 17 2026 late — "everything leans to the left" on iPhone):
   .ambient's -15% horizontal inset overflowed the viewport on the RIGHT and widened the
   page's scroll width on any page without overflow clipping, so the centered column read
   as leaning left. Root fix: clip horizontal overflow at the root (clip, not hidden —
   no scroll container is created, so position:sticky keeps working) AND contain .ambient
   itself below. Mirrored on every inline-style page. */
html{-webkit-text-size-adjust:100%;overflow-x:clip;}
body{margin:0;background:var(--g);color:var(--ink);overflow-x:clip;
  font-family:var(--f-body);
  font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;
  transition:background-color .3s var(--ease-out),color .3s var(--ease-out);}
.shell{max-width:1000px;margin:0 auto;padding:0 40px;}
img{max-width:100%;display:block;}
:focus-visible{outline:3px solid var(--indigo);outline-offset:3px;border-radius:4px;}

/* ⚑ DISPLAY = Cal Sans, weight 600 (skin pass Jul 17). Was Helvetica-800 — the heavy weight
   was the biggest "old" tell next to the new lighter grotesk. Cal Sans is a single friendly
   display weight; -.02em tracking matches the study. Lowercase stays (masa's voice). */
.disp{font-family:var(--f-disp);font-weight:600;letter-spacing:-.02em;
  text-transform:lowercase;line-height:1;text-wrap:balance;}
.hand{font-family:"MasaHand","Snell Roundhand","Brush Script MT",cursive;font-weight:700;}
.mono{font-family:ui-monospace,"SF Mono",Menlo,monospace;}

/* ---- top bar ---- */
/* ⚑ GLASS ON CHROME ONLY (skin pass Jul 17 2026, the r7/Apple rule): the bar is the one
   backdrop-filter on the page, and only from 768px up — sticky at every width
   stacked chrome over content on a phone in the r6 study, and small viewports need the
   rows back. Content surfaces get plain fills + hairlines, never glass (iOS silently
   drops blur layers past ~3 — the r6 iPhone lesson). */
/* ⚑ TWO STATES (study r16, ported Jul 17 2026 — flask's header, finally measured while
   SCROLLED, not just at scrollY=0): transparent at the top; past 8px of scroll it becomes
   a dark glass PILL — page color at 70% (color-mix keeps it theme-agnostic), blur 24px,
   a 5%-white hairline, pill radius. A passive scroll listener on the index pages flips
   `.scrolled`. FAIL-OPEN: the transparent resting state is gated on html.js, so a page
   without the listener (threads.html) or with JS broken keeps a readable glass bar
   always — never a transparent bar over scrolled content. Still ONE backdrop-filter,
   desktop-only: a phone renders zero blur layers. */
.bar{display:flex;align-items:center;justify-content:space-between;padding:24px 0 4px;}
@media(min-width:768px){
  .bar{position:sticky;top:4px;z-index:30;margin:0 -16px;padding:10px 18px;
    border:1px solid transparent;border-radius:var(--r-pill);
    background:var(--glass);-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);
    transition:background-color .3s var(--ease-out),border-color .3s var(--ease-out);}
  html.js .bar:not(.scrolled){background:transparent;border-color:transparent;
    -webkit-backdrop-filter:none;backdrop-filter:none;}
  .bar.scrolled{background:color-mix(in srgb, var(--g) 70%, transparent);
    border-color:rgba(255,255,255,.05);}
  /* the 5%-white hairline is invisible on the light theme's white ground — the token
     hairline does the same job there */
  :root[data-theme="light"] .bar.scrolled{border-color:var(--line);}
}
.brand{display:flex;align-items:center;gap:9px;font-family:var(--f-disp);
  font-weight:800;font-size:21px;letter-spacing:-.02em;color:var(--peri-ink);}
.brand .m{width:15px;height:15px;background:currentColor;border-radius:var(--r-dough);} /* mark = wordmark color, both modes */
.bar .r{display:flex;align-items:center;gap:14px;font-size:12.5px;color:var(--soft);}
.bar .place{font-family:var(--f-body);letter-spacing:.04em;}
.bar .lang a{color:var(--soft);text-decoration:none;}
.bar .lang a.on{color:var(--indigo);font-weight:700;}
.bar .lang .sep{opacity:.5;margin:0 3px;}
.themebtn{background:none;border:1px solid var(--line);border-radius:var(--r-pill);width:30px;height:30px;
  cursor:pointer;color:var(--soft);font-size:14px;line-height:1;display:grid;place-items:center;
  transition:transform var(--t-micro) var(--ease-out),border-color var(--t-micro) var(--ease-out);}
.themebtn:hover{transform:translateY(-1px);border-color:var(--indigo);color:var(--indigo);}

/* ---- buttons ---- */
/* ⚑ FLASK BUTTONS (Juan's ratification, Jul 17 2026 late — the Clay flat-mango-chip rule
   is SUPERSEDED for the flask skin; see azul-tokens.css header + masa-design-language.md).
   Primary = the study's .btn-primary: light gradient, dark text, layered soft shadow.
   Secondary (.ghost) = the study's .btn-secondary: #202020 fill, hairline border with a
   lighter top edge, 70%-white text. Mango is no longer a button fill anywhere. */
/* ⚑ STUDY METRICS (Juan, Jul 17 2026 late — "I like the buttons' size from the flask
   skin"): height 44 / padding 8 20 / 15px, copied exactly from the study's .btn-primary
   (masa-as-flask-exact.html). Gradient + colors stay as already shipped. Mirrored into
   every inline .btn copy (start/audience/threads/links + ES). */
/* ⚑ BUTTON TEXT = BODY FONT (Juan, Jul 17 2026 closeout): buttons speak UI, not display —
   font-family:var(--f-body) explicitly, because <button> elements do NOT inherit the body
   font (start.html's form buttons were rendering the UA default). Metrics unchanged. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;white-space:nowrap;
  background:linear-gradient(to top,#cfdef6 20%,#fafafa 80%);color:#191919;
  font-family:var(--f-body);font-weight:500;font-size:15px;text-decoration:none;height:44px;padding:8px 20px;
  border:.5px solid transparent;border-radius:var(--r-pill);cursor:pointer;
  box-shadow:inset 0 1px #ffffffd9,inset 0 -1px #09090b0f,0 0 0 .5px #09090b8c,
             0 1px 2px #00000059,0 4px 12px #00000038;
  transition:transform var(--t-micro) var(--ease-out),filter var(--t-micro) var(--ease-out),
             box-shadow var(--t-micro) var(--ease-out);}
.btn:hover{transform:translateY(-1px);filter:brightness(1.03);
  box-shadow:inset 0 1px #ffffffd9,inset 0 -1px #09090b0f,0 0 0 .5px #09090b8c,
             0 2px 4px #00000059,0 6px 16px #00000047;}
.btn:active{transform:translateY(0) scale(.98);filter:none;}
.btn.ghost{background:#202020;color:rgba(255,255,255,.7);box-shadow:none;
  border:1px solid #2A2A2A;border-top-color:#3B3B3B;}
.btn.ghost:hover{background:#242424;color:rgba(255,255,255,.95);filter:none;
  border-color:#3a3a3a;border-top-color:#4d4d4d;}
/* ⚑ the demoted secondary (s5e) — a quiet text link beside the one primary CTA, never a second button */
.plans-link{color:var(--soft);font-size:14px;text-decoration:underline;text-underline-offset:3px;
  transition:color var(--t-micro) var(--ease-out);}
.plans-link:hover{color:var(--ink);}

/* ---- hero: outcome + one CTA, mascot as the one maximalist moment ---- */
/* ⚑ CENTERED STACK (study r13, ported Jul 17 2026) — flask's actual hero pattern,
   measured live: the HERO ONLY is centered (copy centered, demo below full-width);
   every section h2 stays left. The 2-col grid was masa's r118 layout wearing the new
   paint. Readability canon agrees: center short display lines, never multi-line body. */
.hero{display:grid;grid-template-columns:1fr;gap:clamp(32px,5vw,48px);align-items:center;padding:72px 0 var(--sp-section);position:relative;}
.hero>:not(.ambient){position:relative;z-index:1;}
/* ⚑ SPOTLIGHT (study r19 / visual-collection verdict) — parity with audience/threads heroes.
   Gradient-only ambient glow: faint white lift + one mango breath, zero blur, zero iOS cost. */
/* ⚑ contained (iPhone width fix): the glow never extends past the viewport edge —
   left/right = the larger of -15% and the hero-edge→viewport-edge distance. */
/* ⚑ s5w — the glow STARTS BELOW THE TOP so the header/status-bar strip stays flat dark (Juan:
   "the iPhone status bar can't do gradients — the glow shouldn't reach the top"). Was top:-8% with a
   radial at 6% (which bled up behind the bar); now the box starts ~90px down and the glow sits behind
   the HEADLINE (26–40%), fading out well before the top. */
.ambient{position:absolute;top:70px;height:540px;
  left:max(-15%,calc((100% - 100vw)/2));right:max(-15%,calc((100% - 100vw)/2));
  z-index:0;pointer-events:none;
  background:radial-gradient(ellipse 52% 44% at 50% 20%,rgba(250,250,250,.03),transparent 70%),
             radial-gradient(ellipse 58% 50% at 50% 32%,rgba(146,220,229,.11),transparent 72%);}
.hero-copy{max-width:820px;margin:0 auto;text-align:center;}
.hero-copy .lede{margin-inline:auto;}
.hero-copy .trust{justify-content:center;}
.btn-row{display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap;}
/* ⚑ EYEBROW/KICKER = OUTFIT, not mono (Juan, Jul 17 s5 — "the eyebrow copy reads too
   technical; make it Outfit"). The uppercase + tracking stays so it still functions as a
   kicker, but the monospace 'dev console' tell is gone — warmer, editorial, on-brand.
   Tracking eased .15em→.12em (mono needed the extra air; a proportional face doesn't). */
.eyebrow{font-family:var(--f-body);font-weight:500;font-size:12px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--teal-d);margin:0 0 24px;}
.hero h1{font-size:clamp(38px,5.2vw,58px);margin:0 0 24px;}
.hero h1 em{font-style:normal;color:var(--indigo);}
/* day: em in deep periwinkle (5.8:1) — mango is RESERVED for the CTA + hand-script (action-color rule) */
:root[data-theme="light"] .hero h1 em, :root:not([data-theme="dark"]) .hero h1 em{color:var(--peri-ink);}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .hero h1 em{color:var(--indigo);}
}
.lede{font-size:17.5px;line-height:1.55;color:var(--soft);max-width:40ch;margin:0 0 32px;}
.sig{display:block;margin-top:16px;font-size:21px;color:var(--coral);}
.trust{display:flex;flex-wrap:wrap;gap:8px 24px;margin-top:32px;}
.trust span{font-size:13.5px;color:var(--soft);display:flex;align-items:center;gap:7px;}
.trust b{color:var(--ink);font-weight:660;}
.trust .d{width:6px;height:6px;border-radius:50%;background:var(--chip);} /* mango = the single accent (flask-skin ratification Jul 17) */

/* ⚑ dead-mascot sweep (Jul 16 2026): the .stage/#mascot/.dough/.eye/.glyph stage
   rules + assets/js/mascot.js are DELETED — the ES hero adopted the demo in r118,
   so no page had the stage markup and nothing loaded the script (it was flagged
   for exactly this sweep in es/index.html's r118 note). The mascot itself lives
   on as .ava in the phone mock below; the physics lab is self-contained in
   design-studies/masa-mascot-motion-lab.html. Recoverable from git history. */

/* ---- THE PHONE (study port, Jul 17 2026 late — Juan: "I like the mockup from the flask
   skin") ------------------------------------------------------------------------------
   Replaces .hero-demo (the flat panel mock; its hd-* rules are deleted — recoverable from
   git history, including the r118 card notes and the SETTLED hero-media ruling: the
   photos stay Juan's own Kova frames, NEVER stock — that ruling carries over unchanged).
   Ported from design-studies/masa-as-flask-exact.html: a 44px-rounded frame at the page's
   own ground (no device bezel), the f-top header (mascot dot + masa + example), a
   bottom-anchored thread, the glass composer ('type it… or just talk'), the home
   indicator, and the frame-contained glow. The site's real content beats ride inside
   (photo → caption → reply → voice note → reply → newsletter approve card with 'see it
   in your space →', ghost LEFT / approve RIGHT — HIG order, as the product draws them).
   Namespaced: .fr (row — a bare .r would hit .bar .r), .fvn (voice note — .vn is the
   knot's), .flnk/.fpill/.pact (link row / status pill / mini-buttons). Hairlines are the
   site's uniform var(--line) (the two-tone "Apple line" stays retracted — tokens header).
   BLUR BUDGET (the r7 iPhone lesson — iOS silently drops layers past ~3): the composer's
   backdrop-filter is this page's SECOND blur layer (the bar's is desktop-only, so a phone
   renders exactly one). .frame-amb is a filter (not backdrop-filter) clipped inside the
   frame — the study's contained glow, flask's only big blur.
   Built at TRUE iPhone logical size (393×852 HIG points) and SCALED for presentation:
   transform:scale shrinks the PAINT, never the LAYOUT, so the frame is absolute (out of
   flow) and .phone-wrap carries the scaled footprint (study r6/r23). Scale steps are
   FIXED unitless numbers — scale(calc(…px)) is invalid CSS and silently drops. */
.phone-wrap{--s:.72;--fsh:0 10px 15px -3px rgba(0,0,0,.2),0 4px 6px -4px rgba(0,0,0,.2);
  position:relative;min-width:0;width:calc(393px * var(--s));height:calc(852px * var(--s));
  margin:0 auto;}
@media(max-width:900px){.phone-wrap{--s:.82;}}
@media(max-width:430px){.phone-wrap{--s:.78;}}
@media(max-width:350px){.phone-wrap{--s:.68;}}
/* ⚑ RETINA-SHARP FRAME (Juan, Jul 17 2026 s5 — "the desktop mockup looks very blurry"):
   the old `-webkit-mask-image:-webkit-radial-gradient(white,black)` rounded-clip hack (study
   r7) forced this scaled layer to rasterize at 1× device pixels, then scale(.72) squeezed
   that soft texture harder on desktop = the blur. REMOVED. The 44px corner clip is now held
   by overflow:hidden + isolation:isolate (both already here; modern WebKit/Blink clip
   composited children to border-radius once the element is a stacking context with a
   transform — verified retina-sharp in-browser). Belt-and-suspenders: .frame-amb below
   self-clips with its own border-radius so its blur can't leak past the corners on Safari. */
.frame{position:absolute;top:0;left:50%;width:393px;height:852px;
  transform:translateX(-50%) scale(var(--s));transform-origin:top center;
  border-radius:44px;background:var(--g);border:1px solid var(--line);
  box-shadow:var(--lift);overflow:hidden;z-index:1;isolation:isolate;
  display:flex;flex-direction:column;font-family:var(--f-ui);}
/* ⚑ DISPERSED INTERFACE GLOW (s5o) — the "motivated light" the s5g hook was left for. s5g removed a
   TIGHT top-left spot from no source; this is the FLASK look Juan asked for after studying flask.do:
   a soft, DISPERSED multi-radial wash INSIDE the frame (warm + cyan + a touch of pink), reading as
   ambient interface depth — flask's own mock does exactly this (colored pastel radials inside the
   product frame). Motivated now because (a) it's the flask reference Juan chose, and (b) the mock is
   STATIC as of s5o (live-texting, no marquee), so the light no longer floats unmotivated over moving
   content. iOS-cheap: plain radial-gradients (soft by nature), NO blur filter — flask uses blur(120px)
   but that's the scroll-raster cost s5h–l fought; wide radial falloffs get the same dispersion for free.
   Clipped to the rounded frame by .frame's overflow:hidden. Tunable — dial the alphas up/down. */
.frame-amb{position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(78% 44% at 74% 20%, rgba(255,140,66,.14), transparent 62%),
    radial-gradient(66% 46% at 22% 30%, rgba(146,220,229,.11), transparent 64%),
    radial-gradient(60% 40% at 56% 80%, rgba(231,150,180,.06), transparent 66%);}
/* header: 16pt inset + status-bar breathing room. The dot is the mascot (dough recipe),
   so the thread reads as the same character answering — the r1 ruling, kept. */
.f-top{position:relative;z-index:2;display:flex;align-items:center;gap:8px;
  padding:24px 16px 8px;font-size:13px;min-height:68px;color:var(--ink);}
.f-top .fdot{width:32px;height:32px;border-radius:var(--r-dough);background:var(--dough);
  flex:none;display:flex;align-items:center;justify-content:center;gap:4px;}
.f-top .fdot i{width:4px;height:4px;border-radius:50%;background:var(--dough-eye);display:block;}
.f-top b{font-weight:500;font-size:15px;}
.f-top .st{margin-left:auto;font-size:12px;color:var(--soft);}
/* thread: 16pt inset, 8pt gaps, anchored to the BOTTOM like every real messaging app */
.frame .thread{position:relative;z-index:2;display:flex;flex-direction:column;gap:8px;
  padding:8px 16px;flex:1;justify-content:flex-end;overflow:hidden;}
.fr{display:flex;gap:7px;}
.fr.out{justify-content:flex-end;}
.stk{display:flex;flex-direction:column;gap:5px;max-width:86%;}
.stk.end{align-items:flex-end;}
.via{font-size:9.5px;color:var(--soft);padding:0 4px;}
/* ⚑ MOTIVATED GLOW ON THE MOCK PHOTO (s5h, Juan — "the media glow should follow the images"): a soft
   warm bloom on the photo itself, so the glow is motivated BY the media and travels with it as the
   thread scrolls. Tight + contained (not the big standalone-media glow). */
/* ⚑ MEDIA GLOW (s5v) — the wrap holds a blurred copy of the image (the glow, from the media's own
   colors) behind the clipped image. The mock is static (s5o), so the blur pays no scroll-raster cost;
   own GPU layer keeps it cheap. */
.shot-wrap{position:relative;display:inline-block;line-height:0;}
.shot-glow{position:absolute;inset:0;z-index:0;pointer-events:none;
  background-size:cover;background-position:center;border-radius:16px;
  filter:blur(20px) saturate(1.5);opacity:.6;transform:scale(1.18) translateZ(0);will-change:transform;}
.shot-img{position:relative;z-index:1;width:184px;border-radius:16px;overflow:hidden;
  border:1px solid var(--line);box-shadow:0 8px 22px -12px rgba(0,0,0,.5); /* neutral depth now the glow is the media's colour */
  transform:translateZ(0);}/* own layer → no flicker during scroll (s5i) */
.shot-img img{width:100%;aspect-ratio:1;object-fit:cover;display:block;}
.bub{padding:8px 12px;border-radius:18px;font-size:15px;line-height:1.35;color:var(--ink);
  background:var(--panel);border:1px solid var(--line);box-shadow:var(--fsh);}
.bub.out{border-bottom-right-radius:6px;}
.bub.in{border-bottom-left-radius:6px;}
/* the voice note — masa's PRIMARY lane (capture/README), so it belongs in the demo */
.fvn{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:18px;
  border-bottom-right-radius:6px;background:var(--panel);border:1px solid var(--line);
  box-shadow:var(--fsh);}
.fvn .play{width:24px;height:24px;border-radius:50%;flex:none;
  background:linear-gradient(to top,#cfdef6 20%,#fafafa 80%);}
.fvn .wave{display:flex;align-items:center;gap:2px;height:16px;}
.fvn .wave i{width:2px;border-radius:1px;background:var(--soft);display:block;}
.fvn .len{font-size:12px;color:var(--soft);font-variant-numeric:tabular-nums;}
/* the agent — the dough on masa's reply (the "mascot promoted to agent" ruling) */
.ava{width:24px;height:24px;border-radius:var(--r-dough);background:var(--dough);flex:none;
  align-self:flex-end;display:flex;align-items:center;justify-content:center;gap:3.5px;}
.ava i{width:3.5px;height:3.5px;border-radius:50%;background:var(--dough-eye);display:block;}
/* the deliverable card — real product strings; 27px left = the avatar gutter */
.pkg{position:relative;border-radius:22px;padding:11px;margin-left:27px;
  background:var(--panel);border:1px solid var(--line);box-shadow:var(--fsh);}
.pkg-h{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-bottom:3px;}
.pkg-h b{font-size:12.5px;font-weight:500;color:var(--ink);}
.fpill{font-size:8.5px;font-weight:500;letter-spacing:.05em;text-transform:uppercase;
  padding:2px 7px;border-radius:var(--r-pill);background:var(--sunk);color:var(--soft);flex:none;}
.pkg-m{font-size:10.5px;color:var(--soft);margin:0 0 8px;}
/* a waiting card's cross-link is 'see it in your space →' (capture.js real string) */
.flnk{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 10px;
  border-radius:9px;font-size:11px;background:var(--sunk);color:var(--ink);margin-bottom:9px;}
.flnk b{font-weight:500;}
.flnk span{color:var(--soft);flex:none;}
.pkg-a{display:flex;gap:6px;}
/* mini-buttons at the study's .btn-sm metrics (34 / 6 14 / 12.5) */
.pact{display:inline-flex;align-items:center;justify-content:center;height:34px;
  padding:6px 14px;font-size:12.5px;font-weight:500;border-radius:var(--r-pill);
  white-space:nowrap;background:#202020;color:rgba(255,255,255,.7);
  border:1px solid #2A2A2A;border-top-color:#3B3B3B;}
.pact.ok{background:linear-gradient(to top,#cfdef6 20%,#fafafa 80%);color:#191919;border:0;
  box-shadow:0 0 0 .5px #09090b8c,0 1px 2px #00000059;}
/* composer: glass on CHROME only (the r7/Apple rule) — this page's 2nd blur layer */
.f-bar{position:relative;z-index:2;margin:0 16px 8px;border-radius:var(--r-pill);
  padding:8px 8px 8px 16px;min-height:44px;font-size:15px;color:var(--soft);
  display:flex;align-items:center;gap:8px;border:1px solid var(--line);
  background:rgba(44,44,44,.15);
  -webkit-backdrop-filter:blur(40px);backdrop-filter:blur(40px);box-shadow:var(--fsh);}
.f-bar .mic{margin-left:auto;width:32px;height:32px;border-radius:50%;flex:none;
  background:linear-gradient(to top,#cfdef6 20%,#fafafa 80%);}
/* the home indicator — on-SCREEN iOS content, not bezel */
.home-ind{position:relative;z-index:2;width:140px;height:5px;border-radius:3px;
  background:color-mix(in srgb,var(--ink) 28%,transparent);margin:0 auto 8px;flex:none;}
/* ⚑ LOOPING CONVERSATION with CLIMB (s5f, Juan — "always show messages coming through: each starts
   at the bottom near the text box and climbs up as more arrive, then subtly loops"). Each beat starts
   COLLAPSED (max-height:0, no space) so the bottom-anchored thread grows from the composer up — as the
   JS loop (index.html) reveals beats one by one, the stack physically climbs. gap→margin so collapsed
   beats add zero space (gap would leave 8px per hidden beat). After the last beat it holds, resets, and
   repeats; pauses off-screen (masa motion rule). No JS / reduced-motion → all beats simply visible. */
/* ⚑ SEAMLESS SCROLLING CONVERSATION — the CSS moved to the shared mock.css (.mock-scroll, s5h) so the
   hero thread and the device mocks share one behaviour; index.html now links mock.css too. The hero
   thread opts in via mocks.js (adds .mock-scroll + .loop). */

/* ---- section scaffolding ---- */
.sec{padding:0 0 var(--sp-section);}
/* kicker → Outfit too (same call as .eyebrow, Jul 17 s5) */
.k{font-family:var(--f-body);font-weight:500;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--teal-d);margin:0 0 16px;}
.sec h2{font-size:clamp(26px,3.4vw,36px);margin:0 0 24px;}
.center{text-align:center;}
.center .k{text-align:center;}

/* proof: product-as-hero (real client screenshot) */
/* ⚑ MEDIA GLOW (Juan, Jul 17 s5 — "every piece of media should have that light/glow effect
   like flask"): flask halos its framed media with a soft lit-from-behind bloom. masa's take
   is the same spotlight recipe used by .ambient — a faint cool-white lift + one warm mango
   breath — rendered as a layered box-shadow so it's iOS-cheap (no filter/backdrop, unlike a
   real bloom). --glow is shared by every standalone media block (.live, .who .face). */
:root{--media-glow:0 18px 80px -24px rgba(255,140,66,.16),0 0 56px -12px rgba(207,222,246,.07);}
.live{max-width:600px;margin:0 auto;border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;
  background:var(--panel);box-shadow:var(--lift),var(--media-glow);}
/* ⚑ gap:14px + flex:none on the dots + a min-width:0 wrapping label (Juan, Jul 17 s5 —
   "the in-progress indicator overlaps the traffic lights on mobile"): space-between with a
   long uppercase label and no gap let the label collide with the dots on a narrow phone.
   The dots never shrink; the label keeps its distance and wraps/right-aligns if it must. */
.live .cbar{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:12px 16px;
  border-bottom:1px solid var(--line);}
.live .dots{display:flex;gap:6px;flex:none;}
.live .dots i{width:10px;height:10px;border-radius:50%;background:var(--line);display:block;}
.live .lv{display:flex;align-items:center;gap:8px;min-width:0;flex-wrap:wrap;justify-content:flex-end;
  text-align:right;font-family:ui-monospace,Menlo,monospace;font-size:11px;
  letter-spacing:.04em;text-transform:uppercase;color:var(--soft);}
/* the live-pulse DOT goes mango (Juan, Jul 17 late) — the label text stays gray */
.pulse{width:8px;height:8px;border-radius:50%;background:var(--chip);position:relative;}
.pulse::after{content:"";position:absolute;inset:-4px;border-radius:50%;border:2px solid var(--chip);
  opacity:.5;animation:ping 1.9s ease-out infinite;}
@keyframes ping{0%{transform:scale(.6);opacity:.6}100%{transform:scale(1.7);opacity:0}}
.live img{width:100%;height:auto;}
.cap{text-align:center;font-size:13.5px;color:var(--soft);margin:16px auto 0;max-width:46ch;}
.cap b{color:var(--indigo);font-weight:640;}

/* why: three calm lines */
.line{display:flex;align-items:flex-start;gap:16px;padding:24px 0;border-top:1px solid var(--line);}
.why .line:last-child{border-bottom:1px solid var(--line);}
.line .mini{width:34px;height:32px;border-radius:var(--r-dough);position:relative;flex:none;margin-top:3px;}
.line .mini::before,.line .mini::after{content:"";position:absolute;top:42%;width:7px;height:7px;
  border-radius:50%;background:var(--cream);}
.line .mini::before{left:24%;}.line .mini::after{right:24%;}
.line h3{font-family:var(--f-disp);font-weight:600;font-size:19px;letter-spacing:-.02em;
  text-transform:lowercase;margin:0 0 4px;}
.line p{font-size:14.5px;line-height:1.5;color:var(--soft);margin:0;max-width:60ch;}

/* warm proof: editorial image + text (Masienda pattern) */
.who{display:grid;grid-template-columns:.8fr 1.2fr;gap:34px;align-items:center;}
.who .face{border-radius:var(--r-card);overflow:hidden;border:0;aspect-ratio:1/1;box-shadow:0 18px 80px -24px rgba(146,220,229,.20),0 0 46px -12px rgba(146,220,229,.10);}
.who .face img{width:100%;height:100%;object-fit:cover;}
.who p{margin:0 0 16px;font-size:16px;line-height:1.6;color:var(--ink);}
.who p:last-of-type{margin-bottom:0;}
.who .name{color:var(--coral);font-size:19px;margin-top:6px;}

/* plans — the STUDY's layout (Juan, Jul 17 2026 late): FOUR equal compact cards, bio in
   the grid (its 'start here' pill kept inside the card; the .starter strip is retired),
   full ratified bullets kept. 'most popular' = the study's subtle border-highlight + a
   quiet uppercase tag — NO ORANGE BORDER (Juan: remove regardless; the mango-select
   border is retired from plans). color-mix keeps the highlight theme-agnostic. */
.tiers{display:grid;grid-template-columns:1fr;gap:12px;}
@media(min-width:640px){.tiers{grid-template-columns:1fr 1fr;}}
@media(min-width:980px){.tiers{grid-template-columns:repeat(4,1fr);}}
.tier{position:relative;border:1px solid var(--line);background:var(--panel);border-radius:var(--r-card);
  padding:18px;display:flex;flex-direction:column;gap:7px;box-shadow:var(--lift-sm);
  transition:border-color .25s var(--ease-out);}
.tier.on{border-color:color-mix(in srgb,var(--ink) 32%,transparent);}
.tier .badge{position:absolute;top:12px;right:12px;white-space:nowrap;
  font-size:8.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  background:var(--sunk);color:var(--ink);border-radius:var(--r-pill);padding:3px 7px;}
.tier .t{font-family:var(--f-disp);font-weight:600;font-size:15px;text-transform:lowercase;margin:0;}
.tier .p{font-family:var(--f-disp);font-weight:600;font-size:clamp(21px,2.8vw,25px);letter-spacing:-.025em;color:var(--indigo);margin:0;}
.tier .p small{font-size:13px;font-weight:600;color:var(--soft);letter-spacing:0;}
.tier ul{margin:2px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:6px;}
.tier li{font-size:14px;color:var(--soft);padding-left:14px;position:relative;line-height:1.45;}
.tier li::before{content:"";position:absolute;left:0;top:6px;width:5px;height:5px;border-radius:50%;background:var(--chip);opacity:.75;}

/* plans — reassurance */
.anchor{text-align:center;font-size:15px;color:var(--soft);max-width:52ch;margin:0 auto 24px;line-height:1.5;}
.reassure{text-align:center;font-size:13.5px;color:var(--soft);margin:16px 0 0;}

.ownnote{text-align:center;font-size:13.5px;color:var(--soft);margin:12px auto 0;max-width:52ch;line-height:1.5;}
.ownnote b{color:var(--indigo);}
.ownnote a{color:var(--indigo);text-decoration:none;}
.ownnote a:hover{text-decoration:underline;text-underline-offset:3px;}
.alt{margin-top:34px;}
.altk{text-align:center;font-size:11px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--soft);opacity:.8;margin:0 0 2px;}

/* faq */
.faq details{border-top:1px solid var(--line);}
.faq details:last-of-type{border-bottom:1px solid var(--line);}
.faq summary{cursor:pointer;list-style:none;padding:18px 34px 18px 0;position:relative;
  font-family:var(--f-disp);font-weight:600;font-size:16px;letter-spacing:-.01em;
  text-transform:lowercase;color:var(--ink);}
.faq summary::-webkit-details-marker{display:none;}
.faq summary::after{content:"+";position:absolute;right:4px;top:15px;font-size:22px;font-weight:400;
  color:var(--indigo);transition:transform var(--t-micro) var(--ease-out);}
.faq details[open] summary::after{transform:rotate(45deg);}
.faq .a{padding:0 0 20px;font-size:14.5px;line-height:1.6;color:var(--soft);max-width:64ch;}
/* ⚑ s5 — FAQ SMOOTH COLLAPSE, take 3 (Juan: "still stutters — web-search it"). Researched
   Jul 17 2026: animating `grid-template-rows:0fr→1fr` on ::details-content is a KNOWN iOS
   Safari jank source (the fr-track re-sizes every frame). WebKit 18.4's own note + the
   accordion community converge on the reliable fix: drive the height with the Web Animations
   API in JS (the faqAccordion() block in each page's script), keeping <details> open through
   the close animation. So the CSS animation is REMOVED here to avoid fighting the JS; native
   <details> is the fail-open fallback (instant toggle, content always visible, never hidden). */
.faq details .a{min-height:0;}

/* close */
/* ⚑ CLOSE HORIZON (Jul 17 2026 closeout, Juan's go-ahead) — one AI-generated ILLUSTRATIVE
   atmosphere: a warm masa-dough ridge fading into the ground, placed UNDER the close copy
   as a horizon band (never behind text — contrast stays untouched; the ground stays flat
   per the visual-collection verdict, this is contained imagery like flask's frames).
   Edge-faded by mask; dark-theme only (a dark plate on the light ground would read as a
   blob). Asset: close-masa-texture.webp — AI-generated, labeled at the markup. */
.close-amb{max-width:860px;margin:34px auto -26px;pointer-events:none;}
.close-amb img{width:100%;height:auto;display:block;opacity:.85;
  -webkit-mask-image:radial-gradient(ellipse 68% 90% at 50% 60%,#000 38%,transparent 76%);
  mask-image:radial-gradient(ellipse 68% 90% at 50% 60%,#000 38%,transparent 76%);}
:root[data-theme="light"] .close-amb{display:none;}
.close{text-align:center;padding:0 0 var(--sp-6);}
.close h2{font-size:clamp(28px,4.2vw,46px);margin:0 0 24px;}
.close .sig{margin-top:24px;}
footer{border-top:1px solid var(--line);margin-top:40px;padding:24px 0 60px;text-align:center;
  font-size:13px;color:var(--soft);}
footer a{color:var(--soft);text-decoration:underline;margin:0 9px;}

/* ---- LINEAR-STYLE BLUR-INTO-FOCUS REVEAL (s5m, Jul 17 2026) — replaces the scroll-timeline
   .reveal, which used animation-timeline:view() and so NEVER fired on iOS Safari (Juan's phone).
   Now IntersectionObserver-driven (inline script), per-child STAGGERED: each direct child lifts +
   un-blurs + fades in, delayed by --i (Linear's cascade). iOS-cheap: transform/opacity/one blur.
   FAIL-OPEN: the hidden start state is gated on html.js AND :not(.in); the script guarantees .in
   (via IO, or immediately when reduced-motion / no IntersectionObserver / a throw), so no-JS keeps
   everything visible. ---- */
@media (prefers-reduced-motion:no-preference){
  html.js .reveal>*{transition:opacity .6s var(--ease-out),transform .6s var(--ease-out),filter .6s var(--ease-out);
    transition-delay:calc(var(--i,0) * 55ms);}
  html.js .reveal:not(.in)>*{opacity:0;transform:translateY(16px);filter:blur(8px);}
  /* ⚑ s5n — THE HERO ITSELF reveals: the copy blur-fades in ON LOAD (Juan: "reveal the hero
     when the page loads"), staggered like a section; the phone mockup is a SEPARATE reveal that
     fires on scroll-in (Juan: "reveal the mockup at a certain scroll point, like the sections").
     Same fail-open contract as .reveal (script adds .in; reduced-motion / no-JS = visible). */
  html.js .hero-copy>*{transition:opacity .7s var(--ease-out),transform .7s var(--ease-out),filter .7s var(--ease-out);
    transition-delay:calc(var(--i,0) * 60ms);}
  html.js .hero-copy:not(.in)>*{opacity:0;transform:translateY(16px);filter:blur(8px);}
  html.js .phone-wrap{transition:opacity .8s var(--ease-out),transform .8s var(--ease-out),filter .8s var(--ease-out);}
  html.js .phone-wrap:not(.in){opacity:0;transform:translateY(26px);filter:blur(10px);}
}

/* ---- reduced motion: kill all non-essential movement ---- */
@media (prefers-reduced-motion:reduce){
  *{scroll-behavior:auto !important;}
  .dough,.eye,.eye .ball,.btn,.themebtn{transition:none !important;}
  .pulse::after{animation:none;}
  .reveal{opacity:1 !important;transform:none !important;}
}

/* ---- responsive ---- */
@media (max-width:780px){
  .shell{padding:0 22px;}
  /* ⚑ s5r — more breathing room between the hero copy/trust chips and the phone mock (Juan;
     8pt scale). 16→40px so the mock reads as its own beat, not crowding the chips. */
  .hero{grid-template-columns:1fr;gap:var(--sp-7);padding:40px 0 var(--sp-section-sm);}
  .who{grid-template-columns:1fr;gap:22px;}
  .who .face{max-width:220px;}
}

/* native cross-document page transitions (EN<->ES), progressive — reduced-motion-gated
   like every other animation on the site */
@media (prefers-reduced-motion: no-preference){
  @view-transition{navigation:auto;}
}
/* study register: plain (italic retired with the old card), flex:1 so bullets share a
   baseline across the row and bio's pill sits at its card's foot */
.tier .bf{font-size:15px;color:var(--soft);margin:0;line-height:1.5;flex:1;}
/* how-it-works: numbered steps on a panel band — deliberately distinct from the why-lines */
.steps{background:var(--panel);border:0;border-radius:var(--r-card);padding:32px;}
.srow{display:grid;grid-template-columns:repeat(4,1fr);gap:24px;margin-top:16px;}
@media(max-width:980px){.srow{grid-template-columns:repeat(2,1fr);}}
@media(max-width:560px){.srow{grid-template-columns:1fr;}}
.step .num{display:flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:50%;background:var(--element);color:#ececee;font-family:var(--f-disp);font-weight:600;font-size:15px;margin-bottom:12px;} /* flask element fill (Jul 17 late) */
.step h3{font-family:var(--f-disp);font-weight:600;font-size:16px;margin:0 0 6px;text-transform:lowercase;}
.step p{font-size:13.5px;color:var(--soft);line-height:1.5;margin:0;}
/* ⚑ breathing room above the panel (Juan, Jul 17 s5 — "how it works is too close to the
   voice-note section"): #talk clips its lower arc to padding-bottom:8px, leaving a 0px gap
   to this band. A top margin restores the section rhythm without un-clipping the knot.
   On the 8pt scale (s5 spacing pass): 48 above / 40 below. */
.steps{margin-top:var(--sp-8);margin-bottom:var(--sp-7);}

/* ---- THE KNOT (study r17/r18, ported Jul 17 2026) — flask's stream-curve, masa's story.
   One SVG path loops on itself mid-page; the client's raw spoken ramble rides it as a
   <textPath> and streams through the tangle: messy speech in (the .vn voice pill at the
   left end) → structure out (the deliverable card at the right end). Words-only, like
   flask: no visible path stroke. aria-hidden — the section's real words are the h2 + sub.
   Motion: flask LOOPS it (SMIL); masa's no-loops rule says a one-shot forward pass on
   arrival instead (the r18 autoplay JS on the index pages — rAF, latches done, pauses
   off-screen; reduced-motion pins a readable static offset; no JS = static text). */
/* ⚑ r21 desktop layout (Juan: "it's supposed to go BEHIND the waveform and the blocks in
   its same section" — measured flask: the streaming text is dim BACKGROUND texture, the
   composer + card are solid FOREGROUND that occlude it). So: the loop is narrower and
   z-BEHIND (z:1, dimmer); the voice pill and the deliverable card sit ON the loop (z:2,
   solid fills already occlude) so the words visibly pass behind them; the section clips so
   the loop's lower arc never spills into HOW-IT-WORKS. */
#talk{overflow:hidden;padding-bottom:8px;}
.talk-wrap{position:relative;max-width:720px;margin:14px auto 0;}
.knot{width:100%;height:auto;display:block;position:relative;z-index:1;
  /* ⚑ r23 — edge FADE (Juan: "start/end of the note should fade behind the knot, not leak
     out the edges"). A horizontal mask fades the streaming text into the ground at both
     sides so it dissolves instead of hard-cutting at the section edge — flask does this. */
  /* ⚑ s5j — TIGHTER CONTAINMENT (Juan: "no letters leaking out the sides; the stream should come out
     of the voice note's right and into the post block's left"). Fade in later / out earlier so no stray
     words touch the section edges — on desktop this lands the fade-in ~ the voice note's right and the
     fade-out ~ the card's left (the solid pill/card then occlude the rest); on mobile it just keeps the
     text off both edges. */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,transparent 15%,#000 31%,#000 69%,transparent 85%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,transparent 15%,#000 31%,#000 69%,transparent 85%,transparent 100%);}
/* ⚑ r22 — FULL WHITE (Juan + flask measured: flask's stream is rgb(250,250,250), not dimmed).
   The r21 62% was a wrong shortcut for "behind" — flask keeps it bright and lets the SOLID
   pill/card (opaque var(--panel), z:2) OCCLUDE it. So: text bright at z:1, blocks opaque at
   z:2 sitting ON the loop path → the white words visibly pass BEHIND them. */
.knot text{font-size:92px;fill:var(--ink);opacity:.95;font-weight:500;
  font-family:var(--f-disp);letter-spacing:-.01em;}
.knot-pill{position:absolute;left:6%;bottom:14%;z-index:2;}
/* ⚑ s5l — OCCLUDER (Juan: "the g/y descenders peek out of the voice note"). A ground-coloured block
   behind the pill (extending left + below it) hides the stream's overshoots around the pill, so the
   text only ever appears emerging from its RIGHT edge. Desktop only (the pill is hidden ≤700px). */
.knot-pill::before{content:"";position:absolute;inset:-18px 0 -22px -60%;background:var(--g);
  border-radius:24px;z-index:-1;}
/* ⚑ s5k — card dropped to meet the stream's end (Juan: "the end should enter the LEFT side of the
   block"). At top:50% the up-curving tail passed just BELOW the card; ~62% lands the card's left edge
   where the stream arrives, so the words read as entering it (the solid card then occludes the rest). */
.knot-card{position:absolute;right:1%;top:62%;transform:translateY(-50%);width:235px;text-align:left;z-index:2;}
@media(max-width:700px){
  .talk-wrap{max-width:none;width:100vw;margin-left:50%;transform:translateX(-50%);}
  .knot text{opacity:.95;}
  .knot-pill{display:none;}
  .knot-card{position:static;transform:none;width:auto;max-width:270px;margin:12px auto 0;}
}
/* the voice pill — masa's PRIMARY lane (capture/README), drawn as the site draws voice
   notes: plain fill + hairline (never glass on content), the same indigo play control
   indigo play control (the phone mock's .fvn runs the study's light-gradient control —
   that one lives inside the frame's own material system). */
.vn{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:18px;
  border-bottom-right-radius:6px;background:var(--panel);border:1px solid var(--line);
  box-shadow:var(--lift-sm);}
.vn .play{width:24px;height:24px;border-radius:50%;flex:none;background:var(--indigo);
  display:grid;place-items:center;}
.vn .play::after{content:"";border-left:7px solid var(--cream);border-top:4.5px solid transparent;
  border-bottom:4.5px solid transparent;margin-left:2px;}
.vn .wave{display:flex;align-items:center;gap:2px;height:16px;}
.vn .wave i{width:2px;border-radius:1px;background:var(--soft);display:block;}
.vn .len{font-size:12px;color:var(--soft);font-variant-numeric:tabular-nums;}

/* ---- THE SPACE strip (study r13/3b, ported Jul 17 2026) — the portal, sold as
   ownership. Three cards echoing what the real product renders (a post kit · a script
   that opens in a filming view · the full-res vault); every string on them is one the
   product genuinely renders (portal.js / script-view.js). CSS mock, aria-hidden, plain
   fills, zero blur. Replaces the second .reassure line in plans (same copy, now a
   section that SHOWS it). .sp-pill is namespaced — threads.html already owns `.pill`. */
.space-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:6px;}
@media(max-width:760px){.space-grid{grid-template-columns:1fr;}}
/* ⚑ GLOW BELONGS TO THE MEDIA, NOT THE CARD (s5d, Juan — "the space card glows even though the
   card isn't media; the glow should stay on the media within the card"). So the card itself only
   carries its elevation shadow; the warm glow moves onto .sp-thumb (the actual image) below and
   stays contained inside the card. This also fixes the knot's "saturday's post" text card, which
   is the same .sp-card class and was glowing with no media at all. */
.sp-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:14px;display:flex;flex-direction:column;gap:10px;box-shadow:var(--lift-sm);
  text-align:left;}
/* the media glows, contained within the card (s5d) — a soft warm bloom under the thumb only */
.sp-thumb{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:10px;
  box-shadow:0 6px 20px -8px rgba(255,140,66,.22);}
.sp-script{aspect-ratio:16/9;border-radius:10px;background:var(--sunk);
  display:flex;flex-direction:column;justify-content:center;gap:9px;padding:0 18px;}
.sp-line{height:8px;border-radius:4px;background:var(--line);display:block;}
.sp-files{aspect-ratio:16/9;border-radius:10px;background:var(--sunk);
  display:flex;align-items:center;justify-content:center;gap:10px;}
.sp-file{width:34px;height:44px;border-radius:6px;background:var(--line);display:block;}
.sp-meta{display:flex;align-items:center;justify-content:space-between;gap:8px;
  font-size:13.5px;color:var(--ink);}
.sp-meta .sp-pill{flex:none;}
.sp-pill{font-size:9.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:3px 8px;border-radius:var(--r-pill);background:var(--sunk);color:var(--soft);
  white-space:nowrap;}
.sp-sub{font-size:12.5px;color:var(--soft);margin:0;}
