/* Concept Shopify-theme case studies (ava, CARVÉ, Mason Varde, ...): the shared storefront-replica components, the Concept pill and
   disclosure, the hero, "01 Discover" and "02 Define" (the brief, the proto-personas, the journey) and "How we'd test it". Markup:
   src/_includes/e2/theme/*.njk; behaviour: e2-theme.js. The Design, Optimise and signature sections have their own sheets
   (e2-theme-store.css, e2-theme-sig.css) and reuse the components in the first block below.
   Look: E2 (black, Geist, white type, blue accents). A theme's own brand colours live only inside its stage and documents: each section
   sets --th-from / --th-to / --th-ink / --th-accent from themes[key].stage, and a persona's --c from the data. Nothing here is specific to one theme.
   Phones (max-width 699px) get their own layouts; the journey turns into a vertical timeline below 960px. Reduced motion: everything is
   shown finished (last block). */

/* =====================================================================================================================
   SHARED COMPONENTS: the storefront replica (used by the hero, the Design and the Optimise sections)
   A 1440px-wide Figma artboard inside a browser frame, scaled to the frame's width:
     <div class="th-browser"><div class="th-browser__bar"><i></i><i></i><i></i><span>label</span></div>
       <div class="th-viewport" style="aspect-ratio:1440 / {visible artboard px}">
         <div class="th-artboard" style="--ah:{artboard px}" aria-hidden="true" inert> ...slices (.th-s) and .th-banner... </div></div></div>
   .th-viewport is the size container; the artboard is laid out at 1440px and scaled by --k = (frame width / 1440), a unitless number you can
   also use inside it (translate: calc(var(--k) * -1500px)). e2-theme.js sets --k itself where CSS can't compute it.
   ===================================================================================================================== */
.th-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* The sticky 68px site header covers the top of the viewport: keyboard focus, find-in-page and scrollIntoView stop below it (WCAG 2.4.11).
   Scoped to the theme pages (:has the hero), so it never stacks with e2.css's own anchor offsets elsewhere. */
html:has([data-th-hero]) { scroll-padding-top: calc(var(--header-h) + 16px); }
/* "← Work" (e2.css: 15px text, 6px padding = 35px tall): a 44px-tall box with 8px sides, the extra taken back by negative margins, so the
   hit area is the box itself, nothing moves and "Work" stays on the wrap's edge; the radius rounds the focus ring. */
.e2-back { min-height: 44px; padding: 0 8px; margin: -4.75px -8px; border-radius: 8px; }

