:root{
  /* Ground is shared with the WebApp but separated from component paper, so
     site-wide contrast can move without changing the cards themselves. The
     app's dot grid does NOT come with it — that stays a product surface. */
  --page-ground:#dce8ef;
  --page-ground-deep:#cbdbe5;
  --page-ground-highlight:#edf4f7;
  --paper:#eaf3f8;
  --paper-2:#dceaf2;
  --paper-3:#c7dbe6;
  /* Where a card shows through instead of a photo. Lighter than paper, so a
     card never disappears into the page. App token: --paper-highlight. */
  --paper-lift:#f7fbfd;
  --ink:#090b0c;
  --muted:#5d696d;
  /* TWO line systems, and they are not interchangeable.
     --line is an EDITORIAL rule drawn straight on paper: section markers, the
     method and plan grids, the footer rule. It stays dark to be seen.
     --card-line is a hairline INSIDE a card, and it is a BEVEL, not ink: the
     app's --card-shade paired with the white --card-edge highlight below it.
     That pairing is why it reads as lighting rather than as a ruled line.
     NOTE the app's white --glass-border is the wrong token here. It works in
     the product because those cards float over a darker 3D workspace; on a
     light landing card a white hairline is invisible. The app's own answer for
     a light card surface is --card-shade, which is what this is. Dark mode
     flips it, because there white is the one that shows. */
  --line:rgba(9,11,12,.22);
  --soft-line:rgba(9,11,12,.1);
  --card-line:rgba(88,104,116,.10);
  --card-edge:inset 0 1px 0 rgba(255,255,255,.75);
  /* A THIRD line, for dividers drawn inside the header shell only.
     The shell has no border of its own (border:1px solid transparent); the
     edge you can see is --glass-glow's white top inset. So a divider inside it
     should be made of the same light, not of ink — dark --soft-line hairlines
     read as grey sticks laid on the glass rather than as seams in it.

     It is a GRADIENT, not a colour, because that is how the shell itself is
     lit: --glass-glow puts .75 white on the top edge only, then leaves the
     rest to a 24px rim bloom and a 60px ambient wash. A seam holding .75 for
     its whole height would be brighter at the bottom than the surface it sits
     in. So it starts at the top-edge value, falls away quickly, and settles at
     the ambient level the bottom of the pill actually carries — light catching
     the top of a seam rather than a drawn stripe.

     Being an image, it needs `border-image`, not `border-color`. Anything
     using it must set a border-width and a transparent border first.

     ONLY for the shell's frosted surface. The mobile dropdown keeps
     --soft-line: it drops to opaque --paper, where a white line is invisible.
     Same theme-aware-token-meets-different-surface trap as --plate-line. */
  --shell-line:linear-gradient(to bottom,
    rgba(255,255,255,.75) 0,
    rgba(255,255,255,.30) 22%,
    rgba(255,255,255,.14) 100%);
  /* A hairline drawn on the stencil plates. Those plates are #fff in BOTH
     themes, because the artwork needs a white ground, so this token is
     deliberately NOT overridden in the dark block. Give it a theme-aware
     value and it flips to light-on-white in dark mode and disappears. */
  --plate-line:rgba(9,11,12,.10);
  --accent:#f25565;
  --accent-hover:#ff6a78;
  --accent-rgb:242,85,101;
  /* Coral surfaces stay vivid; small coral ink needs a darker light-theme
     step to remain legible on the page ground and paper cards. */
  --accent-ink:#ba2c40;
  /* Fixed-black editorial slabs need the bright coral in both themes; coral
     surfaces need the same invariant dark ink. Name those jobs explicitly so
     neither is accidentally routed through a theme-dependent foreground. */
  --accent-on-dark:#f25565;
  --ink-on-coral:#090b0c;
  /* Copied verbatim from the WebApp's :root — same rule as --glass-glow in
     contract 47: change it in the app first, then re-copy, because these two
     surfaces are meant to be one material. --accent-deep remains a material
     step; --accent-ink above is the measured light-theme text step. --accent
     itself stays the colour of coral SURFACES such as .launchButton. */
  --accent-deep:#d63b4e;
  --accent-deep-rgb:214,59,78;
  /* The coral controls are lit pieces of the same frosted material as the
     Export tray. Saturated pools preserve the brand colour; the pale layer is
     only the thin light caught inside the surface. */
  --coral-frost-field:
    linear-gradient(to bottom,rgba(255,255,255,.22),rgba(255,255,255,.055) 22%,transparent 46%),
    radial-gradient(128% 150% at 50% 108%,transparent 52%,rgba(255,255,255,.08) 74%,rgba(255,255,255,.20) 100%),
    radial-gradient(118% 108% at 50% 124%,rgba(255,150,120,.62),rgba(255,124,132,.26) 46%,transparent 78%),
    radial-gradient(44% 150% at 74% 66%,rgba(255,138,112,.58),rgba(255,124,124,.24) 46%,transparent 80%),
    radial-gradient(40% 165% at 29% 44%,rgba(191,44,66,.72),rgba(191,44,66,.3) 48%,transparent 80%);
  --ease:cubic-bezier(.22,.61,.36,1);
  /* Hero field, behind the transparent renders, so the art stays reusable. */
  --hero-field:#c6d8dc;--hero-deep:#aec4c9;--hero-lift:#e5eff1;
  --white:#fbfdfd;
  /* ---- canonical design tokens: one shared language with the WebApp ----
     Radius is a single squircle scale (paired with corner-shape:squircle).
     Shadows collapse to two elevation steps. Controls share three heights. */
  --r-2xs:8px;   /* tags, chips, small insets, range tracks */
  --r-xs:12px;   /* thumbnails, tooltips, tight controls */
  --r-sm:16px;   /* inputs, small buttons */
  --r-md:22px;   /* standard buttons + controls, small cards */
  --r-lg:32px;   /* cards, popovers, mid figures */
  --r-xl:46px;   /* large shells: header, hero stage, section shells */
  --r-2xl:64px;  /* the largest editorial shells */
  --r-pill:999px;--r-round:50%; /* true circles */
  --shadow-soft:0 22px 48px -38px rgba(9,11,12,.48);  /* resting shells + controls */
  --shadow-lift:0 34px 80px -58px rgba(9,11,12,.55);  /* large / raised shells */
  --h-control-sm:40px; /* compact controls */
  --h-control:44px;    /* standard action height */
  --h-control-lg:52px; /* prominent CTAs */
  /* Typeset roles: display sizes remain editorial; these are the reading and
     interaction floors beneath them. */
  --type-kicker:11px;
  --type-caption:12px;
  --type-action:14px;
  --type-body-sm:14px;
  --type-body:16px;
  /* ---- THE MEASURE -------------------------------------------------------
     One centred content width for the whole page, the same 1322px shell the
     WebApp and the travelling header already use. Nothing on this page is
     full-bleed content: the dark and coral slabs still span the viewport, but
     what sits inside them stops at the measure.
     --bleed is the distance from the viewport edge in to the measure. The
     percentage inside it resolves at the point of use, against the containing
     block, so one token is correct for every full-width element.
     --bleed-slab is the same edge for a slab that already sits 14px in on its
     own margin, so its content lines up with everything else. The final CTA is
     the only one left since the signal band was retired. */
  /* ---- CARD GLASS: ported from the WebApp's .sideCard --------------------
     Frosted, borderless, no drop shadow. Definition comes from inner light
     rather than an outline: a bright top edge, a tight rim bloom and a broad
     ambient wash. Three stacked insets, because Lee found a single 34px blur
     read as a flat halo instead of something lit from within. These values are
     copied from the app on purpose, not re-tuned, so the two surfaces stay one
     material — change them there first.
     --glass-ink is the same material for cards sitting ON the dark bands,
     which need the dark recipe even while the page is in light mode. */
  --glass:rgba(255,255,255,.32);
  --glass-blur:blur(44px) saturate(1.5);
  /* What --glass + --glass-blur RESOLVE TO over flat --paper: paper through
     saturate(1.5), then --glass composited on top. For frosted surfaces that
     sit on plain paper with nothing behind them to reveal — there the blur
     renders this colour anyway, while still sampling (and dragging in)
     whatever neighbours fall inside its ~130px reach. See .faqList. */
  --glass-flat:#eef7fc;
  --glass-glow:inset 0 1px 0 rgba(255,255,255,.75),
               inset 0 0 24px rgba(255,255,255,.22),
               inset 0 0 60px rgba(255,255,255,.17);
  --glass-ink:rgba(24,25,22,.44);
  --glass-ink-glow:inset 0 1px 0 rgba(255,255,255,.14),inset 0 0 34px rgba(255,255,255,.05);
  --measure:1322px;
  --gutter:clamp(20px,3.35vw,54px);
  --bleed:max(var(--gutter),calc((100% - var(--measure)) / 2));
  --bleed-slab:max(var(--gutter),calc((100% - var(--measure)) / 2 - 14px));
  color-scheme:light;
}
[data-theme="dark"]{
  --page-ground:#343c40;
  --page-ground-deep:#2a3135;
  --page-ground-highlight:#434d52;
  --paper:#11120f;
  --paper-2:#0c0e0c;
  --paper-3:#292d2b;
  --paper-lift:#242a2d;
  --ink:#f1f4f0;
  --muted:#9ea6a1;
  --line:rgba(241,244,240,.26);
  --soft-line:rgba(241,244,240,.11);
  --card-line:rgba(255,255,245,.13);
  --card-edge:inset 0 1px 0 rgba(255,255,255,.14);
  /* Same shape, tracking the dark --glass-glow: .14 top edge falling to the
     .05 ambient wash. Dark mode was already close to right, since --soft-line
     is white-ish here, so this is a smaller correction than it is in light. */
  --shell-line:linear-gradient(to bottom,
    rgba(255,255,255,.14) 0,
    rgba(255,255,255,.08) 22%,
    rgba(255,255,255,.05) 100%);
  --white:#f8faf8;
  --accent-ink:#ff7d87;
  --hero-field:#2c363b;--hero-deep:#1d2529;--hero-lift:#3b474c;
  --glass:rgba(24,25,22,.44);
  --glass-flat:#141511;
  --glass-glow:inset 0 1px 0 rgba(255,255,255,.14),inset 0 0 34px rgba(255,255,255,.05);
  color-scheme:dark;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;background:var(--page-ground)}