.th-browser {
  position: relative; overflow: hidden; border-radius: 14px; background: #fff; color: #111;
  box-shadow: 0 0 0 1px rgba(2,9,18,.1), 0 2px 6px rgba(2,9,18,.06);
}
.th-browser__bar { display: flex; align-items: center; gap: 6px; height: 34px; padding: 0 12px; background: #f4f4f5; border-bottom: 1px solid #e4e4e7; }
.th-browser__bar i { flex: none; width: 10px; height: 10px; border-radius: 50%; background: #d4d4d8; }
.th-browser__bar::after { content: ""; flex: none; width: 42px; }   /* balances the three dots, so the pill sits in the middle */
.th-browser__bar span {
  flex: 0 1 auto; min-width: 0; max-width: min(64%, 380px); margin: 0 auto; padding: 0 14px;
  height: 22px; line-height: 22px; border-radius: 7px; background: #fff; box-shadow: inset 0 0 0 1px #e4e4e7;
  font-size: 11px; font-weight: 500; letter-spacing: .01em; color: #6b6b73; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.th-viewport { position: relative; container-type: inline-size; overflow: clip; background: #fff; }
.th-artboard {
  --k: tan(atan2(100cqw, 1440px));
  position: absolute; left: 0; top: 0; width: 1440px; height: calc(var(--ah, 900) * 1px);
  transform-origin: 0 0; transform: scale(var(--k)); pointer-events: none; user-select: none; -webkit-user-select: none;
}
/* One section of the storefront (an exact render, 1440 wide), placed at its Figma y. */
.th-s { position: absolute; left: 0; width: 1440px; top: calc(var(--y) * 1px); height: calc(var(--h) * 1px); overflow: hidden; }
.th-s > img { display: block; width: 1440px; max-width: none; height: 100%; }
/* The hero banner's video (banner.njk): over its rect on the artboard, hidden until it plays, so the render shows until then. The clip
   starts on the render's own frame, so the hand-over is a long, soft cross-fade (--fade) that should read as nothing at all. */
.th-banner { --fade: .9s; position: absolute; left: calc(var(--x) * 1px); top: calc(var(--y) * 1px); width: calc(var(--w) * 1px); height: calc(var(--h) * 1px); }
.th-banner__video { display: block; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity var(--fade) ease-in-out; }
.th-banner.is-playing .th-banner__video { opacity: 1; }
/* The theme's image overlay (th.hero.banner.shade), which the clip doesn't have and the render does: it fades in with the video, in step,
   so the shaded clip meets the render's tone exactly. */
.th-banner__shade { position: absolute; inset: 0; background: #000; opacity: 0; transition: opacity var(--fade) ease-in-out; pointer-events: none; }
.th-banner.is-playing .th-banner__shade, .th-banner.is-poster .th-banner__shade { opacity: var(--shade); }
.th-banner.is-poster .th-banner__shade { transition: none; }   /* reduced motion: over the poster, once e2-theme.js has set it */
/* Registration (th.hero.banner.dy, artboard px, optional): the clip and its shade drawn that much lower, together, to land on the render's
   photo. The strip it opens at the top shows the render itself; the banner's clip-path crops the overflow at the bottom. */
.th-banner__video, .th-banner__shade { transform: translateY(calc(var(--dy, 0) * 1px)); }
/* Light type set straight on the photo (a themesOver rect with "matte"): the render's own pixels for that rect, keyed by luminance (the SVG
   filter beside it) so only the letters stay, over the moving clip. It fades in with the clip: over the still render it would only thicken
   the letters' edges. */
.th-banner__defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.th-banner__matte {
  position: absolute; overflow: hidden; opacity: 0; transition: opacity var(--fade) ease-in-out;
  left: calc(var(--mx) * 1px); top: calc(var(--my) * 1px); width: calc(var(--mw) * 1px); height: calc(var(--mh) * 1px);
}
.th-banner__matte img { position: absolute; left: calc(var(--ix) * -1px); top: calc(var(--iy) * -1px); width: 1440px; max-width: none; height: auto; }
.th-banner.is-playing .th-banner__matte, .th-banner.is-poster .th-banner__matte { opacity: 1; }
.th-banner.is-poster .th-banner__matte { transition: none; }
/* A copy block laid over the clip as a picture (a themesOver rect with "layer", banner.njk): the storefront's own type, glows and button, alpha
   and all, rendered without the photo. Placed at its artboard rect, in the render's 1x px; it comes in with the clip, as the matte does. */
.th-banner__layer {
  position: absolute; max-width: none; opacity: 0; transition: opacity var(--fade) ease-in-out; pointer-events: none; user-select: none; -webkit-user-select: none;
  left: calc(var(--mx) * 1px); top: calc(var(--my) * 1px); width: calc(var(--mw) * 1px); height: calc(var(--mh) * 1px);
}
.th-banner.is-playing .th-banner__layer, .th-banner.is-poster .th-banner__layer { opacity: 1; }
.th-banner.is-poster .th-banner__layer { transition: none; }

/* =====================================================================================================================
   Concept pill and disclosure (src/_includes/e2/case-study.njk, only when the page says `concept: true`)
   ===================================================================================================================== */
.e2-cs__titlerow { display: flex; align-items: center; flex-wrap: wrap; gap: 14px 22px; }
.e2-cs__concept {
  flex: none; display: inline-flex; align-items: center; gap: 9px; padding: 8px 14px 8px 12px; border-radius: 999px;
  font-family: var(--mono); font-size: 12px; font-weight: 500; line-height: 1.2; letter-spacing: .08em; text-transform: uppercase; white-space: nowrap;
  color: var(--blue-light); background: rgba(63,123,240,.12); box-shadow: inset 0 0 0 1px rgba(118,162,255,.4);
}
.e2-cs__concept::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--blue-light); }
.e2-cs__disclosure {
  max-width: 62ch; padding-left: 16px; border-left: 2px solid var(--border-strong);
  font-size: 15px; line-height: 1.55; color: var(--text-4); text-wrap: pretty;
}

/* =====================================================================================================================
   Section heading block (eyebrow, title, intro): same scale as the story title
   ===================================================================================================================== */
.th-block { display: flex; flex-direction: column; gap: clamp(32px, 4vw, 56px); }
.th-hd { display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 20px 56px; }
.th-hd__main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.th-hd__eyebrow { font-family: var(--mono); font-size: 12px; font-weight: 500; line-height: 1.4; letter-spacing: .08em; text-transform: uppercase; color: var(--text-4); }
.th-hd__title { font-weight: 600; font-size: clamp(36px, 4vw, 56px); line-height: 1; letter-spacing: -.05em; text-wrap: balance; }
.th-hd__aside { max-width: 44ch; font-size: 18px; line-height: 1.5; color: var(--text-3); text-wrap: pretty; }

/* =====================================================================================================================
   1. Hero: the stage
   ===================================================================================================================== */
.th-hero {
  --px: 0; --py: 0;
  position: relative; margin: 0; overflow: hidden; isolation: isolate; border-radius: 32px; aspect-ratio: 16 / 9; width: 100%;
  background: linear-gradient(135deg, var(--th-from), var(--th-to)); color: var(--th-ink);
}
/* Soft light on the stage: a bright pool top-left, a warm one bottom-right, so the frame has something to sit in. */
.th-hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(60% 80% at 22% 8%, rgba(255,255,255,.62), transparent 62%),
    radial-gradient(55% 70% at 88% 100%, rgba(255,255,255,.4), transparent 70%);
}
.th-hero__scene { position: absolute; inset: 0; perspective: 1800px; }

/* The frame: ~62% of the stage, tilted towards the reader; the pointer leans it a few degrees more (JS sets --px / --py, eased). */
.th-hero__lift { position: absolute; left: 50%; top: 50%; width: 62%; translate: -50% -50%; z-index: 1; animation: th-rise 1.1s var(--ease-out) both; }
.th-hero__frame { position: relative; transform: rotateX(calc(6deg - var(--py) * 4deg)) rotateY(calc(var(--px) * 4deg)); }
.th-hero .th-browser {
  border-radius: 14px;
  box-shadow: 0 0 0 1px rgba(2,9,18,.1), 0 60px 90px -30px rgba(2,9,18,.5), 0 28px 44px -22px rgba(2,9,18,.28);
}
/* A faint sheen that slides across the frame as the pointer moves. */
.th-hero__sheen {
  position: absolute; inset: 0; border-radius: 14px; pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, rgba(255,255,255,.16) 50%, transparent 62%) calc(50% + var(--px) * 45%) 0 / 260% 100% no-repeat;
}
@keyframes th-rise { from { transform: translateY(5%) scale(.97); } to { transform: none; } }

/* Floating objects: the span carries the pointer parallax (deeper ones move more), the img the slow bob. */
.th-float {
  position: absolute; left: var(--x); top: var(--y); width: var(--w); z-index: 2;
  translate: calc(var(--px) * var(--z) * 36px) calc(var(--py) * var(--z) * 24px);
  filter: drop-shadow(0 20px 22px rgba(2,9,18,.22));
  animation: th-pop .9s var(--ease-out) both; animation-delay: calc(var(--delay) * -0.1 + .25s);
}
.th-float img { display: block; width: 100%; height: auto; animation: th-bob var(--d) ease-in-out var(--delay) infinite alternate; }
@keyframes th-bob {
  from { transform: translateY(-3.5%) rotate(var(--r)); }
  to { transform: translateY(3.5%) rotate(calc(var(--r) * .5)); }
}
@keyframes th-pop { from { opacity: 0; scale: .8; } to { opacity: 1; scale: 1; } }

/* Chips: small pills in the top-left corner; the first ("Concept") is the filled one. */
.th-hero__chips {
  position: absolute; z-index: 3; left: clamp(14px, 2.4vw, 32px); top: clamp(14px, 2.4vw, 32px); right: clamp(14px, 2.4vw, 32px);
  display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; pointer-events: none;
}
.th-hero__chip {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 13px; border-radius: 999px;
  font-family: var(--mono); font-size: 11px; font-weight: 500; line-height: 1.2; letter-spacing: .07em; text-transform: uppercase; white-space: nowrap;
  color: var(--th-ink); background: rgba(255,255,255,.62); box-shadow: inset 0 0 0 1px rgba(2,9,18,.1);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.th-hero__chip--first { color: #fff; background: var(--th-ink); box-shadow: none; }
.th-hero__chip--first::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--th-accent); box-shadow: 0 0 0 3px rgba(255,255,255,.18); }