body{margin:0;min-width:320px;overflow-x:hidden;background:var(--page-ground);color:var(--ink);font-family:Manrope,Arial,sans-serif;transition:background .2s,color .2s}
a{color:inherit;text-decoration:none}
button,input{font:inherit;color:inherit}
button{cursor:pointer}
img{display:block;max-width:100%}
svg{fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
:where(a,button,input,summary,[tabindex]):focus-visible{outline:2px solid currentColor;outline-offset:4px}
.mono{font-family:"Manrope",sans-serif;font-size:10px;line-height:1.35;letter-spacing:.08em;text-transform:uppercase}
/* The image captions stay on .mono — INTERACTIVE TOOLS, WEBAPP, EXPORT SHEET,
   CONSULT WITH YOUR ARTIST (Lee, 2026-08-05, matching ALL RIGHTS RESERVED on
   the body study). A sentence-case variant was tried and rejected: what made
   the old captions read as generic was the invented index and the slash
   ("EXPORT 041 / LEFT LEG"), not the uppercase. Removing the label's content
   problem does not require changing its typographic voice, and the mono
   micro-label is a deliberate part of the page's editorial language. */
.skipLink{position:fixed;z-index:200;left:12px;top:-60px;padding:10px 14px;background:var(--accent);color:var(--ink-on-coral);font:500 11px "Manrope",sans-serif}.skipLink:focus{top:12px}
.sectionFrame{width:100%;padding-inline:var(--bleed)}

.siteHeader{position:fixed;z-index:100;left:0;right:0;top:0;height:64px;padding:0 clamp(16px,2.1vw,34px);display:grid;grid-template-columns:1fr auto 1fr;align-items:center;border-bottom:1px solid var(--line);background:color-mix(in srgb,var(--paper) 92%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
.siteBrand{display:inline-flex;align-items:center;gap:10px;width:max-content;color:var(--ink);font:500 17px Noto Sans,Arial,sans-serif;letter-spacing:-.025em}
/* The header mark is inline `.stensylsIcon` (see index.html) and inherits the
   `color` set above through `fill:currentColor`, so light/dark and the coral
   hover below are one rule instead of a separate `filter:invert(1)` fighting
   a separate hover colour. The footer's is still a flat `<img>`, unaffected —
   its own dark-mode invert stays put.
   Do NOT add `transform:translateZ(0)` or any other compositor-layer hack
   here. One was added 2026-08-12 as a guessed fix for a reported hover jump on
   the WebApp's matching icon, copied here pre-emptively, and reverted the same
   day: it forces this icon onto its own GPU-rasterised layer, which visibly
   blurs its fine interlocking lines into a heavier mark AT REST — worse than
   the problem it was guessing at, and never confirmed to fix that problem
   either. See the equivalent note on `.stensylsIcon` in stensyls-app.html. */
/* `stroke:none` is LOAD-BEARING, not tidiness. This page sets a global
   `svg{fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round}`
   for its line icons. Inlining the brand mark put it under that rule, and
   overriding only `fill` left the 1.6-unit stroke painting an outline AROUND
   the filled shape. In a 100-unit viewBox drawn at 31px that is 0.496px of
   extra width, half of it outside the outline, so every edge gained 0.248px
   and the mark rendered 29.7% heavier than the WebApp's — measured by ink
   coverage on a rasterised comparison, and exactly the "thicker logo" Lee
   reported. The rounded joins softened its corners on top of that.
   This mark is a FILLED shape. It must never be stroked. */
.siteBrand .stensylsIcon{display:block;flex:none;width:31px;height:31px;fill:currentColor;stroke:none}
/* The footer's own unconditional invert (its background is always near-black,
   independent of site theme) lives with the rest of `.siteFooter`, below. */
.siteHeader .siteBrand>span{transform:translateY(-2px)}
/* NO NUMBERS IN THE NAV. They were 01–05 in coral, and the method list in
   section 02 is also 01–05 in coral — so "Export" was labelled 04 in the
   header and 05 in the list, on screen at the same time, because this header
   travels. Two numbering systems disagreeing about the same word.

   Only one of them was ever real. The method list is a genuine sequence: you
   choose a body before you build a stack, and its heading says FIVE MOVES, so
   the count is the argument. A nav is not a sequence — nothing stops you
   clicking Access first — so its numbers were the invented-index convention
   that DESIGN_OBSERVATIONS bans by name (the one that took STUDY 014 with it).
   The list keeps its numbers and is now the only numbered thing on the page.

   Cells are centred and 10px narrower, which is exactly the number plus its
   gap: the tabs stay uniform, sized to the words instead of to something no
   longer there. Narrowing costs nothing structurally — .siteNav is the `auto`
   middle column of a fixed-width shell, so the space returns to the 1fr
   columns either side rather than resizing the header. */
/* The only divided group in the shell, and only between its items — `a+a`,
   so there's no leading rule before Why and no trailing one after Access.
   Every other seam in the header is gone (the actions cluster used to fence
   off @stensyls, the theme toggle and Launch from each other and from the
   nav). Bracketing the nav and then subdividing the actions made six lines
   carve the shell into cells it doesn't have; four seams inside one group
   read as a control, and everything else is free to sit on the glass. */
.siteNav{display:flex;align-self:stretch}
.siteNav a{min-width:96px;padding:0 18px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600}
/* border-image, because --shell-line is a gradient. Slice 1 takes a 1px
   column of the image for the left edge; the other three sides have zero
   width so nothing draws there. The transparent border underneath is the
   fallback and is deliberately invisible — a seam is not worth a grey stick
   if border-image ever fails. */
.siteNav a+a{border-left:1px solid transparent;border-image:var(--shell-line) 1}
.headerActions{justify-self:end;display:flex;align-items:center;height:100%}
.headerActions>*{height:100%;border:0;background:transparent}
.instagramLink{padding:0 16px;display:grid;place-items:center;font:500 10px "Manrope",sans-serif;text-transform:uppercase}
.themeToggle{position:relative;isolation:isolate;width:52px;display:grid;place-items:center}
/* The masked pill that used to appear behind this toggle on hover is gone with
   the rest of the header's hover plates — see the block below the nav. */
.themeToggle svg{position:relative;z-index:1;grid-area:1/1;width:17px;height:17px}
.sunIcon,[data-theme="dark"] .moonIcon{opacity:0;transform:scale(.7)}
.moonIcon,[data-theme="dark"] .sunIcon{opacity:1;transform:scale(1)}
.themeToggle svg{transition:opacity .18s,transform .18s,filter .18s var(--ease)}
.launchButton{
  position:relative;isolation:isolate;overflow:hidden;padding:0 19px;
  display:flex;align-items:center;gap:18px;background:var(--accent);color:var(--ink-on-coral)!important;
  font-size:11px;font-weight:800;text-transform:uppercase;
  box-shadow:inset 0 1px 0 rgba(255,226,222,.72),inset 0 -14px 24px -18px rgba(179,34,57,.72)
}
.launchButton::before{
  content:"";position:absolute;z-index:0;inset:0;border-radius:inherit;pointer-events:none;
  background:var(--coral-frost-field);opacity:.7;transition:opacity .2s var(--ease)
}
.launchButton::after{
  content:"";position:absolute;z-index:1;left:7%;right:7%;bottom:-68%;height:124%;border-radius:50%;pointer-events:none;
  background:radial-gradient(ellipse at 50% 68%,rgba(255,255,255,.9),rgba(255,221,216,.62) 25%,rgba(255,157,145,.25) 49%,transparent 73%);
  filter:blur(7px);mix-blend-mode:screen;opacity:0;transform:translateY(30%) scale(.68);transform-origin:50% 100%
}
.launchButtonLabel,.launchButtonArrow{position:relative;z-index:2}
/* THIS ARROW IS THE REFERENCE. The WebApp's Download button is matched to it,
   never the other way round. It is the character ↗ (U+2197), confirmed via
   Safari's Font inspector to render in Manrope itself (not a fallback font).
   Manrope does not render ↘ (U+2198) the same way, so #exportGoBtn i in
   stensyls-app.html reuses this same ↗ character and rotates it 90deg with
   CSS rather than using a different glyph — guarantees an identical shape
   by construction instead of hoping two codepoints match. */
.launchButtonArrow{font-size:16px;display:inline-block;transition:transform .24s cubic-bezier(.2,.85,.25,1)}
.launchButton:hover .launchButtonArrow,.launchButton:focus-visible .launchButtonArrow{transform:translate(3px,-3px)}
/* ---- Header hover: coral, no halo (2026-08-13 `[LEE]`, was 2026-08-12) ----
   Every header cell used to light a grey rectangle behind it. On a shell whose
   argument is that it is one continuous piece of glass, that drew boxes the
   layout does not have — the same reasoning as the seams in the note above the
   nav, one step further in. The label or icon just goes coral now; the soft
   `text-shadow`/`drop-shadow` halo this rule used to add on top was tried and
   dropped (Lee, 2026-08-13) — plain coral reads cleaner than coral-plus-glow.
   Coral ink is `--accent-ink`, matching `.quietLink` — the contrast-safe
   language for an interactive word going live.
   `.launchButton` keeps its coral fill and bloom; it is the CTA, not a quiet
   cell. The WebApp header carries the same language — keep the two in step. */
.siteNav a,.instagramLink,.siteBrand,.themeToggle,.menuButton{
  transition:color .18s var(--ease);
}
/* Both themes use --accent-ink, matching the WebApp header exactly. The brand
   lock-up is in this list, so it hovers like every other cell rather than
   having a treatment of its own. */
.siteNav a:hover,.siteNav a:focus-visible,
.instagramLink:hover,.instagramLink:focus-visible,
.siteHeader .siteBrand:hover,.siteHeader .siteBrand:focus-visible,
.themeToggle:hover,.themeToggle:focus-visible,
.menuButton:hover,.menuButton:focus-visible{
  background:transparent;color:var(--accent-ink);
}
[data-theme="dark"] .siteNav a:hover,[data-theme="dark"] .siteNav a:focus-visible,
[data-theme="dark"] .instagramLink:hover,[data-theme="dark"] .instagramLink:focus-visible,
[data-theme="dark"] .siteHeader .siteBrand:hover,[data-theme="dark"] .siteHeader .siteBrand:focus-visible,
[data-theme="dark"] .themeToggle:hover,[data-theme="dark"] .themeToggle:focus-visible,
[data-theme="dark"] .menuButton:hover,[data-theme="dark"] .menuButton:focus-visible{
  color:var(--accent-ink);
}
/* `svg{stroke:currentColor}` is global on this page and the burger's bars are
   `background:currentColor`, so the `color` above already carries the brand
   MARK and menu icon too — no separate icon rule needed now the halo is
   gone. The brand mark goes coral together with the wordmark (2026-08-12): it
   used to be an external `<img>` that `color` could not reach, so only the
   wordmark lit up beside a black-or-white mark that held still — see the note
   on `.siteBrand .stensylsIcon` above for why it is inline `currentColor` SVG
   now, the same fix already proven on the WebApp's `#brandChip`. */
.launchButton:hover,.launchButton:focus-visible{
  outline:none;background:var(--accent-hover);
  box-shadow:0 14px 30px -20px rgba(var(--accent-rgb),.86),inset 0 1px 0 rgba(255,236,232,.88),inset 0 -16px 26px -18px rgba(179,34,57,.64)
}
.launchButton:hover::before,.launchButton:focus-visible::before{opacity:.92}
.launchButton:hover::after,.launchButton:focus-visible::after{animation:coralControlBloom .86s cubic-bezier(.16,1,.3,1) both}
@keyframes coralControlBloom{
  0%{opacity:0;transform:translateY(30%) scale(.68)}
  48%{opacity:.92;transform:translateY(-1%) scale(1.04)}
  100%{opacity:.34;transform:translateY(-9%) scale(1.14)}
}
/* No border. It used to carry a !important border-right purely to beat the
   .headerActions>* border rule, and since it is the last child that line
   landed on the shell's own inner right edge, doubling it. */
.menuButton{display:none;width:52px;place-items:center}
.menuButton span{grid-area:1/1;width:18px;height:1px;background:currentColor;transition:transform .2s,filter .18s var(--ease)}.menuButton span:first-child{transform:translateY(-4px)}.menuButton span:last-child{transform:translateY(4px)}
.menuButton[aria-expanded="true"] span:first-child{transform:rotate(45deg)}.menuButton[aria-expanded="true"] span:last-child{transform:rotate(-45deg)}

/* ---- 00 / HERO: the pointer reveal ----------------------------------------
   Ported from experiment 06. Two stacked renders sharing one frame; the
   tattooed one is revealed through a radial mask that follows the pointer, so
   the visitor uncovers the composition rather than being shown it. The gesture
   is the argument: a body is a whole arrangement, not a slot you drop one
   image into.

   THE MILLIMETRE SLIDER STAGE THAT FILLED THE RIGHT HALF IS GONE. PRODUCT.md
   is explicit and CONFIRMED that marketing must not lead with measurement, and
   the first thing a visitor touched on this page was a ruler. Reasoning in
   Landing_Page_Plan_2026-08-01.md section 1; one git revert away if that call
   turns out to be wrong. */
.hero{
  --reveal-x:66%;--reveal-y:43%;
  --reveal-radius:clamp(130px,15vw,250px);
  --reveal-diameter:clamp(260px,30vw,500px);
  /* Where the reveal starts, as a percentage of the hero width. The render is
     right-anchored and the paper veil above it only clears around the halfway
     mark, so hunting for ink to the left of this found nothing and put the ring
     over the headline instead. landing.js reads this and gates on it. */
  --reveal-zone:52%;
  position:relative;min-height:max(760px,100svh);overflow:hidden;
  border-bottom:1px solid var(--line);
}
.heroMedia{position:absolute;z-index:0;inset:0;overflow:hidden;background:radial-gradient(circle at 78% 32%,var(--hero-lift),transparent 44%),linear-gradient(112deg,var(--page-ground) 0%,var(--hero-field) 58%,var(--hero-deep) 100%)}
/* Holds the type legible over the render without dimming the body itself. */
.heroMedia::after{content:"";position:absolute;z-index:2;inset:0;pointer-events:none;background:linear-gradient(90deg,color-mix(in srgb,var(--page-ground) 88%,transparent) 0%,color-mix(in srgb,var(--page-ground) 72%,transparent) 27%,color-mix(in srgb,var(--page-ground) 22%,transparent) 47%,transparent 63%),linear-gradient(180deg,color-mix(in srgb,var(--page-ground) 10%,transparent),transparent 26%,transparent 74%,color-mix(in srgb,var(--page-ground) 16%,transparent))}
.heroVisualLayer{position:absolute;z-index:0;inset:0}
.heroRender{position:absolute;z-index:0;top:0;right:0;width:auto;height:100%;max-width:none;object-fit:contain;object-position:right center;user-select:none;-webkit-user-drag:none;filter:contrast(1.025) saturate(.94)}
[data-theme="dark"] .heroRender{filter:brightness(1.28) contrast(.94) saturate(.88)}
.heroRenderInk{
  z-index:1;opacity:0;transition:opacity .3s var(--ease);
  -webkit-mask-image:radial-gradient(circle var(--reveal-radius) at var(--reveal-x) var(--reveal-y),#000 0%,#000 52%,rgba(0,0,0,.88) 66%,rgba(0,0,0,.42) 80%,transparent 100%);
  mask-image:radial-gradient(circle var(--reveal-radius) at var(--reveal-x) var(--reveal-y),#000 0%,#000 52%,rgba(0,0,0,.88) 66%,rgba(0,0,0,.42) 80%,transparent 100%);
}
.hero.is-revealing .heroRenderInk{opacity:1}
.focusRing{position:absolute;z-index:3;left:var(--reveal-x);top:var(--reveal-y);width:var(--reveal-diameter);height:var(--reveal-diameter);border:1px solid rgba(var(--accent-rgb),.34);border-radius:var(--r-round);opacity:0;transform:translate(-50%,-50%);pointer-events:none;transition:opacity .15s ease}
.focusRing::after{content:"";position:absolute;left:50%;top:50%;width:5px;height:5px;border-radius:var(--r-round);background:var(--accent);transform:translate(-50%,-50%)}
.hero.is-revealing .focusRing{opacity:1}
/* The copy column must not eat the pointer, or the reveal dies wherever the
   text sits. Only the interactive children take pointer events back. */
/* The hero copy sits in the same centred 1322px measure the WebApp uses for its
   shell, rather than being pushed against the viewport edge. On a wide screen
   that moves it a few hundred pixels inward, so the type sits with the render
   instead of running away from it. Ported from experiment 06's .wrap. */
.heroInner{position:relative;z-index:2;width:min(var(--measure),calc(100vw - 48px));margin:0 auto;min-height:100svh;padding:clamp(40px,6vh,72px) 0 136px;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:24px;pointer-events:none}
.heroInner a,.heroInner button{pointer-events:auto}
/* The two hero actions share a row. The 34px that used to sit on .quietLink
   moves here, so the pair keeps the same distance from the lead paragraph
   that the single link had. */
.heroActions{display:flex;flex-wrap:wrap;align-items:baseline;gap:clamp(26px,3vw,44px);margin-top:34px}
.heroActions .quietLink{margin-top:0}
/* A button, not a link: it opens a lightbox rather than going anywhere, so
   the only work here is undoing the UA control styling that .quietLink (an
   anchor rule everywhere else) never had to think about. */
/* align-items:center rather than the group's baseline. ↗ is drawn around the
   baseline and belongs on it; an outline triangle ▷ is a closed shape that
   reads from its own middle, so baseline-aligning it hangs it high against
   the word. Centring is scoped here, not changed on .quietLink, because every
   other quiet link uses the arrow and is correct as it is. */
.demoOpen{padding:0;border:0;background:none;color:inherit;font-family:inherit;align-items:center;cursor:pointer}
/* Outline, not solid: ▷ (U+25B7), so it carries the same hairline weight as
   the ↗ beside it instead of putting a filled mass in a row of thin strokes.
   Near the arrow's own size for the same reason — the size drop it had while
   it was solid was compensating for ink that is no longer there.
   The arrow nudges up and to the right because ↗ points that way. A play
   triangle does not, so this one nudges along its own axis.

   The 2px drop is optical, on top of the centring. ▷ comes from a fallback
   font (Manrope has no geometric shapes block), so its glyph box carries that
   font's own vertical metrics, not Manrope's — box-centred still reads high
   against the word. It is `top`, never a transform: the hover nudge owns
   transform on this element, and a translate here would be wiped by it. */
.demoOpen i{position:relative;top:2px;font-size:13px}
.demoOpen:hover i{transform:translateX(3px)}
.heroTitle{margin:0;max-width:14ch;font-size:clamp(52px,8.8vw,126px);font-weight:400;line-height:.86;letter-spacing:-.05em;text-transform:uppercase}
.heroTitle span{display:block}
.heroTitle b{font-weight:800}
.heroLead{max-width:46ch;margin:0;color:var(--muted);font-size:clamp(14px,1.3vw,16px);line-height:1.65}
.heroTruth{margin:4px 0 0;font-size:13px;line-height:1.55}
.heroTruth em{color:var(--accent-ink);font-style:normal;font-weight:700}


/* Once they have found it, stop asking. */

[data-theme="dark"] .studyBody{filter:invert(.87) contrast(.78);mix-blend-mode:screen;opacity:.82}

.sectionFrame[id],.method[id],.access[id]{scroll-margin-top:88px}
.thesis{padding-bottom:clamp(90px,10vw,160px)}
.thesisGrid{padding:clamp(70px,9vw,145px) 0;display:grid;grid-template-columns:1.65fr .75fr;gap:8vw;align-items:end}
.thesisGrid h2,.methodLead h2,.studiesLead h2,.accessLead h2,.faqGrid>h2{margin:0;font-size:clamp(52px,7.7vw,124px);font-weight:400;line-height:.87;letter-spacing:-.075em;text-wrap:balance}
.thesisCopy{max-width:430px}.thesisCopy>p{margin:0 0 24px;font-size:14px;line-height:1.7}.thesisCopy>p:first-child{font-size:22px;font-weight:600;line-height:1.35}.thesisCopy>p:nth-child(2){color:var(--muted)}.thesisCopy>p:last-child{margin-bottom:0}
/* Editorial actions are quiet links: no rule above, no rule below, just a
   dashed rule that draws in from the left. Sentence case, per the settled rule
   that every control on both surfaces is sentence case. Three links share this
   language: the hero and thesis actions, Make an Export Sheet, and Follow
   @stensyls, which gave up its border-block pair to take it.

   THE DASH IS THE PLACEMENT RING, STRAIGHTENED. `#gizmo .ring ellipse` in the
   WebApp is stroke-dasharray:2 6 at 1.45 width with round caps. A round cap
   adds half the stroke width to each end of every dash, so 2/6 RENDERS as
   about 3.5 on / 4.5 off. The values below match that rendered rhythm, not the
   raw dasharray: copying 2/6 literally reads visibly tighter than the app.

   The rule is wiped in with clip-path, never scaleX. Scaling a dashed pattern
   stretches every dash from nothing instead of drawing the line, which is the
   same dash-unit trap the gizmo hit. */
.quietLink,.actionLink,.honestyBlock a{
  position:relative;display:inline-flex;align-items:baseline;gap:10px;
  font-size:14px;font-weight:700;line-height:1;letter-spacing:-.012em
}
.quietLink{margin-top:34px}
.quietLink i,.actionLink i,.honestyBlock a i,.accessTable article>a i,.finalCta>a i{font-size:15px;font-style:normal;transition:transform .24s cubic-bezier(.2,.85,.25,1)}
.quietLink::after,.actionLink::after,.honestyBlock a::after,.accessTable article>a::after,.finalCta>a::after{
  content:"";position:absolute;left:0;right:0;bottom:-9px;height:1.5px;
  background:repeating-linear-gradient(90deg,currentColor 0 3.5px,transparent 3.5px 8px);
  clip-path:inset(0 100% 0 0);
  transition:clip-path .34s cubic-bezier(.2,.85,.25,1)
}
.quietLink:hover,.quietLink:focus-visible,
.actionLink:hover,.actionLink:focus-visible,
.honestyBlock a:hover,.honestyBlock a:focus-visible{color:var(--accent-ink)}
.quietLink:hover::after,.quietLink:focus-visible::after,
.actionLink:hover::after,.actionLink:focus-visible::after,
.honestyBlock a:hover::after,.honestyBlock a:focus-visible::after,
.accessTable article>a:hover::after,.accessTable article>a:focus-visible::after,
.finalCta>a:hover::after,.finalCta>a:focus-visible::after{clip-path:inset(0)}
.quietLink:hover i,.actionLink:hover i,.honestyBlock a:hover i,.accessTable article>a:hover i,.finalCta>a:hover i{transform:translate(3px,-3px)}
.quietLink:focus-visible,.actionLink:focus-visible,.honestyBlock a:focus-visible,.accessTable article>a:focus-visible,.finalCta>a:focus-visible{outline:2px solid var(--accent-ink);outline-offset:7px}
/* The only access CTA belongs to the available prototype. The future note is
   intentionally non-actionable, so nothing in it can be mistaken for an
   upgrade, waitlist or checkout path. */
.accessTable article>a:hover,.accessTable article>a:focus-visible{color:var(--accent-on-dark)}
.accessTable article>a:focus-visible{outline-color:var(--accent-on-dark)}
.finalCta>a:hover,.finalCta>a:focus-visible{color:var(--ink-on-coral)}
.finalCta>a:focus-visible{outline-color:var(--ink-on-coral)}
/* Two separate cards, not one slab split by a hairline — same arrangement as
   the section 03 studies below, which is where the 14px gap comes from. The
   card identity (radius, lifted paper, rim glow, clipping) therefore lives on
   each .bodyStudy rather than on the container; .bodyStudies is now only a
   grid. The old divider between them is gone with it: the gap does that job,
   and a border on a rounded card would cut across its own corner. */
.bodyStudies{display:grid;grid-template-columns:1.35fr .65fr;gap:14px}
.bodyStudy{min-width:0}
/* Both studies run the full height of the card now. The photo used to be
   dropped 90px with its own shorter clamp — an editorial inset that left a
   band of empty card above it. Sharing one height means it fills to the top
   and both footers still line up on the same row. The border-top went with
   the margin: it existed to give the inset image an edge inside that gap,
   and at the very top of the card it would just be a line across the
   rounded corner. */
.studyImage{position:relative;height:clamp(480px,55vw,760px);overflow:hidden;background:var(--paper-2)}
.studyBody{position:absolute;left:50%;top:50%;width:118%;height:118%;max-width:none;object-fit:cover;transform:translate(-50%,-50%);filter:contrast(1.12) saturate(.3)}
.studyBody.studyBackExport,.studyBody.studyStuckStencils{width:100%;height:100%;object-fit:cover;transform:translate(-50%,-50%);mix-blend-mode:normal;opacity:1}
.studyBody.studyBackExport{object-position:center 48%;filter:saturate(.58) contrast(1.06)}
/* NOTE, because this wasted a round trip: the photo is 1122x1728 (ratio .649)
   and its frame is narrower than that at every viewport (~.55–.57), so cover
   scales it to fit the HEIGHT and crops off the SIDES only — there is no
   vertical overflow, so the second value here does nothing; only the first
   (horizontal) value moves anything. 30% pulls the crop window left of centre
   — toward the raised arm — cropping more off the hair on the right instead
   of splitting the loss evenly between both sides. */
.studyBody.studyStuckStencils{object-position:30% center;filter:contrast(1.03) saturate(1)}
[data-theme="dark"] .studyBody.studyBackExport{filter:grayscale(.35) brightness(.68) contrast(1.05);mix-blend-mode:normal;opacity:1}
[data-theme="dark"] .studyBody.studyStuckStencils{filter:brightness(.72) contrast(1.04) saturate(.94);mix-blend-mode:normal;opacity:1}
/* ---- The live study has to look live -------------------------------------
   Sat beside a photograph, a real 3D plan reads as a second photograph. The
   overlays below are the WebApp's own instruments rather than new landing
   decoration: a status tag whose dot reports real state, a live centimetre
   readout, the coral dotted placement ring, and one cue that names the
   gesture and retires for good the moment the user makes it.
   Corner chrome is inset 28px because the shell's 64px corner radius clips
   anything closer: at 18px the tag's own corner sits outside the arc. */
.studyInteractive{
  isolation:isolate;background:#fff;
  --study-chip:color-mix(in srgb,#fbfdfd 86%,transparent);
}
[data-theme="dark"] .studyInteractive{
  background:#111414;
  --study-chip:color-mix(in srgb,#0d0f0f 82%,transparent);
}
.studyInteractiveFallback{z-index:0;transition:opacity .42s ease}
.studyInteractiveViewport{position:absolute;z-index:1;inset:0;display:block;width:100%;height:100%;opacity:0;outline:0;touch-action:pan-y pinch-zoom;transition:opacity .42s ease;filter:grayscale(1) contrast(1.02)}
[data-theme="dark"] .studyInteractiveViewport{filter:grayscale(1) brightness(1.08) contrast(1.04)}
.studyInteractive.is-ready .studyInteractiveViewport{opacity:1}
.studyInteractive.is-ready .studyInteractiveFallback{opacity:0}
/* The WebGL study is one keyboard surface, not eight invisible controls.
   Focus frames the canvas; the existing placement ring shows which piece the
   arrows will move. Keeping the outline inside the rounded card prevents it
   from being clipped by .studyImage's overflow while still making the focus
   arrival unmistakable. */
.studyInteractiveViewport:focus-visible{outline:2px solid var(--accent-ink);outline-offset:-5px}

/* Placement ring. Same dotted coral boundary the WebApp draws around a
   selected stencil, in the panel's own pixel space: the SVG carries no
   viewBox, so one user unit is one CSS pixel and the JS can write raw
   coordinates. */
.studyRing{position:absolute;z-index:3;inset:0;width:100%;height:100%;opacity:0;pointer-events:none;transition:opacity .22s ease}
.studyRing circle{fill:none;stroke:var(--accent);stroke-width:1.4;stroke-linecap:round;stroke-dasharray:1.4 7}
.studyInteractive.is-instrument .studyRing{opacity:1}

/* STUDY 014 / LIVE and the 8 PIECES readout are both gone — one pill in each
   top corner was too much chip. What's left, the drag cue, moved up into the
   tag's old top:28px/left:28px slot instead of sitting bottom-centred, so the
   card now carries exactly one piece of corner chrome instead of three.
   studyPulse is kept: it used to animate the small solid dot inside the
   retired tag, and now animates the new dotted-circle glyph below instead, so
   "flashes/glows" is the same keyframe, just pointed at a different element. */
@keyframes studyPulse{0%,100%{opacity:.4;transform:scale(.82)}50%{opacity:1;transform:scale(1)}}

/* The cue names the gesture and nothing else. Once the gesture happens it is
   gone permanently: an instruction that survives the action it describes is
   just noise. It's the only chip left on the card now, so it can afford to
   read as a real call-out rather than a quiet corner label. */
.studyInteractiveStatus{
  position:absolute;z-index:5;top:28px;left:28px;padding:13px 20px 13px 15px;
  display:inline-flex;align-items:center;gap:12px;
  border:1px solid var(--line);border-radius:var(--r-pill);background:var(--study-chip);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  color:var(--ink);font-size:11.5px;letter-spacing:.09em;white-space:nowrap;
  transition:opacity .32s ease,transform .32s ease;
  /* It sits over the manikin. A cue that blocks the gesture it is asking for
     would be its own bug. */
  pointer-events:none;
}
/* A dotted ring standing in for the old crosshair-arrows glyph, carrying the
   pulse the removed STUDY 014 / LIVE dot used to have. A zero-length dash
   with a round cap draws as a plain circle rather than a capsule, so this
   is actual dots, not short dashes. Spacing is exactly π (circumference
   2·π·8 over 16 dots = π), which divides the ring with no remainder — the
   last dot lands exactly where the first one starts, so there's no seam or
   overlap where the pattern wraps. Sized up now that it's the card's one
   cue instead of one of three, with a soft accent glow riding the same
   pulse so the animation reads from across the card, not just up close. */
.studyCueGlyph{width:22px;height:22px;flex:none;filter:drop-shadow(0 0 5px color-mix(in srgb,var(--accent) 55%,transparent));animation:studyPulse 2.4s ease-in-out infinite}
.studyCueGlyph circle{fill:none;stroke:var(--accent-ink);stroke-width:2.1;stroke-linecap:round;stroke-dasharray:0 3.1416}
/* This used to freeze mid-pulse whenever a piece was actively being dragged
   or demonstrated (is-instrument), matching how the old solid dot froze
   solid while "live". But freezing and un-freezing a CSS animation restarts
   it from 0%, which reads as a stutter — a visible stop-and-lurch every time
   a drag begins or ends. The cue isn't a live/idle indicator any more, it's
   just a beacon saying "this is draggable", so it keeps pulsing throughout. */
.studyInteractive:not(.is-ready) .studyCueGlyph,.studyInteractive.is-failed .studyCueGlyph{display:none}
/* Dismissing on touch used to slide sideways off a horizontally centred
   position (translateX(-50%) plus a downward nudge); now that the pill is
   corner-anchored instead of centred, that transform would yank it off to
   one side. It just lifts and fades in place. */
.studyInteractive.is-touched .studyInteractiveStatus{opacity:0;transform:translateY(-6px);pointer-events:none}
/* Keyboard placement reuses the one existing cue rather than adding another
   toolbar to a deliberately quiet landing study. It outranks is-touched while
   focus is inside the canvas, then the pointer-first surface returns unchanged
   when Escape or Tab leaves. The right edge gives longer keyboard copy a real
   wrapping boundary at narrow widths. */
.studyInteractive.is-keyboard .studyInteractiveStatus{
  top:auto;bottom:28px;width:max-content;max-width:calc(100% - 56px);white-space:normal;line-height:1.35;
  opacity:1;transform:none
}
.studyInteractive.is-keyboard .studyCueGlyph{animation:none;opacity:1;transform:scale(1)}
.bodyStudy footer{min-height:54px;padding:12px 14px;display:flex;align-items:center;justify-content:space-between;gap:15px;border-top:1px solid var(--card-line)}
/* Sits inside a 54px caption strip alongside a plain mono label on the card
   next to it — "ALL RIGHTS RESERVED" in the card beside it — so it matches
   that label's weight and colour exactly (regular weight, --ink, not
   --muted) rather than the quietLink family's normal bold 14px. Only the
   hover state (colour, dashed underline, arrow nudge) still comes from the
   shared quietLink rules, so it still reads as clickable without looking
   different from the plain caption at rest. */
.studyOpenLink{margin:0 0 0 auto;gap:8px;font-family:"Manrope",sans-serif;font-size:10px;font-weight:400;letter-spacing:.08em;text-transform:uppercase;color:var(--ink)}
.studyOpenLink i{font-size:12px}
.studyOpenLink::after{bottom:-6px}

.method{padding-bottom:clamp(90px,10vw,160px);background:#090b0c;color:#eff3f0}
.methodLead,.studiesLead,.accessLead{padding:clamp(70px,9vw,145px) 0;display:grid;grid-template-columns:1.65fr .75fr;gap:8vw;align-items:end}.methodLead p,.studiesLead p,.accessLead p{max-width:430px;margin:0;color:#aab1ad;font-size:15px;line-height:1.7}
.studiesLead p{color:var(--muted)}
.methodList{list-style:none;margin:0 0 110px;padding:0;border-top:1px solid rgba(255,255,255,.2)}.methodList li{min-height:122px;padding:24px 0;display:grid;grid-template-columns:80px 1fr 360px;align-items:center;gap:22px;border-bottom:1px solid rgba(255,255,255,.2)}.methodList>li>span{color:var(--accent-on-dark)}.methodList h3{margin:0;font-size:clamp(25px,3.2vw,52px);line-height:1;font-weight:700;letter-spacing:-.05em}.methodList p{margin:0;color:#aab1ad;font-size:12px;line-height:1.55}
.instrument{height:720px;display:grid;grid-template-columns:220px 1fr 240px;grid-template-rows:46px 1fr 54px;border:1px solid rgba(255,255,255,.28);background:#dce7ea;color:#0a0c0d;overflow:hidden}

/* No closing gap at all, which no other section does, because no other section
   ends on a rule. honestyBlock's 3px bottom border already IS the boundary;
   anything after it is not a section end, it is the opening of section 04, and
   that space belongs to .planLead alone. Trimming this to 6vw (2026-08-05) was
   the right instinct applied to the wrong half — two paddings still stacked,
   and 6vw + 9vw was still around 210px of nothing between a hard black rule
   and a 100px headline. One value now owns the gap, and it lives with the
   thing it opens. Lee flagged it again 2026-08-07; if it needs tuning, tune
   .planLead's top padding and leave this at zero. */
.studies{padding-bottom:0}.studiesLead{grid-template-columns:1.65fr .75fr}.artRail{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);border-left:1px solid var(--line)}.artRail figure{margin:0;min-width:0}.artRail figure>div{height:clamp(280px,28vw,440px);padding:12%;display:grid;place-items:center;background:#fff}.artRail img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply}.artRail figcaption{min-height:72px;padding:12px;display:flex;flex-direction:column;justify-content:space-between;gap:8px}/* Not coral. Accent has to report live state (DESIGN_OBSERVATIONS, hard
   rule) and "FINE LINE" is a style category, not a state — the same
   reasoning that took the coral off the Export Sheet captions. These now
   match ALL RIGHTS RESERVED on the body study: plain mono in page ink. */
.artRail figcaption span{color:inherit}.artRail figcaption b{font-size:12px}
/* The HOUSE RULE / 000 label is gone; the title takes its column too. Same
   1.65fr/.75fr split as thesisGrid, methodLead, studiesLead and accessLead, so
   this reads as the same two-column rhythm as the rest of the page rather than
   a one-off. h3 is the first child so it lands in column 1 by auto-placement;
   p and a are both pinned to column 2 (below), stacking there in source order
   since neither sets a row. */
/* The closing rule mirrors the opening one exactly: same 3px var(--ink), same
   36px clearance, so the block reads as bracketed rather than just topped —
   this is the block's own space and stays put. Everything past that rule now
   belongs to section 04: .studies has no closing padding and .planLead's top
   owns the whole gap. */
.honestyBlock{margin-top:100px;padding:36px 0;display:grid;grid-template-columns:1.65fr .75fr;gap:5vw;border-top:3px solid var(--ink);border-bottom:3px solid var(--ink)}.honestyBlock h3{margin:0;font-size:clamp(28px,4vw,64px);line-height:.96;letter-spacing:-.055em}.honestyBlock p{grid-column:2;margin:0;color:var(--muted);font-size:13px;line-height:1.7}

.access{padding-bottom:clamp(90px,10vw,160px);background:#090b0c;color:#eff3f0}
.accessTable{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(280px,.7fr);gap:clamp(36px,5vw,72px);align-items:stretch}
.accessTable article{padding:34px}
.accessTable article header{display:flex;align-items:flex-start;justify-content:space-between;gap:28px}
.currentAccess header>div{min-width:0}
.currentAccess h3,.futureAccess h3{margin:0;font-weight:800;line-height:.95;letter-spacing:-.04em}
.currentAccess h3{font-size:clamp(28px,3vw,46px)}
.currentAccess header p{margin:9px 0 0;color:#aab1ad;font-size:14px;line-height:1.45}
.accessTable header strong{flex:none;font-size:clamp(52px,6vw,92px);line-height:.8;letter-spacing:-.08em;text-align:right}
.accessTable header small{display:block;max-width:150px;margin-top:12px;font:500 12px/1.35 "Manrope",sans-serif;letter-spacing:0;text-align:right}
.accessTable ul{list-style:none;margin:58px 0 38px;padding:0}
.accessTable li{padding:14px 0;border-top:1px solid rgba(255,255,255,.18);font-size:12px}
.accessTable li:before{content:"+";margin-right:12px;color:var(--accent-on-dark)}
.accessTable article>a{position:relative;margin-top:16px;display:inline-flex;align-items:baseline;gap:10px;color:inherit;text-align:left;text-transform:uppercase;font:700 10px "Manrope",sans-serif}
.futureAccess{align-self:center;max-width:520px;padding:clamp(20px,3vw,42px) 0}
.futureAccess h3{max-width:430px;font-size:clamp(34px,4.4vw,68px)}
.futureAccess>p{max-width:58ch;margin:24px 0 0;color:#aab1ad;font-size:16px;line-height:1.68}
.futureAccess>p+p{margin-top:16px}
.futureAccess .futureStatus{margin-top:34px;color:#eff3f0;font-size:12px;line-height:1.5}

.faq{padding-bottom:clamp(90px,10vw,160px)}.faqGrid{padding-top:clamp(70px,9vw,145px);display:grid;grid-template-columns:.8fr 1.2fr;gap:8vw}.faqList summary{position:relative;list-style:none;padding:27px 46px 27px 0;cursor:pointer;font-size:14px;font-weight:700}.faqList summary::-webkit-details-marker{display:none}.faqList summary i:before,.faqList summary i:after{content:"";position:absolute;right:4px;top:50%;width:16px;height:1px;background:var(--ink);transition:transform .2s}.faqList summary i:after{transform:rotate(90deg)}.faqList:not([data-accordion-js]) details[open] summary i:after{transform:none}.faqList[data-accordion-js] details.faqOpen summary i:after{transform:none}.faqList p{max-width:640px;margin:0;padding:0 50px 27px 0;color:var(--muted);font-size:13px;line-height:1.7}

/* h2 and the launch link share one row, bottom-aligned — the same "headline +
   secondary content, align-items:end" pattern as thesisGrid/methodLead/
   studiesLead/accessLead elsewhere on this page. They land correctly through
   plain auto-placement (h2 first, into column 1; the link next, into the only
   open cell, column 2), so neither needs an explicit grid-column. The link's
   column is auto-sized to its own content, not a fixed fraction, so it never
   fights h2 for width at any viewport — h2 always gets whatever is left.
   Below 760px they go back to stacking (see media query), because the
   headline's mobile size assumes the full row to itself.

   REMOVED 2026-08-05 `[LEE]`: the meta line above the headline (STENSYLS /
   2026 · PLACEMENT IS THE TASTE) and its divider. This used to be a second
   grid row of its own — deleting it collapsed grid-template-rows from
   `auto 1fr` to a single `1fr`, which is the one line that mattered here.
   With only one explicit row, h2 and the link both land in it and align-
   items:end still bottom-anchors them against the card's min-height, exactly
   as before; there is no longer a top row to pin a meta line against, but
   nothing else depended on it. The mobile override loses the matching
   three-row template for the same reason — see the media query. */
.finalCta{min-height:72svh;padding:24px var(--bleed-slab) 48px;display:grid;grid-template-rows:1fr;grid-template-columns:1fr auto;column-gap:40px;align-items:end;background:var(--accent);color:var(--ink-on-coral)}.finalCta h2{margin:0;font-size:clamp(78px,13vw,210px);font-weight:400;line-height:.72;letter-spacing:-.095em}.finalCta>a{position:relative;justify-self:end;display:inline-flex;align-items:baseline;gap:12px;font-size:13px;font-weight:800;text-transform:uppercase}.finalCta>a i{font-size:18px;font-style:normal}
/* .siteFooter doesn't set align-items, so its grid default (stretch) makes
   the siteBrand link's own box as tall as the row — the row's height is set
   by the nav's 3 stacked lines, not by the brand mark. .siteBrand then
   centers the logo+wordmark WITHIN that stretched box (align-items:center is
   correct there for the header, where the whole bar is meant to centre it),
   so in the footer the logo drifts down to the row's vertical middle while
   the plain-text <p> beside it just sits at the top like text normally does.
   align-self:start stops the anchor's box from stretching in the first
   place, so it sizes to its own content and its top lines up with the
   paragraph's top — scoped to the footer only, the header still wants its
   centered behaviour. */
/* THREE GROUPS, NOT ONE LIST. The policies briefly shared a column grid with
   Why/How/Plan/Export/Pricing, which made five places to go and three legal
   documents look like eight of the same thing. They now sit in the base bar
   under the rule the footer already had, which is what makes them read as
   administrative rather than as more navigation, and the product nav is back
   to the two columns it had before. The parent studio link sits under the
   mark, because that is provenance and belongs with the brand rather than
   with either group. The one rule in here is the base bar's, and it is the
   footer's own structure rather than a divider dropped between two blocks of
   copy: it was already there under the copyright line. */
.siteFooter{min-height:300px;padding:45px var(--bleed) 28px;display:grid;grid-template-columns:1fr 1fr auto;grid-template-rows:1fr auto;gap:32px;background:#090b0c;color:#eff3f0}
.siteFooter .footerBrandGroup{align-self:start;display:grid;justify-items:start;gap:6px}
.siteFooter .siteBrand{align-self:start;color:inherit}
.siteFooter .siteBrand img{filter:invert(1)}
.siteFooter p{margin:0;color:#9ea6a1;font-size:11px;line-height:1.7}
/* It is not inside a <nav>, so it does not inherit the footer links' 44px
   control box from the typeset pass. Stated here instead, with the group gap
   reduced to match, or the link's own box would push it away from the mark. */
.siteFooter .footerParent{display:inline-flex;align-items:center;gap:7px;min-height:var(--h-control);color:#9ea6a1}
.siteFooter .footerParent i{font-style:normal;font-size:1.15em;transition:transform .24s cubic-bezier(.2,.85,.25,1)}
.siteFooter .footerParent:hover i,.siteFooter .footerParent:focus-visible i{transform:translate(2px,-2px)}
.siteFooter nav{font:500 10px "Manrope",sans-serif;text-transform:uppercase}
/* ONE SET OF COLUMNS FOR BOTH GROUPS.
   The base bar is a SUBGRID of the footer, so its third column is literally the
   track the navigation sits in rather than a second auto track that happens to
   come out about the same width. Both groups then divide that one track into
   three equal columns with the same gap, so Terms lands under Why by
   construction and cannot drift when a label changes length. The grey rule
   still spans the whole footer, because it belongs to the bar and not to
   either group. */
.siteFooter .footerNav,.siteFooter .footerLegal{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:15px 50px}
.siteFooter .footerBase{grid-column:1/-1;padding-top:20px;border-top:1px solid rgba(255,255,255,.18);display:grid;grid-template-columns:subgrid;gap:32px;align-items:center}
.siteFooter .footerBase small{grid-column:1/3}
.siteFooter .footerLegal{grid-column:3;color:#7e8782}
/* Subgrid is in every browser this site supports. The fallback is two lines and
   exists so a missing implementation gives the previous right-aligned bar
   rather than a single collapsed column. */
@supports not (grid-template-columns:subgrid){
  .siteFooter .footerBase{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:4px 32px}
  .siteFooter .footerLegal{display:flex;flex-wrap:wrap;gap:4px 26px}
}
/* The page you are already on, marked in the surface-aware coral the fixed
   black bands use. --accent-ink is the page-ground token and is the wrong one
   here; this band is black in both themes. */
.siteFooter .footerLegal a[aria-current]{color:var(--accent-on-dark)}
.siteFooter .siteBrand:hover,.siteFooter .siteBrand:focus-visible,.siteFooter nav a:hover,.siteFooter nav a:focus-visible,.siteFooter .footerParent:hover,.siteFooter .footerParent:focus-visible{color:var(--accent-on-dark)}
.siteFooter small{color:#7e8782}

/* The landing page now borrows the product's frosted superellipse language.
   Large outer shells curve; their internal editorial grid stays disciplined.

   CARD EDGES ARE LIGHT, NOT DARK. No card carries a grey outline or a drop
   shadow any more; each one is a frosted panel defined by the inner glow
   above. Two cases:
   - Cards whose content is type or controls take the glow directly.
   - Cards filled edge to edge with a photo cannot show frost through an
     opaque image, and an inset shadow on the card paints UNDER that image, so
     those carry the identical glow on a ::after overlay instead. Same edge,
     drawn on top of the picture.
   Internal hairlines stay. They are the editorial grid, not card edges. */
.siteHeader{
  left:12px;right:12px;top:12px;height:64px;
  border:1px solid transparent;
  border-radius:var(--r-md);
  background:var(--glass);
  backdrop-filter:var(--glass-blur);
  -webkit-backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-glow);
}
.launchButton{height:calc(100% - 12px);margin:6px;border-radius:var(--r-pill)}
.hero{padding-top:0}
.bodyStudy,.instrument,.artRail,.faqList{
  overflow:hidden;border-radius:var(--r-xl);border:0;box-shadow:none;
}
.instrument{border:0;border-radius:var(--r-xl)}
.accessTable{border:0}
.accessTable article{
  border:0;border-radius:var(--r-xl);overflow:hidden;
  background:var(--glass-ink);box-shadow:var(--glass-ink-glow);
}
/* THIS CARD HAS NO BACKDROP-FILTER, AND MUST NOT GET ONE BACK.
   It was the source of a dark smear up the card's right edge that shimmered
   whenever Lee scrolled, 2026-08-05. Two wrong diagnoses first, both recorded
   because the reasoning is the useful part:

   1. "corner-shape:squircle clipping against the inset glow." Chrome-only
      behaviour. Lee tests in SAFARI, which does not implement corner-shape at
      all, so the whole @supports block was never running for him. Fixing it
      could not have done anything.
   2. "Safari samples the blur past its own clip edge." Plausible, and the
      oversized-::before trick is the real remedy for that bug — but it did
      not move this one either, which is what finally ruled the theory out.

   THE ACTUAL CAUSE, from source order rather than guesswork: in index.html
   the <h2> "WHAT THIS ISN'T." is written BEFORE .faqList, and both sit in the
   same grid row (h2 in column 2, the list in column 1, both placed
   explicitly). Painting first makes the headline part of this card's
   BACKDROP. blur(44px) samples meaningfully out to roughly 130px, and the
   column gap is 8vw — about 120px at Lee's viewport. So the card was reaching
   past its own edge and blurring a wall of near-black display type into
   itself. Worst at the top-right because that is where WHAT, the heaviest
   black mass, sits closest, fading down the edge as the letterforms thin out.
   The shimmer is Safari re-sampling that backdrop every frame while scrolling:
   subpixel offsets change which pixels get pulled in.

   The fix is not to fight the sampling. It is that the blur had no job here.
   Frost on this page is FUNCTIONAL — it exists so the manikin shows through
   and the workspace feels deeper (DESIGN_OBSERVATIONS is explicit). This card
   sits on flat component paper. Nothing is behind it to reveal, so the blur resolved
   to a flat colour anyway and its only other effect was the artifact.

   --glass-flat is that resolved colour, computed not eyeballed: --paper
   through saturate(1.5), then --glass composited over it. Light #eaf3f8 ->
   #eef7fc; dark #11120f -> #141511. The card renders identically and the bug
   is structurally impossible, because there is no longer a backdrop to
   sample. If a future card here genuinely needs to reveal something behind
   it, give it the blur AND move the headline after it in source order. */
/* align-self:start, or the card is taller than its own contents.
   .faqGrid never sets align-items, so it defaults to STRETCH, and the h2
   shares grid-row 1 with this card. At most desktop widths the headline wraps
   to three lines — clamp(52px,7.7vw,124px) at line-height .87, so roughly
   324px — while four FAQ rows come to about 292px. The card was being pulled
   up to the headline's height, and because its rows sit at the top, all ~30px
   of the surplus fell below the last one. Lee read that as the card being
   unbalanced, which it was: the space above the first row was the summary's
   own 27px padding, the space below the last was 27px plus whatever the
   headline happened to need that viewport.
   Sizing the card to its content makes it symmetric by construction (27px top
   and bottom, from the first and last summary's padding) and keeps it that way
   at every width, instead of breathing with the headline's line count.
   The top edge does not move; only the surplus below is trimmed. */
.faqList{align-self:start;border:0;background:var(--glass-flat)}
.faqList details{padding-inline:24px}
/* The questions sit further in than the answers, on purpose (Lee, 2026-08-05).
   The question is the row you read closed, so it is the only thing that has to
   hold its own against the card's edge — and this card's corner radius is 46px
   (--r-xl), so at the shared 24px inset the first and last questions began
   inside the curve rather than clear of it. 24px more brings them to 48px,
   just past where the corner finishes, and the same figure reads as deliberate
   on the straight rows between.
   Answers keep the 24px: they are only ever visible when a row is open, with
   the question directly above them setting the eye's left margin, so pushing
   them out too would just cost the open row its hierarchy. */
.faqList summary{padding-left:24px}

/* WHERE A CARD SHOWS ITSELF. Most of a photo card is picture, so the only
   places the material is visible are the caption and footer strips. Those were
   sitting at page-paper colour, which is why the card vanished into the
   background. They now carry the lifted paper and the app's top edge-light, so
   the card reads as a card exactly where there is something to read. */
.bodyStudy{background:var(--paper-lift)}
.bodyStudy footer,.uiStudies figcaption,.artRail figcaption,.exportStory figcaption,.continuityPair figcaption{
  background:var(--paper-lift);box-shadow:var(--card-edge)
}
/* DARK DOUBLES THE LINE. These strips carry two things at their top edge: a
   border-top in --card-line, and the --card-edge highlight one pixel below it.
   In light mode that is a bevel and reads as one edge, because the border is a
   cool shade and the highlight is white. In dark BOTH are light on dark, so
   they stack into a 2px band — most obvious over the near-black female study,
   where the line is the only thing separating image from strip. Keep the
   border, drop the highlight, and dark gets a single clean hairline.
   .artRail figcaption is deliberately absent: it has no border-top, so its
   highlight is its only line and must stay. */
[data-theme="dark"] .bodyStudy footer,
[data-theme="dark"] .uiStudies figcaption,
[data-theme="dark"] .exportStory figcaption,
[data-theme="dark"] .continuityPair figcaption{box-shadow:none}

/* The photo cards. inset:0 with an inherited radius, above the picture but
   below anything the card deliberately lets escape.

   .faqList rides along for a plainer reason than the photo cards: it just
   needs its glow on an overlay rather than as its own box-shadow, so the
   glow and the card's background stay independent. (It was added here while
   chasing a smear that turned out to be a backdrop-filter problem — see the
   note on .faqList itself. The overlay is harmless and consistent, so it
   stays, but it is not load-bearing.) */
.bodyStudy,.instrument,.artRail,.uiStudies figure,.continuityPair figure,.exportStory,.faqList{position:relative}
.bodyStudy{isolation:isolate}
.bodyStudy::after,.instrument::after,.artRail::after,
.uiStudies figure::after,.continuityPair figure::after,.exportStory::after,.faqList::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  border-radius:inherit;box-shadow:var(--glass-glow);
}
.bodyStudy::after{z-index:6}
/* Below .artDagger, which sits at 6 and is meant to cross its own cell. */
.artRail::after{z-index:5}
/* The rail gives up its perimeter and keeps the hairlines between cells. On
   desktop that is one row, so only the verticals survive. */
.artRail{border-top:0;border-left:0}
/* THE DIVIDER CROSSES TWO DIFFERENT SURFACES, so it cannot be one border on
   the cell. The top half is a white artwork plate in both themes; the bottom
   half is the caption strip, which does follow the theme. One theme-aware
   border on the cell meant that in dark mode the line went light and vanished
   against the white plate while still showing on the strip. Split it: the
   plate takes the fixed --plate-line, the strip takes --card-line. */
.artRail figure>div{border-right:1px solid var(--plate-line)}
.artRail figcaption{border-right:1px solid var(--card-line)}
.artRail figure:last-child>div,.artRail figure:last-child figcaption{border-right:0}
.finalCta{margin:14px;border-radius:var(--r-2xl);overflow:hidden}
@supports (corner-shape:squircle){
  .siteHeader,.bodyStudy,.demoFrame,
  .instrument,.artRail,.accessTable article,.faqList,.finalCta{
    corner-shape:squircle;
  }
  .siteHeader{border-radius:var(--r-lg)}
  .bodyStudy,.artRail,.faqList{border-radius:var(--r-2xl)}
  .instrument,.accessTable article{border-radius:var(--r-2xl)}
  .finalCta{border-radius:var(--r-2xl)}
  /* corner-shape does not inherit on its own, so the rim overlays would fall
     back to plain rounded corners and cut across the squircle. */
  .bodyStudy::after,.instrument::after,.artRail::after,
  .uiStudies figure::after,.continuityPair figure::after,.exportStory::after,.faqList::after{corner-shape:inherit}
}

/* ---- WATCH A DEMO -------------------------------------------------------
   A lightbox, not a page: the visitor comes back to the hero having just
   watched the tool work, which is where Launch is. Native <dialog> supplies
   the focus trap, the inert background and Escape, so landing.js only adds
   click-outside, the scroll lock and pausing the film.

   The frame keeps --glass-ink-glow over a true black video ground. The film's
   delivery file retains roughly 4% black capture rails on each side, so the
   1.885:1 frame and object-fit:cover crop those rails plus a small safety
   margin while keeping native video controls inside the visible box.

   NOTHING ANIMATES ON THE WAY OUT. A full-screen backdrop-filter layer that
   fades out re-blurs itself every frame and snaps at the end — the failure
   the WebApp's export dialog hit and had to be fixed with transition:none.
   The panel animates in; both it and the backdrop leave instantly. */
.demoDialog{
  width:min(1440px,calc(100vw - 24px),calc(190vh - 122px));
  width:min(1440px,calc(100vw - 24px),calc(190dvh - 122px));
  max-width:none;padding:0;
  border:0;background:transparent;overflow:visible
}
.demoDialog::backdrop{background:rgba(9,11,12,.66);backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px)}
.demoDialog[open]{animation:demoIn .3s cubic-bezier(.2,.85,.25,1)}
@keyframes demoIn{from{opacity:0;transform:translateY(10px) scale(.985)}to{opacity:1;transform:none}}
.demoFrame{
  position:relative;aspect-ratio:1.885/1;overflow:hidden;
  border-radius:var(--r-lg);
  background:#090b0c;
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-ink-glow);
  display:grid;place-items:center
}
.demoFilm{width:100%;height:100%;display:block;object-fit:cover;object-position:center;border:0;background:#090b0c}
.demoClose{
  margin:14px 0 0;padding:0;border:0;background:none;color:var(--white);
  font:700 13px "Manrope",sans-serif;letter-spacing:-.012em;cursor:pointer
}
.demoClose:hover,.demoClose:focus-visible{color:var(--accent-on-dark)}
.demoClose:focus-visible{outline:2px solid var(--accent-on-dark);outline-offset:7px}
body.isDemoOpen{overflow:hidden}

[data-reveal]{opacity:0;transform:translateY(14px);transition:opacity .4s ease,transform .4s cubic-bezier(.2,.85,.25,1)}[data-reveal].visible{opacity:1;transform:none}

@media(max-width:1100px){
  /* The dropdown is a stacked list, not a row of tabs, so its items go back
     to left-aligned — overriding the centring the horizontal nav took on when
     the index numbers were removed. */
  .siteHeader{grid-template-columns:1fr auto}.siteNav{display:none}.menuButton{display:grid}.siteNav.open{position:absolute;display:grid;left:0;right:0;top:64px;background:var(--paper)}.siteNav.open a{min-height:52px;justify-content:flex-start;border:0;border-bottom:1px solid var(--soft-line)}
  .heroTitle{font-size:clamp(58px,9vw,96px)}
  .thesisGrid,.methodLead,.studiesLead,.accessLead,.honestyBlock,.continuityLead{grid-template-columns:1fr .65fr;gap:5vw}.bodyStudies{grid-template-columns:1fr 1fr}.methodList li{grid-template-columns:60px 1fr 280px}
}
@media(max-width:760px){
  .siteHeader{height:58px}.siteBrand span{font-size:15px}.siteBrand .stensylsIcon{width:28px;height:28px}.instagramLink{display:none}.themeToggle,.menuButton{width:46px}.launchButton{padding:0 13px}.launchButtonArrow{display:none}.siteNav.open{top:58px}
  .hero{min-height:max(620px,100svh)}
  .heroInner{min-height:100svh;padding:34px 16px 112px;gap:20px}
  .heroTitle{max-width:none;font-size:14.4vw}
  
  .sectionFrame{padding-inline:16px}.thesisGrid,.methodLead,.studiesLead,.accessLead{padding:80px 0;grid-template-columns:1fr;gap:35px}.continuityLead{grid-template-columns:1fr;gap:28px}.thesisGrid h2,.methodLead h2,.studiesLead h2,.accessLead h2,.faqGrid>h2{font-size:15.4vw}.thesisCopy p:first-child{font-size:19px}
  .bodyStudies{grid-template-columns:1fr;gap:12px}.studyImage{height:520px}.bodyStudy footer{font-size:8px}
  .methodList{margin-bottom:72px}.methodList li{padding:25px 0;grid-template-columns:38px 1fr;gap:8px 14px}.methodList h3{font-size:27px}.methodList p{grid-column:2;max-width:420px}
  .artRail{grid-template-columns:1fr 1fr}.artRail figure>div{height:55vw}.artRail figcaption{min-height:62px}.honestyBlock{margin-top:72px;grid-template-columns:1fr;gap:25px}.honestyBlock a{grid-column:1;margin-top:0}
  .accessTable{grid-template-columns:1fr;gap:42px}.accessTable article{padding:26px 20px}.accessTable ul{margin-top:45px}.futureAccess{max-width:620px;padding:0 4px}.faqGrid{padding-top:80px;grid-template-columns:1fr;gap:50px}.faqList summary{font-size:13px}
  .finalCta{min-height:78svh;padding-inline:16px;grid-template-columns:1fr}.finalCta h2{font-size:22vw}.siteFooter{grid-template-columns:1fr;grid-template-rows:auto;min-height:0}.siteFooter .footerBase{grid-column:1;grid-template-columns:1fr;justify-items:start;gap:16px}.siteFooter .footerBase small{grid-column:1}.siteFooter .footerLegal{grid-column:1;width:100%}.siteFooter .footerNav,.siteFooter .footerLegal{gap:15px 16px}.siteFooter .footerNav{margin:25px 0}
}
/* The header drops the wordmark for room it genuinely does not have. The
   footer has the room, and dropping it there leaves the mark sitting directly
   above "A Layermade project", which reads as though the mark belongs to
   Layermade. */
@media(max-width:430px){.siteBrand span{display:none}.siteFooter .siteBrand span{display:inline}.studyImage{height:440px}.artRail figcaption b{font-size:10px}.accessTable header strong{font-size:58px}}
@media(max-width:360px){
  .currentAccess header{flex-direction:column;gap:24px}
  .currentAccess header strong,.currentAccess header small{text-align:left}
}
@media(max-width:1100px){
  /* The menu keeps an opaque paper background: it overlays live page content
     and has to stay legible. It takes the glow, not the frost. */
  .siteNav.open{top:70px;border:0;border-radius:var(--r-md);box-shadow:var(--glass-glow)}
}
@media(max-width:760px){
  .siteHeader{left:8px;right:8px;top:8px;height:58px;padding-inline:12px}
  .launchButton{margin:5px;height:calc(100% - 10px)}
  .siteNav.open{top:64px}
  .bodyStudy,.instrument,.artRail,.faqList{border-radius:var(--r-lg)}
  .accessTable article{border-radius:var(--r-lg)}
  .faqList details{padding-inline:18px}
  .finalCta{margin:8px;border-radius:var(--r-lg)}
}

/* Shared product header + July 13 landing refinements. The 1322px shell is
   the same working width as the WebApp, so identity and actions sit inward
   on wide displays instead of stretching to the browser edges. */
/* THE TRAVELLING SHELL (experiment 06).
   The header does not begin at the top. It rests near the bottom edge of the
   hero, where it reads as the product shell sitting under the render, and
   rises to dock at `top` as the page scrolls. Launching from it flies it the
   rest of the way, so the shell the visitor clicked becomes the shell the app
   opens with.
   The offset is a transform, never `top`, because animating `top` on a
   backdrop-filtered element relayouts and re-blurs it every frame. JS rewrites
   --shell-offset from the live measurements; the value here is only what
   applies before the script runs. */
.siteHeader{
  --shell-offset:calc(100svh - 88px);
  left:50vw;right:auto;top:14px;width:min(var(--measure),calc(100vw - 48px));height:60px;
  padding:6px 7px 6px 18px;transform:translateX(-50%) translateY(var(--shell-offset));
  border:1px solid transparent;border-radius:var(--r-lg);
  background:var(--glass);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-glow);
}
.siteHeader.isAppBound{--shell-offset:0px}
body.isLaunching{overflow:hidden}
body.isLaunching .siteHeader{pointer-events:none;will-change:transform}
/* The page recedes so the shell is the only thing still moving. */
body.isLaunching .heroInner,body.isLaunching .heroMedia{opacity:.16;filter:blur(3px);transition:opacity .38s var(--ease),filter .38s var(--ease)}
.siteNav{height:46px;align-self:center}
.headerActions{height:46px;align-self:center}
.headerActions>*{height:46px}
.instagramLink{width:94px;padding:0}
.launchButton{width:120px;height:46px;margin:0;padding:0 18px;justify-content:space-between;gap:0;border-radius:var(--r-pill)}
/* No top padding: the shell rests at the BOTTOM of the hero, not over its top. */
.hero{padding-top:0}

.bodyStudy footer{min-height:62px;padding:15px clamp(24px,2vw,36px)}

/* The real workspace stays in the normal document flow. Its visible journey
   through the viewport drives the full turntable without pinning the page.
   The 2560 px desktop source renders in an 80% shell for true Retina detail. */
.instrumentScroll{position:relative;margin-bottom:clamp(72px,8vw,124px)}
/* The workspace is the one thing on the page that breaks the measure, and only
   just: 10px past it on each side (Lee, 2026-08-05). It was 80% of the measure
   and flanked by two labelled pills; without them it has to carry the section
   alone, and reading fractionally wider than every other element is what makes
   it read as the real thing rather than another figure. The overhang is small
   enough to stay deliberate — this is not full-bleed, which the page rules out
   everywhere. Negative margins rather than a wider parent, so --bleed keeps
   owning the measure and nothing else in the section moves. */
.instrumentScroll .instrument{
  position:relative;width:calc(100% + 20px);height:auto;margin-inline:-10px;
  aspect-ratio:16/9;display:block;background:#0d0f0f;isolation:isolate
}
.instrument,.uiStudies,.artRail{scroll-margin-top:96px}
.instrumentPicture{position:absolute;inset:0;display:block}
.instrumentShot{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center;background:#0d0f0f}
/* The two pills that used to flank the workspace are gone (Lee, 2026-08-05):
   "PAGE SCROLL / ORBIT 360° 001 / 060" above it and "ACTUAL WEBAPP / FULL
   WORKSPACE — OPEN THE TOOL" below. Both were the same instrument-readout
   convention the page keeps having to delete: a frame counter nobody needs to
   read, and a slash-separated label doing a caption's job in an interface's
   voice. The image rotates as you scroll whether or not a number says so.
   The JS that fed the counter is untouched and already guarded
   (`if (turntableCounter)`), so it simply finds nothing now — which means the
   pill can come back by restoring only its markup, if it is ever wanted. */

/* Two real workspace captures sit at their native proportions in one shared
   superellipse. Their source ratios make both images the same visual height,
   so the column split is not a taste value: it is left ratio / right ratio.
   1800/1447 divided by 900/1128 = 1.559. Re-derive it if either study is
   re-exported at a new aspect, or the two frames stop lining up. */
/* The rule below the two studies no longer matches honestyBlock's — Lee asked
   for this one specifically lighter and thinner (1px var(--line), the page's
   existing soft editorial rule, instead of the heavier 3px var(--ink)), so
   they're now two deliberately different weights in the same section. --line
   already flips per theme the same way --ink does, so dark mode still needs
   no separate override. It sits centred in the gap before the stencil rail,
   not flush against either: padding-bottom and margin-bottom are the same
   clamp, split evenly around the line — that centring math doesn't care about
   the line's own thickness, so it didn't need to change here. */
.uiStudies{
  height:auto;padding-bottom:clamp(32px,3.5vw,52px);
  border-bottom:1px solid var(--line);
  margin-bottom:clamp(32px,3.5vw,52px);
  display:grid;grid-template-columns:1.559fr 1fr;gap:14px
}
.uiStudies figure{
  min-width:0;margin:0;display:grid;grid-template-rows:auto 62px;align-self:start;overflow:hidden;
  border:0;border-radius:var(--r-xl);background:var(--paper-2)
}
.uiStudies img{width:100%;height:auto;object-fit:contain;object-position:center;background:var(--paper-2)}
.uiStudies figure:first-child img{aspect-ratio:1800/1447}
.uiStudies figure:last-child img{aspect-ratio:900/1128}
.uiStudies figcaption{
  padding:15px clamp(24px,2vw,34px);display:flex;align-items:center;justify-content:space-between;gap:18px;
  border-top:1px solid var(--card-line)
}
/* Each card kept ONE caption, and the two that went were the ones in the row's
   outer corners (Lee, 2026-08-05). space-between would now push the survivor
   to flex-start on both cards, which puts the left card's label straight back
   into the far-left corner that was just cleared. Sending the left one to the
   end keeps the pair facing each other across the gutter, and the outside
   edges of the row empty, which was the point. */
.uiStudies figure:first-child figcaption{justify-content:flex-end}
@supports (corner-shape:squircle){.uiStudies figure{corner-shape:squircle;border-radius:var(--r-2xl)}}

/* ---- CONTINUITY: the work you already carry, and the plan built around it --
   Sits between the studies row and the stencil rail, and is the section's
   proof rather than a new argument: PLAN THE PATCHWORK claims one tattoo
   changes the next, and this is the same leg, photographed and then planned
   on. So it takes an h3 under the section's h2, not a competing display line.

   THE COLUMN RATIO IS MEASURED, NOT CHOSEN (recomputed 2026-08-14 for the
   higher-quality film). The photograph is 1086x1448, a clean 4:3. The film is
   960x1706, a clean 16:9 — Lee supplied it pre-cut at 1080x1920, scaled down
   here for web weight; 16:9 survives any uniform scale. Equal media heights
   need the columns in the inverse ratio, (16/9)/(4/3) = 4/3 exactly — hence
   1.333fr 1fr, which lands both cards on exactly the same baseline with their
   caption strips aligned. This one is a clean fraction because both source
   ratios are; that will not generally be true, so if either asset changes,
   recompute from ITS OWN pixel dimensions rather than assuming 4:3 again. */
.continuity{
  padding-bottom:clamp(32px,3.5vw,52px);
  border-bottom:1px solid var(--line);
  margin-bottom:clamp(32px,3.5vw,52px)
}
.continuityLead{
  padding-bottom:clamp(34px,4vw,58px);
  display:grid;grid-template-columns:1.65fr .75fr;gap:8vw;align-items:end
}
.continuityLead h3{
  margin:0;font-size:clamp(26px,3.5vw,54px);font-weight:400;
  line-height:.94;letter-spacing:-.055em;text-wrap:balance
}
.continuityLead h3 b{font-weight:800}
.continuityLead p{max-width:430px;margin:0;color:var(--muted);font-size:15px;line-height:1.7}
.continuityPair{display:grid;grid-template-columns:1.333fr 1fr;gap:14px}
.continuityPair figure{
  min-width:0;margin:0;display:grid;grid-template-rows:auto 62px;align-self:start;overflow:hidden;
  border:0;border-radius:var(--r-xl);background:var(--paper-2)
}
/* object-fit:cover with a stated aspect-ratio, so a future asset swap crops
   rather than silently breaking the height match the column ratio depends on. */
.continuityPair img,.continuityFilm{
  display:block;width:100%;height:auto;background:var(--paper-2)
}
.continuityPair figure:first-child img{aspect-ratio:1086/1448;object-fit:cover;object-position:center}
.continuityFilm{aspect-ratio:960/1706;object-fit:cover;object-position:center}
.continuityPair figcaption{
  padding:15px clamp(24px,2vw,34px);display:flex;align-items:center;justify-content:space-between;gap:18px;
  border-top:1px solid var(--card-line)
}
/* Same facing-inward logic as .uiStudies: the row's outer corners stay empty
   and the two labels address each other across the gutter. */
.continuityPair figure:first-child figcaption{justify-content:flex-end}
@supports (corner-shape:squircle){.continuityPair figure{corner-shape:squircle;border-radius:var(--r-2xl)}}

/* THESE TWO NEED MORE THAN A GLOW, AND HERE IS THE MEASUREMENT.
   Both section 03 studies are workspace captures whose own background is
   #ebf4f9. Against the current #dce8ef ground that is 1.119:1 — improved by
   the site-wide ground adjustment, but still too close to carry the edge.
   A brighter glow cannot fix it. Pure white at full opacity only reaches
   1.115:1 against that image, so there is no white bright enough to separate
   them; every extra percent of opacity buys almost nothing.
   So the edge here is a bevel, not just a bloom: a cool hairline rim that
   actually separates card from paper (1.34:1), with a much stronger white
   bloom inside it so it still reads as light rather than as a drawn border.
   Light mode only. In dark the figure swaps to Back_Labels_Dark and the
   standard glow has all the contrast it needs.
   Scoped to .uiStudies deliberately: section 04's export sheet sits on pure
   white and its consult photo is dark, so both already separate. */
/* .continuityPair joins this for the same measured reason, not by association:
   its app film is a workspace capture on the same near-white ground, and the
   leg photograph is shot on pale grey. Both sit within a rounding error of the
   page and need the bevel, not just the bloom. */
html:not([data-theme="dark"]) .uiStudies figure::after,
html:not([data-theme="dark"]) .continuityPair figure::after{
  box-shadow:
    inset 0 0 0 1px rgba(88,104,116,.22),
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 0 22px rgba(255,255,255,.55),
    inset 0 0 64px rgba(255,255,255,.34);
}

/* The dagger is intentionally taller than its library cell. Its point crosses
   the caption and the breathing space, stopping at the honesty rule. */
/* NO BACKGROUND ON THE RAIL ITSELF — this one is a trap worth naming.
   The rail can't clip its children (overflow must stay visible so .artDagger
   can overhang its cell), so the container's corners and the corner cells'
   corners are drawn independently — and they disagree: the rail rounds at
   --r-2xl (64px) AS A SQUIRCLE, while the corner figure and its caption round
   at --r-xl (46px) as ordinary arcs, because corner-shape doesn't inherit.
   A hardcoded white background here therefore showed as a pale crescent in
   the sliver between the two curves. Invisible in light (white on near-white
   paper); in dark it was a bright white smear on the corner of a #242a2d
   caption strip over a #343c40 page ground.
   It was also redundant: .artRail figure and .artRail figure>div both paint
   #fff already and the four cells tile the whole rail, so the container's own
   background was never visible ANYWHERE except in that corner sliver.
   Third time this codebase has been bitten by a theme-invariant surface
   meeting theme-aware surroundings — check for it before hardcoding a colour
   next to anything that flips with the theme. */
.artRail{position:relative;overflow:visible;isolation:isolate}
/* AND NO WHITE ON THE FIGURE EITHER — this is the one that actually shows.
   The dark caption strip rounds its bottom corner at 46px and was painted
   directly on top of this white, which rounds at exactly the same 46px. Along
   a curve the caption's edge pixels are ANTIALIASED — partially transparent —
   so every pixel on that curve blended the caption down onto white instead of
   onto the page, and the corner lit up with a pale fringe. A straight edge
   doesn't show it (coverage goes 0 to 1 in one pixel); a curve spreads that
   transition over the whole arc, which is why it appeared at the two bottom
   corners and nowhere else. Light mode hid it because a #f7fbfd caption on
   white has nothing to reveal; dark mode put #242a2d on white and it glowed.
   Redundant as well as harmful: figure>div paints the plate white and
   figcaption paints the strip, so between them the whole cell is covered.
   Safe for the blend modes too — the multiply-blended artwork backs onto
   figure>div's white directly, and .artDagger's img is mix-blend-mode:normal
   at z-index 8, so neither was relying on this. */
.artRail figure{position:relative}
.artRail figure>div{position:relative;overflow:visible;padding:10%}
.artRail figcaption{position:relative;z-index:4;min-height:80px;padding:17px clamp(22px,1.8vw,30px)}
.artRail figure:first-child,.artRail figure:first-child>div{border-top-left-radius:var(--r-xl)}
.artRail figure:first-child,.artRail figure:first-child figcaption{border-bottom-left-radius:var(--r-xl)}
.artRail figure:last-child,.artRail figure:last-child>div{border-top-right-radius:var(--r-xl)}
.artRail figure:last-child,.artRail figure:last-child figcaption{border-bottom-right-radius:var(--r-xl)}
.artDagger{z-index:6}
.artDagger>div{z-index:auto}
.artDagger img{
  position:absolute;z-index:8;left:50%;top:16px;width:auto;height:calc(100% + 335px);max-width:none;
  object-fit:contain;transform:translateX(-50%);mix-blend-mode:normal;pointer-events:none
}
.artDagger figcaption{z-index:7}
.honestyBlock{position:relative;z-index:9;background:var(--page-ground)}
/* Placement only. The look lives with the other quiet links; the two ink rules
   this used to sit between are gone, because a permanent bottom border fights
   the rule that draws in. justify-self keeps the dash under the words rather
   than stretched across the whole column. */
.honestyBlock a{grid-column:2;margin-top:22px;justify-self:start;align-self:start}

@supports (corner-shape:squircle){
  .siteHeader{corner-shape:squircle;border-radius:var(--r-xl)}
  .launchButton{border-radius:var(--r-pill)}
}

@media(max-width:1100px){
  .siteHeader{--shell-offset:calc(100svh - 80px);left:50vw;top:10px;width:calc(100vw - 32px);height:60px;padding-left:16px}
  .siteHeader.isAppBound{--shell-offset:0px}
  .siteNav.open{
    left:0;right:0;top:calc(100% + 6px);bottom:auto;height:auto;max-height:calc(100vh - 92px);
    max-height:var(--menu-max-height,calc(100dvh - 92px));display:grid;grid-template-columns:1fr;
    grid-auto-rows:minmax(52px,auto);overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;background:var(--paper)
  }
  /* The travelling shell begins at the foot of the hero. In that state there
     is no viewport below it, so the same dropdown must attach to the shell's
     upper edge. JS chooses this only when the measured space below cannot hold
     the menu; once the shell docks at the top, the default downward placement
     above takes over again. */
  .siteHeader.menuOpensUp .siteNav.open{top:auto;bottom:calc(100% + 6px)}
  .instrument{height:auto;aspect-ratio:16/9}
}
@media(max-width:760px){
  .siteHeader{--shell-offset:calc(100svh - 74px);left:50vw;right:auto;top:8px;width:calc(100vw - 16px);height:58px;padding:5px 7px 5px 12px}
  .siteHeader.isAppBound{--shell-offset:0px}
  .headerActions,.headerActions>*,.siteNav{height:48px}
  .launchButton{width:86px;height:48px;margin:0;border-radius:var(--r-pill)}
  .bodyStudy footer{padding:15px 22px;gap:12px}
  .instrumentScroll{margin-bottom:72px}
  /* No overhang on mobile: --bleed is only 16px there, so 10px each side would
     leave the workspace nearly touching the viewport edge. */
  .instrumentScroll .instrument{width:100%;height:auto;min-height:0;margin-inline:0;aspect-ratio:16/9}
  .uiStudies{height:auto;padding-bottom:72px;margin-bottom:72px;grid-template-columns:1fr;gap:12px}
  .uiStudies figure{grid-template-rows:auto 58px;border-radius:var(--r-lg)}
  .uiStudies figure:first-child img{aspect-ratio:1800/1447}
  .uiStudies figure:last-child img{aspect-ratio:900/1128}
  .uiStudies figcaption{padding:14px 20px;font-size:8px}
  /* Stacked, the measured 1.34fr ratio is meaningless — nothing sits beside
     anything — so both media go back to their own natural height. */
  .continuity{padding-bottom:72px;margin-bottom:72px}
  .continuityLead{padding-bottom:44px}
  .continuityPair{grid-template-columns:1fr;gap:12px}
  .continuityPair figure{grid-template-rows:auto 58px;border-radius:var(--r-lg)}
  .continuityPair figcaption{padding:14px 20px;font-size:8px}
  .continuityPair figure:first-child figcaption{justify-content:flex-start}
  /* Two columns, two rows: the verticals move to the odd cells and the top
     row gets its horizontal back. The perimeter still belongs to the rim. */
  .artRail figure:nth-child(2n)>div,.artRail figure:nth-child(2n) figcaption{border-right:0}
  .artRail figure:nth-child(-n+2){border-bottom:1px solid var(--card-line)}
  .artRail figure:first-child,.artRail figure:first-child>div{border-top-left-radius:var(--r-lg)}
  .artRail figure:first-child{border-bottom-left-radius:0}
  .artRail figure:first-child figcaption{border-bottom-left-radius:0}
  .artRail figure:nth-child(2),.artRail figure:nth-child(2)>div{border-top-right-radius:var(--r-lg)}
  .artRail figure:nth-child(3),.artRail figure:nth-child(3) figcaption{border-bottom-left-radius:var(--r-lg)}
  .artRail figure:last-child,.artRail figure:last-child figcaption{border-bottom-right-radius:var(--r-lg)}
  .artRail figure:last-child>div{border-top-right-radius:0}
  .artRail figcaption{min-height:70px;padding:14px 20px}
  .artDagger img{height:calc(100% + 230px)}
  .honestyBlock a{grid-column:1;margin-top:0}
}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.demoDialog[open]{animation:none}[data-reveal]{opacity:1;transform:none;transition:none}.studyInteractiveViewport,.studyInteractiveFallback,.studyInteractiveStatus,.studyRing,.quietLink::after,.quietLink i,.actionLink::after,.actionLink i,.honestyBlock a::after,.honestyBlock a i,.accessTable article>a::after,.accessTable article>a i,.finalCta>a::after,.finalCta>a i,.launchButtonArrow,.heroRenderInk,.focusRing{transition:none}.launchButton::before,.launchButton::after{transition:none!important}.launchButton:hover::after,.launchButton:focus-visible::after{animation:none;opacity:.34;transform:translateY(-9%) scale(1.14)}.studyCueGlyph{animation:none}}
@media(max-width:760px){
  /* These editorial leads inherit their desktop column assignments from rules
     that appear later in the cascade. Collapse both at the final mobile layer
     and place every direct child back on the single readable track, so no
     stale column 2 can create an implicit narrow column at phone widths. */
  .continuityLead,.honestyBlock{grid-template-columns:minmax(0,1fr)}
  .continuityLead>h3,.continuityLead>p,
  .honestyBlock>h3,.honestyBlock>p,.honestyBlock>a{grid-column:1 / -1;min-width:0}
  .honestyBlock>p{max-width:65ch}
  .studyFemale .studyImage{height:auto;aspect-ratio:4/5}
  .studyInteractiveStatus{top:18px;left:18px}
  .studyInteractive.is-keyboard .studyInteractiveStatus{bottom:18px;max-width:calc(100% - 36px)}
  .quietLink{margin-top:28px}
}


/* ---- 04 / EXPORT SHEET — the placement moves from screen to consult ---- */
.planShare{padding-bottom:clamp(90px,10vw,160px)}
/* Asymmetric, unlike its siblings: the top opens against honestyBlock's
   closing rule and owns the whole gap on its own (see .studies), so it is
   roughly 6vw rather than 9. Big type can sit closer to a rule than small type
   can, and the other section leads open across a colour change, which is a
   harder boundary that wants more air. The bottom keeps the shared 9vw,
   because that one separates the lead from the export images. */
.planLead{padding:clamp(46px,6vw,100px) 0 clamp(70px,9vw,145px);display:grid;grid-template-columns:1.65fr .75fr;gap:8vw;align-items:end}
.planLead h2{margin:0;font-size:clamp(52px,7.7vw,124px);font-weight:400;line-height:.87;letter-spacing:-.075em;text-wrap:balance}
.planLead p{max-width:430px;margin:0;color:var(--muted);font-size:15px;line-height:1.7}
.exportStories{display:grid;grid-template-columns:minmax(0,1.42fr) minmax(280px,.58fr);gap:18px;align-items:end}
.exportStory{min-width:0;margin:0;overflow:hidden;border:0;border-radius:var(--r-xl);background:var(--paper-2)}
.exportStoryImage{overflow:hidden;background:#fff}
.exportStoryImage img{width:100%;height:100%;max-width:none}
.exportSheetStory .exportStoryImage{aspect-ratio:3360/2533}
.exportSheetStory .exportStoryImage img{object-fit:contain}
.consultStory{margin-top:clamp(80px,11vw,175px)}
.consultStory .exportStoryImage{aspect-ratio:1122/1402}
.consultStory .exportStoryImage img{object-fit:cover;filter:contrast(1.04)}
[data-theme="dark"] .consultStory .exportStoryImage img{filter:brightness(.74) contrast(1.05)}
.exportStory figcaption{min-height:64px;padding:15px clamp(18px,2vw,30px);display:flex;align-items:center;justify-content:space-between;gap:22px;border-top:1px solid var(--card-line);color:var(--muted)}
/* The coral used to mark the invented index ("EXPORT 041", "CONSULT 001").
   Those are gone, and a first-child rule would now paint the surviving plain
   caption coral instead — accent has to report something, and "Export Sheet"
   is a name, not a state.

   EXPORT SHEET sits at the right-hand end of its caption (Lee, 2026-08-05).
   Same reasoning as the study pair above: with one child left, space-between
   defaults it to flex-start, and the two cards' captions would then both
   start at the far left. Sending this one to the end keeps it beside the
   consult card's label rather than stranded at the outer edge of the row. */
.exportSheetStory figcaption{justify-content:flex-end}
.consultStory figcaption{flex-direction:column;align-items:flex-start;justify-content:center;gap:6px}
/* Rounded (Lee, 2026-08-05), which changes how the borders have to work. It
   was a four-sided ruled grid: border-top on the container, border-right and
   border-bottom on every cell, border-left added back on the first. Rounding
   that is not possible — the cells' own square corners would cut straight
   across the curve, the same trap the photo cards' ::after overlays hit.
   So the perimeter moves to the container, where one border and one radius
   can agree, and the cells keep only the two verticals BETWEEN them. Same
   ruled-grid language, one shape.
   The 01/02/03 kicker titles are gone with it, so the cells hold a paragraph
   each and no longer need the 28px gap that separated label from copy. */
.planPoints{margin-top:clamp(54px,6vw,92px);display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden}
.planPoints>div{min-height:150px;padding:27px clamp(20px,2.4vw,38px);display:flex;flex-direction:column;justify-content:center}
.planPoints>div+div{border-left:1px solid var(--line)}
.planPoints p{max-width:360px;margin:0;color:var(--muted);font-size:13px;line-height:1.7}
/* The CTA and the compact-width note left .planPoints when it became a rounded
   box with overflow:hidden — as grid children they would have been sealed
   inside it, and clipped by its radius. They sit in their own row below now,
   which is where they already appeared to be when .planPoints was only a set
   of rules with no enclosing shape. */
.planFoot{margin-top:34px;display:flex;flex-direction:column;align-items:flex-end;gap:18px}
.compactExportNote{display:none}
@supports (corner-shape:squircle){
  .planPoints{corner-shape:squircle}
  .exportStory{corner-shape:squircle;border-radius:var(--r-2xl)}
}
@media (max-width:1100px){
  .planLead{grid-template-columns:1fr .65fr;gap:5vw}
  /* WIDE SHEET, NARROWER CONSULT COLUMN. Both cards are bottom-aligned, so
     the stagger between their top edges is exactly sheetH - consultH — the
     .consultStory margin-top below has no say in it once it is binding. The
     Aug 18 Export Sheet is a wide 3360x2533 where the old one was near-square
     3360x3126, which made the sheet card short enough that the consult card
     started ABOVE it here and inverted the stagger. Widening the sheet column
     makes it taller again: measured stagger 53/48/43/38px at 1100/1000/900/800,
     against 59/53/48/43 before the swap. Re-measure this if either image's
     aspect ratio changes again. */
  .exportStories{grid-template-columns:minmax(0,1.3fr) minmax(240px,.7fr)}
  .consultStory{margin-top:80px}
}
@media (max-width:900px){
  .compactExportNote{display:block;max-width:360px;text-align:right}
}
@media (max-width:760px){
  .planLead{padding:44px 0 80px;grid-template-columns:1fr;gap:35px}
  .planLead h2{font-size:15.4vw}
  .exportStories{grid-template-columns:1fr;gap:14px}
  .consultStory{margin-top:0}
  .exportStory{border-radius:var(--r-lg)}
  .exportStory figcaption{min-height:58px;padding:14px 18px;font-size:7.5px}
  /* Stacked, so the dividers between cells turn horizontal. border-left would
     draw a rule down the left edge of every cell, inside the container's own
     rounded border. */
  .planPoints{grid-template-columns:1fr}
  .planPoints>div{min-height:0;padding:25px 20px}
  .planPoints>div+div{border-left:0;border-top:1px solid var(--line)}
  .planFoot{align-items:flex-start}
  .compactExportNote{text-align:left}
}

/* ── Section headings: the app's two-word device, and an alternating rhythm ──
   The WebApp carries its titles as Body FORM, Stencil STACK, Export SHEET:
   one weight for the phrase, a heavier one for the word that matters. The
   landing borrows that rather than setting everything at 800, so the two
   surfaces read as one product. Contrast is weight only, not colour — the
   headings carry no accent now.
   Emphasis never lands on the negative half of a line (Lee, August 1). */
.thesisGrid h2 b,.methodLead h2 b,.studiesLead h2 b,
.accessLead h2 b,.planLead h2 b,.faqGrid>h2 b,.finalCta h2 b{font-weight:800}

/* Headings alternate sides down the page. Scoped above the breakpoint where
   these leads collapse to one column, so the stacked layout is untouched. */
@media (min-width:761px){
  .methodLead,.planLead{grid-template-columns:.75fr 1.65fr}
  .methodLead h2,.planLead h2{grid-column:2;text-align:right}
  .methodLead p,.planLead p{grid-column:1;grid-row:1}
  .faqGrid{grid-template-columns:1.2fr .8fr}
  .faqGrid>h2{grid-column:2;grid-row:1;text-align:right}
  .faqGrid .faqList{grid-column:1;grid-row:1}
}

/* ---- Impeccable typeset pass: sighted reading + touch floor (2026-08-22) --
   The large display voice is already doing its job. This block establishes a
   small set of semantic floors beneath it: 16px reading copy, 14px compact
   support/actions, 12px captions/chrome, and 11px true editorial kickers.
   Labels no longer become tiny merely because a composition narrows. */
.mono{font-size:var(--type-kicker)}
.skipLink{
  min-height:var(--h-control);display:inline-flex;align-items:center;
  font-size:var(--type-action)
}
.siteBrand{min-width:var(--h-control);min-height:var(--h-control)}
.siteNav a,.instagramLink,.launchButton{font-size:var(--type-caption)}

.heroLead{font-size:clamp(var(--type-body),1.3vw,18px)}
.heroTruth{font-size:var(--type-body-sm)}
.thesisCopy>p{font-size:var(--type-body);line-height:1.68}
.methodLead p,.studiesLead p,.accessLead p,.planLead p{font-size:var(--type-body);line-height:1.68}
.methodList p{font-size:var(--type-body-sm);line-height:1.62}
.honestyBlock p,.planPoints p{font-size:var(--type-body);line-height:1.68}
.accessTable li{font-size:var(--type-body-sm);line-height:1.5}
.accessTable header small{font-size:var(--type-caption);line-height:1.35}
.futureAccess>p{font-size:var(--type-body);line-height:1.68}
.futureAccess .futureStatus{font-size:var(--type-caption);line-height:1.5}
.faqList summary{font-size:var(--type-body);line-height:1.35}
.faqList p{max-width:65ch;font-size:var(--type-body);line-height:1.68}

.quietLink,.actionLink,.honestyBlock a,
.accessTable article>a,.finalCta>a,.studyOpenLink{
  min-height:var(--h-control);display:inline-flex;align-items:center;
  font-size:var(--type-action);line-height:1.2
}
.studyInteractiveStatus{font-size:var(--type-caption)}
.studyOpenLink{font-size:var(--type-caption)}
.bodyStudy footer,.uiStudies figcaption,.continuityPair figcaption,
.exportStory figcaption{font-size:var(--type-caption);line-height:1.4}
.artRail figcaption .mono{font-size:var(--type-kicker)}
.artRail figcaption b{font-size:var(--type-caption)}
.compactExportNote{
  font-size:var(--type-body-sm);line-height:1.55;letter-spacing:0;text-transform:none
}
.finalCta>a{font-size:var(--type-action)}
.demoClose{
  min-width:var(--h-control);min-height:var(--h-control);display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--type-action)
}
.siteFooter p{font-size:var(--type-body-sm);line-height:1.7}
.siteFooter nav{font-size:var(--type-action)}
.siteFooter .footerLegal{font-size:var(--type-caption)}
.siteFooter nav a{min-width:var(--h-control);min-height:var(--h-control);display:flex;align-items:center}

/* Accent colour now has separate surface and ink jobs. Bright coral remains
   the brand fill; the ink step is readable on both light and dark grounds. */
.heroTruth em,
.siteNav a:hover,.siteNav a:focus-visible,
.instagramLink:hover,.instagramLink:focus-visible,
.siteHeader .siteBrand:hover,.siteHeader .siteBrand:focus-visible,
.themeToggle:hover,.themeToggle:focus-visible,
.menuButton:hover,.menuButton:focus-visible,
.quietLink:hover,.quietLink:focus-visible,
.actionLink:hover,.actionLink:focus-visible,
.honestyBlock a:hover,.honestyBlock a:focus-visible{color:var(--accent-ink)}
[data-theme="dark"] .siteNav a:hover,[data-theme="dark"] .siteNav a:focus-visible,
[data-theme="dark"] .instagramLink:hover,[data-theme="dark"] .instagramLink:focus-visible,
[data-theme="dark"] .siteHeader .siteBrand:hover,[data-theme="dark"] .siteHeader .siteBrand:focus-visible,
[data-theme="dark"] .themeToggle:hover,[data-theme="dark"] .themeToggle:focus-visible,
[data-theme="dark"] .menuButton:hover,[data-theme="dark"] .menuButton:focus-visible{color:var(--accent-ink)}

@media(max-width:760px){
  /* The base hero width already reserves the page gutter. Adding another
     16px inset here left only 240px at a 320px viewport, which wrapped the
     two 44px actions and pushed the truth line under the travelling shell. */
  .heroInner{width:100%;min-height:max(620px,100svh)}
  /* Previous mobile-only caption reductions (7.5–8px) defeated the reading
     scale precisely where the images are smallest. Keep one caption role. */
  .uiStudies figcaption,.continuityPair figcaption,.exportStory figcaption{
    font-size:var(--type-caption)
  }
  /* A tighter left-hand veil holds the enlarged copy against the live image;
     it feathers away before the manikin's visual centre. */
  .heroMedia::after{
    background:
      linear-gradient(90deg,color-mix(in srgb,var(--page-ground) 94%,transparent) 0%,color-mix(in srgb,var(--page-ground) 84%,transparent) 48%,transparent 82%),
      linear-gradient(180deg,color-mix(in srgb,var(--page-ground) 10%,transparent),transparent 26%,transparent 74%,color-mix(in srgb,var(--page-ground) 16%,transparent))
  }
}