/* Pause / play (WCAG 2.2.2), in the bottom-right corner at the chips' inset and in their glass: a 44px hit area round a 40px disc. JS unhides
   it and flips aria-pressed; .is-paused on the stage holds the bob (the parallax and the video are stopped in JS). The focus ring is the
   stage's ink, not the site's blue, so it reads on a light stage. */
.th-hero__pause {
  position: absolute; z-index: 3; right: clamp(14px, 2.4vw, 32px); bottom: clamp(14px, 2.4vw, 32px); isolation: isolate;
  display: grid; place-items: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 50%;
  background: none; color: var(--th-ink); cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.th-hero__pause[hidden] { display: none; }
.th-hero__pause::before {
  content: ""; position: absolute; inset: 2px; z-index: -1; border-radius: 50%;
  background: rgba(255,255,255,.62); box-shadow: inset 0 0 0 1px rgba(2,9,18,.1);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: background-color .2s ease, scale .15s ease;
}
.th-hero__pause:hover::before { background: rgba(255,255,255,.86); }
.th-hero__pause:active::before { scale: .94; }
.th-hero .th-hero__pause:focus-visible { outline: 2px solid var(--th-ink); outline-offset: 2px; }
.th-hero__pico { display: block; }
.th-hero__pico--play, .th-hero__pause[aria-pressed="true"] .th-hero__pico--pause { display: none; }
.th-hero__pause[aria-pressed="true"] .th-hero__pico--play { display: block; }
.th-hero.is-paused .th-float img { animation-play-state: paused; }

/* =====================================================================================================================
   2. "01 Discover": the brief as a paper document, the proto-personas beside it
   ===================================================================================================================== */
/* The stage accent for small type on a light panel (the brief's labels and numerals, a sig's ticks): darkened toward the stage's ink so it
   reads at 4.5:1 or more on --th-to for every theme (Aurelle's terracotta is 4.38:1 raw, 5.7:1 here; ava, CARVÉ and Mason Varde 6.7, 7.0, 9.8).
   Set on every block that carries the stage vars, so the sig sheets can use it too. */
.th-hero, .th-brief, .th-define, .th-tests, .th-sigwrap { --th-accent-ink: color-mix(in srgb, var(--th-accent) 78%, var(--th-ink)); }
.th-brief__grid { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(24px, 3.4vw, 48px); align-items: start; }
.th-brief { gap: 24px; }   /* this block has no title: its eyebrow sits close over the brief, as other eyebrows do over their titles */

.th-doc {
  position: relative; display: flex; flex-direction: column; gap: clamp(26px, 3vw, 40px);
  padding: clamp(24px, 3.6vw, 56px); background: var(--th-to); color: var(--th-ink); border-radius: 20px;
  clip-path: polygon(0 0, calc(100% - 48px) 0, 100% 48px, 100% 100%, 0 100%);   /* the folded corner */
}
.th-doc::after {   /* the fold itself */
  content: ""; position: absolute; top: 0; right: 0; width: 48px; height: 48px;
  background: linear-gradient(to bottom left, transparent 50%, color-mix(in srgb, var(--th-to) 82%, #000) 50%);
}
.th-doc__bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding-bottom: 16px; border-bottom: 1px solid color-mix(in srgb, var(--th-ink) 14%, transparent); padding-right: 36px; }
.th-doc__label { font-family: var(--mono); font-size: 12px; font-weight: 500; line-height: 1.3; letter-spacing: .12em; text-transform: uppercase; }
.th-doc__brand { font-family: var(--mono); font-size: 12px; letter-spacing: .04em; color: color-mix(in srgb, var(--th-ink) 65%, transparent); }
.th-doc__part { display: flex; flex-direction: column; gap: 14px; }
.th-doc__k { font-family: var(--mono); font-size: 11px; font-weight: 500; line-height: 1.3; letter-spacing: .1em; text-transform: uppercase; color: var(--th-accent-ink); }
.th-doc__goal { font-size: clamp(24px, 2.7vw, 36px); font-weight: 500; line-height: 1.28; letter-spacing: -.03em; text-wrap: pretty; }
.th-doc__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.th-doc__item { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; align-items: baseline; padding: 6px 0; font-size: clamp(16px, 1.35vw, 19px); line-height: 1.5; letter-spacing: -.01em; }
.th-doc__n {
  display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; align-self: start; margin-top: 2px;
  font-family: var(--mono); font-size: 11px; font-weight: 500; color: var(--th-accent-ink);
  box-shadow: inset 0 0 0 1.5px var(--th-accent-ink); transition: background-color .3s ease, color .3s ease;
}
.th-doc__item.is-lit .th-doc__n { background: var(--th-accent-ink); color: var(--th-to); }
/* The highlighter: a marker band sweeps across the text, line by line (each wrapped line carries its own band). */
.th-mark {
  background: linear-gradient(var(--th-from), var(--th-from)) 0 88% / 100% .58em no-repeat;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
  transition: background-size .9s var(--ease-out);
}
.th-js .th-doc [data-th-lit] .th-mark { background-size: 0% .58em; }
.th-js .th-doc [data-th-lit].is-lit .th-mark { background-size: 100% .58em; }

.th-personas { display: flex; flex-direction: column; gap: 16px; }
.th-personas__k { font-family: var(--mono); font-size: 12px; font-weight: 500; line-height: 1.4; letter-spacing: .08em; text-transform: uppercase; color: var(--text-4); }
.th-personas__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.th-persona {
  display: grid; grid-template-columns: 48px minmax(0, 1fr); align-content: start; gap: 16px; padding: 20px; border-radius: 20px;
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--border); transition: background-color .25s ease, box-shadow .25s ease;
}
.th-persona:hover { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--border-strong); }
.th-persona__av {
  display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%; background: var(--c); color: #0a0a0b;
  font-size: 20px; font-weight: 600; letter-spacing: -.02em;
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--c) 22%, transparent);
}
.th-persona__body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.th-persona__name { margin: 0; font-size: 18px; font-weight: 600; line-height: 1.25; letter-spacing: -.02em; }
.th-persona__need { font-size: 15px; line-height: 1.5; color: var(--text-2); text-wrap: pretty; }
.th-persona__doubt { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; padding-top: 12px; border-top: 1px solid var(--border); font-size: 14px; line-height: 1.5; color: var(--text-3); text-wrap: pretty; }
.th-persona__k { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--c); }

/* Side by side, the personas column ends level with the brief: the three cards share the extra height, their content centred. (The brief is
   the taller of the two at every two-column width, so it is never stretched itself.) */
@media (min-width: 1100px) {
  .th-brief__grid { align-items: stretch; }
  .th-personas__list { flex: 1; }
  .th-persona { flex: 1; align-content: center; }
}

/* =====================================================================================================================
   3. "02 Define": the journey. Five columns, a mood curve through them (HTML dots on an SVG line), what hesitates and what the design does.
   JS sets --p (0 to 1, how much of the line is drawn) on .th-j, and --seg per stage below 960px (the vertical timeline).
   The persona legend always sits on its own row under the title, left-aligned (flex-basis 100% in the .th-hd row), whatever the title's
   length, so every theme's journey starts at the same height.
   ===================================================================================================================== */
.th-j__legend { display: flex; flex-wrap: wrap; gap: 8px 22px; margin: 0; padding: 0; list-style: none; font-size: 14px; color: var(--text-3); flex-basis: 100%; }
.th-j__legend li { display: inline-flex; align-items: center; gap: 8px; }
.th-j__legend i { width: 10px; height: 10px; border-radius: 50%; background: var(--c); }

.th-j { --nameh: 64px; --p: 1; position: relative; }
.th-js .th-j { --p: 0; }
.th-j__svg { position: absolute; left: 0; top: var(--nameh); width: 100%; height: var(--curveh); overflow: visible; pointer-events: none; }
.th-j__grid line { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 2 7; opacity: .7; }
.th-j__curve, .th-j__glow { fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: calc(1 - var(--p)); }
.th-j__curve { stroke-width: 3.5; }
.th-j__glow { stroke: url(#th-j-grad); stroke-width: 12; opacity: .22; filter: blur(7px); }

.th-j__list { position: relative; list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); }
.th-j__stage { display: flex; flex-direction: column; padding: 0 clamp(10px, 1.6vw, 24px); border-left: 1px solid var(--border); }
.th-j__stage:first-child { border-left-color: transparent; padding-left: 0; }
.th-j__name { display: flex; align-items: center; gap: 10px; height: var(--nameh); font-size: clamp(18px, 1.6vw, 22px); font-weight: 600; line-height: 1.2; letter-spacing: -.03em; }
.th-j__idx { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .06em; color: var(--text-4); }
.th-j__plot { height: var(--curveh); }
.th-j__txt { display: flex; flex-direction: column; gap: 22px; padding-top: 8px; }
.th-j__q, .th-j__a { display: flex; flex-direction: column; gap: 8px; font-size: 15px; line-height: 1.5; text-wrap: pretty; }
.th-j__q { color: var(--text-3); }
.th-j__a { color: #fff; }
.th-j__lbl { font-family: var(--mono); font-size: 11px; font-weight: 500; line-height: 1.3; letter-spacing: .08em; text-transform: uppercase; color: var(--text-4); }
.th-j__a .th-j__lbl { color: var(--blue-light); }

/* A dot per stage, on the curve: filled with the persona's colour and initial; it pops when the line reaches it. */
.th-j__dot {
  position: absolute; z-index: 2; left: calc((var(--i) + .5) / var(--n) * 100%);
  top: calc(var(--nameh) + var(--pad) + (1 - var(--m)) * (var(--curveh) - 2 * var(--pad)));
  display: grid; place-items: center; width: 30px; height: 30px; translate: -50% -50%; border-radius: 50%;
  background: var(--c); color: #0a0a0b; font-size: 13px; font-weight: 600; line-height: 1;
  box-shadow: 0 0 0 5px #000, 0 0 0 6px rgba(255,255,255,.16), 0 10px 26px color-mix(in srgb, var(--c) 45%, transparent);
  transition: scale .5s cubic-bezier(.34, 1.56, .64, 1), opacity .3s ease;
}
.th-js .th-j__dot { scale: .4; opacity: 0; }
.th-js .th-j__dot.is-on { scale: 1; opacity: 1; }
.th-j__rail { display: none; }

/* =====================================================================================================================
   4. "How we'd test it": three If / Then / Because cards
   ===================================================================================================================== */
.th-tests__list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 20px); }
.th-test { display: flex; flex-direction: column; border-radius: 28px; background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--border); overflow: hidden; transition: background-color .25s ease; }
.th-test:hover { background: var(--surface-2); }
.th-test__no { display: block; padding: clamp(22px, 2.4vw, 32px) clamp(22px, 2.4vw, 32px) 0; font-family: var(--mono); font-size: 12px; letter-spacing: .08em; color: var(--text-4); }
.th-test__rows { flex: 1; display: flex; flex-direction: column; gap: 0; margin: 0; padding: 12px clamp(22px, 2.4vw, 32px) clamp(22px, 2.4vw, 32px); }
.th-test__row { display: flex; flex-direction: column; gap: 6px; padding: 18px 0; border-top: 1px solid var(--border); }
.th-test__row:first-child { border-top: 0; }
.th-test dt { font-family: var(--mono); font-size: 11px; font-weight: 500; line-height: 1.3; letter-spacing: .08em; text-transform: uppercase; color: var(--text-4); }
.th-test__row:first-child dt, .th-test__row:nth-child(2) dt { color: var(--blue-light); }
.th-test dd { margin: 0; text-wrap: pretty; }
.th-test__rows dd { font-size: clamp(18px, 1.55vw, 21px); font-weight: 500; line-height: 1.35; letter-spacing: -.02em; }
.th-test__row--why dd { font-size: 16px; font-weight: 400; letter-spacing: -.01em; color: var(--text-3); }
.th-test__foot { display: grid; grid-template-columns: 1fr 1fr; margin: 0; background: var(--surface-2); border-top: 1px solid var(--border); }
.th-test__foot > div { display: flex; flex-direction: column; gap: 6px; padding: 18px clamp(22px, 2.4vw, 32px) 22px; }
.th-test__foot > div + div { border-left: 1px solid var(--border); }
.th-test__foot dd { font-size: 15px; line-height: 1.35; color: #fff; }
/* Three across: each card is three rows (number, the If / Then / Because rows, the metrics) on the list's own rows, so the metrics line up. */
@media (min-width: 960px) {
  .th-tests__list { grid-template-rows: auto 1fr auto; row-gap: 0; }
  .th-test { display: grid; grid-row: span 3; grid-template-rows: subgrid; }
}
/* The cards are dealt in when scrolled to (JS adds .is-in, one after another). Without JS they are simply there. */
.th-js .th-test { opacity: 0; translate: 0 48px; rotate: 1.4deg; transition: opacity .6s ease, translate .9s var(--ease-out), rotate .9s var(--ease-out), background-color .25s ease; transition-delay: calc(var(--i) * 120ms), calc(var(--i) * 120ms), calc(var(--i) * 120ms), 0s; }
.th-js .th-test.is-in { opacity: 1; translate: 0 0; rotate: 0deg; }

/* =====================================================================================================================
   Narrow screens
   ===================================================================================================================== */
@media (max-width: 1099px) {
  .th-brief__grid { grid-template-columns: 1fr; }
  .th-personas__list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .th-persona { grid-template-columns: 1fr; gap: 14px; }
}
/* Three across: each persona is four rows (avatar, name, need, doubt) on the list's own rows, so the names, needs and Doubt rules line up
   whatever each need's length. */
@media (min-width: 700px) and (max-width: 1099px) {
  .th-personas__list { grid-template-rows: repeat(4, auto); row-gap: 0; }
  .th-persona { grid-row: span 4; grid-template-rows: subgrid; row-gap: 14px; }
  .th-persona__body { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 6px; }
}
@media (max-width: 959px) {
  .th-tests__list { grid-template-columns: 1fr; }
  .th-test__rows { padding-top: 4px; }
}
/* Tablet portrait and phones: five columns would be ~140px each, so the journey becomes a vertical timeline with a progress line (JS fills
   --seg below 960px too: e2-theme.js, initJourney). */
@media (max-width: 959px) {
  .th-j { --nameh: 0px; }
  .th-j__svg, .th-j__plot, .th-j__grid { display: none; }
  .th-j__list { display: flex; flex-direction: column; }
  .th-j__stage { position: relative; padding: 0 0 40px 60px; border-left: 0; }
  .th-j__stage:first-child { padding-left: 60px; }
  .th-j__stage:last-child { padding-bottom: 0; }
  .th-j__name { height: 30px; font-size: 22px; }
  .th-j__txt { padding-top: 14px; gap: 18px; }
  .th-j__dot { left: 0; top: 0; translate: none; width: 30px; height: 30px; box-shadow: 0 0 0 4px #000, 0 0 0 5px rgba(255,255,255,.16), 0 8px 20px color-mix(in srgb, var(--c) 45%, transparent); }
  /* The timeline: a track from this stage's dot to the next one, filled by --seg (0 to 1) as the line is "drawn". */
  .th-j__stage::before, .th-j__stage::after { content: ""; position: absolute; left: 14px; top: 15px; width: 2px; height: 100%; border-radius: 1px; }
  .th-j__stage::before { background: var(--border-strong); }
  .th-j__stage::after { background: linear-gradient(var(--c), var(--cn, var(--c))); transform-origin: 0 0; transform: scaleY(var(--seg, 1)); }
  .th-js .th-j__stage::after { transform: scaleY(var(--seg, 0)); }
  .th-j__stage:last-child::before, .th-j__stage:last-child::after { display: none; }
}
/* Tablet portrait: the timeline has the width for "Where shoppers hesitate" and "What the design does" side by side, each label on one line. */
@media (min-width: 700px) and (max-width: 959px) {
  .th-j__txt { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; }
}
/* Phones: the stage turns portrait and the frame fills it (the journey's timeline is in the block above, from 959px down). */
@media (max-width: 699px) {
  .e2-cs__titlerow { flex-direction: column; align-items: flex-start; gap: 16px; }
  .e2-cs__concept { padding: 7px 12px 7px 10px; font-size: 11px; }
  .e2-cs__disclosure { font-size: 14px; }
  .th-hd__aside { font-size: 16px; }

  .th-hero { aspect-ratio: 4 / 5; border-radius: 22px; }
  .th-hero__lift { width: 88%; }
  .th-hero .th-viewport { aspect-ratio: 1440 / 1100 !important; }
  .th-hero .th-browser { border-radius: 10px; }
  .th-hero .th-browser__bar { height: 26px; padding: 0 9px; gap: 5px; }
  .th-hero .th-browser__bar i { width: 7px; height: 7px; }
  .th-hero .th-browser__bar::after { width: 30px; }
  .th-hero .th-browser__bar span { height: 17px; line-height: 17px; font-size: 9px; padding: 0 10px; border-radius: 5px; }
  .th-hero__sheen { border-radius: 10px; }
  /* Fewer, smaller objects on a phone (the one furthest back goes), pulled down off the browser bar and the storefront's nav (its logo, Cart),
     which end about 30% down the portrait stage. */
  .th-float { width: calc(var(--w) * 1.15); top: calc(var(--y) * .5 + 36%); }
  .th-float--far { display: none; }
  .th-hero__chips { gap: 6px; }
  .th-hero__chip { padding: 6px 10px; font-size: 11px; letter-spacing: .05em; }

  .th-doc { border-radius: 16px; clip-path: polygon(0 0, calc(100% - 36px) 0, 100% 36px, 100% 100%, 0 100%); }
  .th-doc::after { width: 36px; height: 36px; }
  .th-doc__bar { padding-right: 24px; }
  .th-doc__goal { font-size: 24px; }
  .th-personas__list { display: flex; }
  .th-persona { grid-template-columns: 44px minmax(0, 1fr); padding: 16px; border-radius: 18px; }
  .th-persona__av { width: 44px; height: 44px; font-size: 18px; }


  .th-tests__list { gap: 12px; }
  .th-test { border-radius: 22px; }
  /* The mono labels go up to 12px, the E2 phone size for the role (.ml-eyebrow, .bx-score__label); 11px stays from 700px up, where 12px
     would wrap the journey's labels unevenly across five columns. The hero's chips stay 11px pills, as .e2-cs__concept does. */
  .th-j__lbl, .th-test dt, .th-doc__k, .th-persona__k { font-size: 12px; }
}

/* =====================================================================================================================
   Reduced motion: no float, no tilt, no deal-in, no draw: everything shown finished. The video shows its poster and does not play, so the
   hero's pause button is gone too.
   ===================================================================================================================== */
@media (prefers-reduced-motion: reduce) {
  .th-hero__lift, .th-float, .th-float img { animation: none !important; }
  .th-hero__pause { display: none; }   /* the hero is already still: nothing to pause */
  .th-hero__frame { transform: rotateX(6deg); }
  .th-hero__sheen { display: none; }
  .th-float { translate: none; }
  .th-banner__video { opacity: 1; transition: none; }
  .th-js .th-doc [data-th-lit] .th-mark { background-size: 100% .58em; transition: none; }
  .th-js .th-j { --p: 1; }
  .th-js .th-j__dot { scale: 1; opacity: 1; transition: none; }
  .th-js .th-test { opacity: 1; translate: none; rotate: none; transition: none; }
  .th-js .th-j__stage::after { transform: scaleY(1); }
}
