/* =========================================================
   Six Humans — placeholder studio site
   Sections: tokens, base, layout, nav, cursor, hero,
   project grid, case study, about, contact, marquee,
   footer, transition, reveal, motion + responsive
   ========================================================= */

/* ---------- tokens ---------- */
:root {
  /* dark default — flipped from cream so the studio reads as a dark surface
     across nav + body. Per-project [data-project] presets still override
     for case study pages; .foot and .case-next stay dark by their own
     declarations. Light is opt-in via [data-theme="light"]. */
  --bg: #131313;
  --bg-deep: #0b0b0b;
  --ink: #efece5;
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.18);
  /* surface tokens — slight tint above the page bg for cards / pills /
     control containers. Auto-flip per theme so dark-on-dark and
     light-on-light always stay visible. */
  --surface:        rgba(239, 236, 229, 0.08);
  --surface-strong: rgba(239, 236, 229, 0.18);

  /* Liquid-glass tokens — reusable across nav, cursor, carousel
     controls, lightbox buttons. Three layers make the glass read as
     glass instead of "darken bg blur":
       1. backdrop-filter blur + saturate (colours behind stay vivid)
       2. inset top-edge highlight + bottom-edge shadow (the rim)
       3. a soft outer drop shadow (elevation off the page)            */
  --glass-blur: blur(24px) saturate(180%);
  /* Cap content + breathing-room on large monitors. Hugo & Marie /
     Instrument both let imagery go edge-to-edge but cap typography
     and add real margins on >1440px viewports. */
  --content-max: 1600px;

  --glass-bg-dark:    rgba(20, 20, 20, 0.7);
  --glass-shadow-dark:
    inset 0 1px 0  rgba(255, 255, 255, 0.20),
    inset 0 -1px 0 rgba(0,   0,   0,   0.20),
    0 1px 2px      rgba(0,   0,   0,   0.12),
    0 12px 32px    rgba(0,   0,   0,   0.22);

  --glass-bg-light:   rgba(255, 255, 255, 0.72);
  --glass-shadow-light:
    inset 0 1px 0  rgba(255, 255, 255, 0.85),
    inset 0 -1px 0 rgba(0,   0,   0,   0.05),
    0 1px 2px      rgba(0,   0,   0,   0.04),
    0 12px 32px    rgba(0,   0,   0,   0.10);

  --accent: #dd5c2c;
  --accent-ink: #fff8f2;

  --serif: "Instrument Serif", "Times New Roman", serif;
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, Menlo, monospace;

  --pad-x: clamp(20px, 4vw, 80px);
  --gutter: clamp(16px, 2vw, 36px);

  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 220ms;
  --dur: 420ms;
  --dur-slow: 800ms;
}

/* opt-in light surface for any subtree that needs to flip back */
[data-theme="light"] {
  --bg: #efece5;
  --bg-deep: #e6e2d8;
  --ink: #131313;
  --ink-soft: rgba(19, 19, 19, 0.62);
  --ink-mute: rgba(19, 19, 19, 0.38);
  --rule: rgba(19, 19, 19, 0.16);
  --surface:        rgba(19, 19, 19, 0.06);
  --surface-strong: rgba(19, 19, 19, 0.14);
}

html[data-page="home"] {
  --bg: #000000;
  --bg-deep: #050505;
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: auto;
  /* Match the footer's dark bg so iOS rubber-band overscroll past the
     footer doesn't reveal the page's per-project bg colour underneath
     — keeps the footer visually flush even when the body bg is light
     (aurora, halcyon) or any other project theme. */
  background: #131313;
  /* NOTE: don't add overflow-x: clip / hidden here. When one axis is
     clipped on the root element the other becomes a scrolling axis
     for descendants, and that breaks position: sticky elsewhere on the
     page (story-pin's phone went off-screen on mobile). Mobile
     horizontal scroll is contained per-section instead — see
     .story-callouts and .story-spread, both `overflow: hidden`. */
}
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  font-feature-settings: "ss01", "cv11";
  overflow-x: hidden;
  min-height: 100vh;
  min-height: 100dvh;       /* dynamic viewport on mobile so chrome retract doesn't leave a gap */
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  /* sticky-footer setup: when content is shorter than the viewport,
     <main> grows to fill so the footer always sits flush at the bottom
     — no slice of body bg peeking under the footer on mobile */
  display: flex;
  flex-direction: column;
}
main { flex: 1 0 auto; }

/* Project pages only: main is themed via the body bg (--bg = project
   colour). When main flex-grows past its content on short pages, the
   empty grown space showed the project theme right above the dark
   footer — visible as a stripe of project colour. Make main a flex
   column with a dark ::after filler that takes whatever space is left
   after the case sections. Content (case-header / -intro / -related)
   keeps the project theme; everything below the last section to the
   footer reads as one continuous dark surface. */
html[data-project] main {
  display: flex;
  flex-direction: column;
}
html[data-project] main::after {
  content: "";
  flex: 1 0 0;
  background: #131313;
}
/* Custom elements default to display: inline, which behaves oddly as a
   flex item — force block so <six-nav> + <six-footer> sit cleanly in
   the body's flex column and the footer always rides the bottom. */
six-nav, six-footer, six-carousel { display: block; }

a { color: inherit; text-decoration: none; }
img, svg, video { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
::selection { background: var(--ink); color: var(--bg); }

h1, h2, h3, h4 { margin: 0; font-weight: 400; letter-spacing: -0.01em; }
p { margin: 0; }

/* ---------- layout primitives ---------- */
.shell {
  width: 100%;
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
}
.row { display: flex; }
.between { justify-content: space-between; }
.center { align-items: center; }

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.rule {
  height: 1px;
  background: var(--rule);
  width: 100%;
  border: 0;
}

/* ---------- nav (transparent by default; liquid glass on scroll) ---------- */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px var(--pad-x);
  /* default: bar floats over content with no fill. Glass + blur fade in
     once vertical scrolling starts (.is-scrolled is added by initNav). */
  background: transparent;
  color: var(--nav-ink, var(--ink));
  /* Same view-transition-name across every page so the browser pairs
     the headers and morphs the bar between navigations instead of
     cross-fading it through the root group. Reads as one persistent nav. */
  view-transition-name: vtn-nav;
  transition: padding var(--dur) var(--ease-out),
              background 320ms var(--ease-out),
              color 320ms var(--ease-out),
              -webkit-backdrop-filter 320ms var(--ease-out),
                      backdrop-filter 320ms var(--ease-out);
}
.nav[data-theme="dark"]  { --nav-ink: #efece5; }
.nav[data-theme="light"] { --nav-ink: #131313; }

/* Sheet is open: the dark .sheet covers the page underneath the nav,
   so light-theme dark-ink logos + hamburger become invisible. Force
   cream ink + hide the halo gradient while open — works regardless of
   the page's base / section data-themes. */
.nav.is-open,
.nav.is-open[data-theme="light"],
.nav.is-open[data-base-theme="light"] {
  --nav-ink: #efece5;
  color: #efece5;
}
.nav.is-open::before { opacity: 0; }

/* Default-state halo — a soft dark gradient bleeding ~180px below the
   bar so the cream logo + links read clearly even when the nav is
   transparent and busy / bright content sits behind it. Fades out the
   moment the glass kicks in (.is-scrolled). On light-themed pages the
   gradient inverts to white so the dark logo stays legible. */
.nav::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 220px;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.66) 0%,
    rgba(0, 0, 0, 0.32) 55%,
    rgba(0, 0, 0, 0)    100%
  );
  pointer-events: none;
  z-index: -1;
  transition: opacity 360ms var(--ease-out);
}
.nav.is-scrolled::before { opacity: 0; }
/* Project pages: drop the nav halo entirely. The cover image already
   provides its own contrast band at the top, and the auto-theme
   handles ink colour. Keeping the halo over story-hero pages caused
   a visible smudge that didn't match the rest of the surface. */
html[data-project] .nav::before { display: none; }
.nav[data-base-theme="light"]::before,
.nav[data-theme="light"]::before {
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.6) 0%,
    rgba(255, 255, 255, 0.28) 55%,
    rgba(255, 255, 255, 0)    100%
  );
}
/* When a section explicitly sets data-nav-theme="dark", initNavTheme()
   writes data-theme="dark" on the nav. Without this override the
   page-level data-base-theme="light" rule above would still match and
   the halo would stay white over a dark hero/section. Source order
   gives this rule the cascade win; specificity is identical. */
.nav[data-theme="dark"]::before {
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.66) 0%,
    rgba(0, 0, 0, 0.32) 55%,
    rgba(0, 0, 0, 0)    100%
  );
}

/* Glass surface on scroll — uses the shared --glass-* tokens so the
   nav reads consistently with the cursor, controls, and lightbox.
   Theme-aware via data-base-theme (page-level) and data-theme
   (section-level overrides; rules come after so they win). */
.nav.is-scrolled {
  padding-top: 12px;
  padding-bottom: 12px;
  background: var(--nav-bg, var(--glass-bg-dark));
  box-shadow: var(--nav-shadow, var(--glass-shadow-dark));
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
}
.nav.is-scrolled[data-base-theme="dark"]  { --nav-bg: var(--glass-bg-dark);  --nav-shadow: var(--glass-shadow-dark); }
.nav.is-scrolled[data-base-theme="light"] { --nav-bg: var(--glass-bg-light); --nav-shadow: var(--glass-shadow-light); }
.nav.is-scrolled[data-theme="dark"]       { --nav-bg: var(--glass-bg-dark);  --nav-shadow: var(--glass-shadow-dark); }
.nav.is-scrolled[data-theme="light"]      { --nav-bg: var(--glass-bg-light); --nav-shadow: var(--glass-shadow-light); }

/* Browsers without backdrop-filter: bump opacity so the bar stays readable */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .nav.is-scrolled { background: var(--nav-bg, rgba(19, 19, 19, 0.92)); }
  .nav.is-scrolled[data-base-theme="dark"]  { --nav-bg: rgba(19, 19, 19, 0.92); }
  .nav.is-scrolled[data-base-theme="light"] { --nav-bg: rgba(239, 236, 229, 0.92); }
  .nav.is-scrolled[data-theme="dark"]       { --nav-bg: rgba(19, 19, 19, 0.92); }
  .nav.is-scrolled[data-theme="light"]      { --nav-bg: rgba(239, 236, 229, 0.92); }
}
.nav__brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--serif);
  font-size: 22px;
  letter-spacing: -0.01em;
}
.nav__brand-mark {
  width: 24px; height: 24px;
  flex: none;
  display: block;
  color: currentColor;
  /* default 16s/turn (was 18s — bumped speed ~10%); a one-shot fast
     spin for the first ~2s of every page load is added by JS via
     animation-duration override, then removed to settle back here */
  animation: nav-brand-spin 16s linear infinite;
  transform-origin: 50% 50%;
  transition: width 360ms var(--ease-out), height 360ms var(--ease-out);
  /* Cross-document View Transition: same name on both pages lets the
     browser morph the mark from home's 56px hero size down to the
     24px scrolled size when navigating into a project, and back. */
  view-transition-name: nav-brand-mark;
}
.nav__brand:hover .nav__brand-mark { animation-duration: 1.2s; }
@keyframes nav-brand-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .nav__brand-mark,
  .nav__brand:hover .nav__brand-mark { animation: none; }
}

/* Brand sizing rules:
   - Home + Project pages: hero-sized 56px mark + hidden wordmark by
     default; on scroll the mark shrinks to 24px and "Six Humans"
     fades in. Both pages share this default so the cross-document
     View Transition morph reads as identity at the start (the wheel
     doesn't visibly jump-shrink during navigation).
   - Other pages (info / contact): small mark + wordmark always visible.
   The cross-page size delta is animated by the View Transition API via
   view-transition-name: nav-brand-mark. */
:is(html[data-page="home"], html[data-project]) .nav__brand-mark {
  width: 56px; height: 56px;
}
:is(html[data-page="home"], html[data-project]) .nav__brand > span {
  display: inline-block;
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  transform: translateX(-6px);
  transition: max-width 360ms var(--ease-out),
              opacity 280ms var(--ease-out),
              transform 360ms var(--ease-out);
}
:is(html[data-page="home"], html[data-project]) .nav.is-scrolled .nav__brand-mark {
  width: 24px; height: 24px;
}
:is(html[data-page="home"], html[data-project]) .nav.is-scrolled .nav__brand > span {
  max-width: 14ch;
  opacity: 1;
  transform: translateX(0);
}
@media (prefers-reduced-motion: reduce) {
  :is(html[data-page="home"], html[data-project]) .nav__brand-mark,
  :is(html[data-page="home"], html[data-project]) .nav__brand > span { transition: none; }
}
.nav__links {
  display: flex; gap: 28px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.nav__links a {
  position: relative;
  padding: 6px 0;
}
.nav__links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease-out);
}
.nav__links a:hover::after,
.nav__links a[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

.nav__menu-btn { display: none; }

@media (max-width: 720px) {
  .nav__links { display: none; }
  .nav__menu-btn {
    display: inline-flex;
    flex-direction: column;
    gap: 5px;
    padding: 6px;
  }
  .nav__menu-btn { gap: 4px; }
  .nav__menu-btn span {
    display: block;
    width: 22px;
    /* whole-pixel height — fixes the visual asymmetry where the top
       line was rendering as 2px and the bottom as 1px on some
       viewports due to subpixel rounding of 1.5px */
    height: 2px;
    background: currentColor;
    transition: transform var(--dur) var(--ease-out);
  }
  /* lines are 2px tall with a 4px gap → centres 6px apart → each moves
     half that distance toward the midpoint to form a true X */
  .nav.is-open .nav__menu-btn span:nth-child(1) { transform: translateY(3px)  rotate(45deg); }
  .nav.is-open .nav__menu-btn span:nth-child(2) { transform: translateY(-3px) rotate(-45deg); }
}

/* mobile sheet — nav centered, social/copy at bottom; nav__menu-btn
   morphs into the close X (no separate close button) */
.sheet {
  position: fixed; inset: 0;
  background: #0e0e0e;
  color: rgba(239, 236, 229, 0.96);
  z-index: 45;
  display: grid;
  grid-template-rows: 1fr auto;
  padding: clamp(20px, 4vw, 56px);
  transform: translateY(-100%);
  transition: transform var(--dur-slow) var(--ease-in-out);
  pointer-events: none;
}
.sheet.is-open { transform: translateY(0); pointer-events: auto; }

.sheet__nav {
  align-self: center;
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 3.5vh, 40px);
  padding: 0 clamp(0px, 2vw, 32px);
}
.sheet__nav a {
  display: block;
  text-decoration: none;
  color: inherit;
}
.sheet__title {
  display: block;
  font-family: var(--serif);
  font-size: clamp(48px, 11vw, 96px);
  line-height: 1;
  letter-spacing: -0.02em;
}
.sheet__ext {
  font-size: 0.42em;
  vertical-align: super;
  margin-left: 0.18em;
  opacity: 0.6;
}

.sheet__foot {
  align-self: end;
  border-top: 1px solid rgba(239, 236, 229, 0.14);
  padding-top: 18px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
.sheet__social {
  list-style: none; padding: 0; margin: 0;
  display: flex; gap: clamp(14px, 2.4vw, 28px);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase;
}
.sheet__social a {
  text-decoration: none;
  color: rgba(239, 236, 229, 0.78);
  transition: color var(--dur) var(--ease-out);
}
.sheet__social a:hover { color: rgba(239, 236, 229, 1); }
.sheet__copyright {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(239, 236, 229, 0.5);
}

/* ---------- custom cursor ---------- */
@media (hover: hover) and (pointer: fine) {
  .cursor {
    position: fixed;
    top: 0; left: 0;
    pointer-events: none;
    z-index: 90;
    mix-blend-mode: difference;
    transform: translate3d(-50%, -50%, 0);
    will-change: transform;
  }
  .cursor__dot {
    width: 8px; height: 8px;
    border-radius: 50%;
    background: #efece5;
    transition: width var(--dur) var(--ease-out),
                height var(--dur) var(--ease-out),
                background-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                backdrop-filter var(--dur) var(--ease-out);
    /* no border — glass surfaces stay borderless to match the nav */
    border: 0;
  }
  .cursor__label {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%) scale(0.85);
    color: #131313;
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    white-space: nowrap;
    opacity: 0;
    transition: opacity var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out);
  }
  /* Expanded — iOS-style glass surface (drop the difference blend so the
     blur reads true to whatever's underneath). Two variants flip in based
     on the surface beneath: light-glass over dark, dark-glass over light. */
  .cursor.is-active {
    mix-blend-mode: normal;
  }
  .cursor.is-active .cursor__dot {
    width: 96px; height: 96px;
    backdrop-filter: blur(28px) saturate(180%);
    -webkit-backdrop-filter: blur(28px) saturate(180%);
    /* Light-glass default (works over the dark-themed sections like the
       footer + dark archive tiles). Borderless — relies on the inset
       highlight + drop shadow for definition. */
    background: rgba(255, 255, 255, 0.22);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.65),
      inset 0 -1px 0 rgba(0, 0, 0, 0.06),
      0 12px 40px rgba(0, 0, 0, 0.18);
  }
  .cursor.is-active .cursor__label {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
    /* Default label = dark ink on light-glass (iOS standard). */
    color: #131313;
    font-weight: 500;
    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.35);
  }
  /* Over a light surface → dark-glass + light label (so it reads). */
  .cursor.is-active.is-light-surface .cursor__dot {
    background: rgba(18, 18, 18, 0.42);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.12),
      inset 0 -1px 0 rgba(0, 0, 0, 0.18),
      0 12px 40px rgba(0, 0, 0, 0.22);
  }
  .cursor.is-active.is-light-surface .cursor__label {
    color: rgba(255, 255, 255, 0.96);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  }
  /* Browsers without backdrop-filter: scrim instead so the label still reads. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .cursor.is-active .cursor__dot { background: rgba(255, 255, 255, 0.85); }
    .cursor.is-active.is-light-surface .cursor__dot { background: rgba(20, 20, 20, 0.78); }
  }
  body.has-cursor, body.has-cursor a, body.has-cursor button { cursor: none; }
}

/* ---------- hero ---------- */
.hero {
  min-height: 100vh;
  padding: 120px var(--pad-x) 60px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  position: relative;
}
.hero__title {
  font-family: var(--serif);
  font-size: clamp(56px, 11vw, 168px);
  line-height: 0.92;
  letter-spacing: -0.02em;
  max-width: 14ch;
}
.hero__title em {
  font-style: italic;
  color: var(--accent);
}
.hero__meta {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: var(--gutter);
  margin-top: 60px;
  padding-top: 22px;
  border-top: 1px solid var(--rule);
}
.hero__meta dt { font-family: var(--mono); font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-soft); margin-bottom: 8px; }
.hero__meta dd { margin: 0; font-size: 14px; }
.hero__scroll {
  position: absolute;
  bottom: 24px; right: var(--pad-x);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: flex; align-items: center; gap: 10px;
}
.hero__scroll::after {
  content: ""; width: 28px; height: 1px; background: var(--ink-soft);
  display: inline-block;
}

@media (max-width: 720px) {
  .hero__meta { grid-template-columns: 1fr 1fr; row-gap: 22px; }
  .hero__scroll { display: none; }
}

/* ---------- section header ---------- */
.section {
  padding: clamp(80px, 12vw, 160px) var(--pad-x);
}
.section__head {
  display: flex; align-items: baseline; justify-content: space-between;
  border-top: 1px solid var(--rule);
  padding-top: 22px;
  margin-bottom: 60px;
  gap: 24px;
  flex-wrap: wrap;
}
.section__title {
  font-family: var(--serif);
  font-size: clamp(40px, 6vw, 88px);
  line-height: 1;
  letter-spacing: -0.02em;
  max-width: 18ch;
}

/* ---------- project grid ---------- */
.work {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
  row-gap: clamp(48px, 8vw, 120px);
}
.work__item {
  position: relative;
  overflow: hidden;
}
.work__item--lg { grid-column: span 12; }
.work__item--md { grid-column: span 7; }
.work__item--sm { grid-column: span 5; }
.work__item--off { grid-column: 4 / span 6; }
.work__item--right { grid-column: 7 / span 6; }
.work__item--left { grid-column: 1 / span 6; }

@media (max-width: 720px) {
  .work__item,
  .work__item--lg, .work__item--md, .work__item--sm,
  .work__item--off, .work__item--right, .work__item--left {
    grid-column: span 12;
  }
}

.work__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--bg-deep);
  overflow: hidden;
  border-radius: 2px;
}
.work__item--lg .work__media { aspect-ratio: 16 / 9; }
.work__item--sm .work__media { aspect-ratio: 3 / 4; }

/* placeholder gradient blocks (no copyrighted imagery) */
.ph {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 80% at 30% 20%, var(--ph-a, #c8b8a3) 0%, transparent 60%),
    radial-gradient(100% 100% at 80% 90%, var(--ph-b, #6a5a48) 0%, transparent 55%),
    var(--ph-base, #d6c9b3);
  transform: scale(1.001);
  transition: transform var(--dur-slow) var(--ease-out);
}
.ph::after {
  content: "";
  position: absolute; inset: 0;
  background-image:
    repeating-linear-gradient(45deg, rgba(0,0,0,0.04) 0 1px, transparent 1px 6px);
  mix-blend-mode: multiply;
  pointer-events: none;
}
.work__item:hover .ph { transform: scale(1.04); }

.work__caption {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-top: 18px;
  gap: 24px;
}
.work__name {
  font-family: var(--serif);
  font-size: clamp(20px, 2.4vw, 30px);
  letter-spacing: -0.005em;
}
.work__tags {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: right;
}
.work__index {
  position: absolute; top: 14px; left: 14px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.18em;
  color: var(--accent-ink);
  mix-blend-mode: difference;
  z-index: 2;
}

/* ---------- studio strip (about teaser on home) ---------- */
.studio {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--gutter);
  align-items: end;
}
.studio__lede {
  font-family: var(--serif);
  font-size: clamp(28px, 3.4vw, 48px);
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.studio__copy { font-size: 16px; max-width: 52ch; color: var(--ink-soft); }
.studio__cta {
  display: inline-flex; align-items: center; gap: 12px;
  margin-top: 28px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--ink);
  padding-bottom: 4px;
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.studio__cta:hover { color: var(--accent); border-color: var(--accent); }
@media (max-width: 720px) {
  .studio { grid-template-columns: 1fr; }
}

/* ---------- capabilities ---------- */
.caps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gutter);
  border-top: 1px solid var(--rule);
}
.caps__item {
  padding: 28px 0;
  border-bottom: 1px solid var(--rule);
}
.caps__num {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-mute);
  margin-bottom: 16px;
}
.caps__name {
  font-family: var(--serif); font-size: clamp(22px, 2.2vw, 30px);
  margin-bottom: 12px;
}
.caps__list {
  list-style: none; padding: 0; margin: 0;
  font-size: 14px; color: var(--ink-soft);
}
.caps__list li { padding: 4px 0; }
@media (max-width: 720px) { .caps { grid-template-columns: 1fr; } }

/* ---------- team grid ---------- */
.team {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gutter);
  row-gap: clamp(40px, 5vw, 64px);
}
.team__person { }
.team__avatar {
  aspect-ratio: 4 / 5;
  background: var(--bg-deep);
  margin-bottom: 16px;
  position: relative;
  overflow: hidden;
}
.team__name {
  font-family: var(--serif); font-size: 22px;
}
.team__role {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-soft);
  margin-top: 4px;
}
@media (max-width: 720px) { .team { grid-template-columns: 1fr 1fr; } }

/* ---------- marquee ---------- */
.marquee {
  display: flex;
  overflow: hidden;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  padding: 22px 0;
  gap: 56px;
  white-space: nowrap;
  user-select: none;
}
.marquee__track {
  display: flex; gap: 28px;
  flex: none;
  animation: marquee 60s linear infinite;
  font-family: var(--mono);
  font-weight: 400;
  font-size: clamp(11px, 0.9vw, 13px);
  letter-spacing: 0.06em;
  line-height: 1;
}
.marquee__track span em { font-style: italic; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee {
  to { transform: translateX(-50%); }
}

/* ---------- footer (planet + horizontal marquee) ---------- */
/* Footer is a "dark island" — overrides per-project theme inheritance so
   the planet + dark colour scheme stays correct on any page. */
.foot {
  --bg: #131313;
  --ink: #efece5;
  --bg-deep: #0b0b0b;
  --ink-soft: rgba(239, 236, 229, 0.68);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.18);
  background: var(--bg);
  color: var(--ink);
  padding: clamp(40px, 6vw, 80px) var(--pad-x) 28px;
  overflow: hidden;
  /* Same view-transition-name across every page so the footer morphs
     between navigations instead of cross-fading through the root. */
  view-transition-name: vtn-footer;
}
.foot__planet {
  position: relative;
  height: clamp(420px, 80vh, 780px);
  display: grid;
  place-items: center;
  margin-bottom: 56px;
}
.foot__globe {
  position: absolute;
  inset: 0;
  display: grid; place-items: center;
  pointer-events: none;
}
.foot__globe canvas,
.foot__globe img,
.foot__globe svg {
  width: clamp(360px, 72vh, 720px);
  height: clamp(360px, 72vh, 720px);
  display: block;
}
.foot__globe img,
.foot__globe svg {
  border-radius: 50%;
  object-fit: cover;
  filter: drop-shadow(0 30px 60px rgba(0,0,0,0.5));
}

.foot__marquee {
  position: absolute;
  inset-inline: 0;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  overflow: hidden;
  pointer-events: none;
}
.foot__marquee .marquee__track {
  display: flex;
  gap: 28px;
  flex: none;
  animation: marquee 60s linear infinite;
  font-family: var(--mono);
  font-weight: 400;
  font-size: clamp(11px, 0.9vw, 13px);
  letter-spacing: 0.06em;
  line-height: 1;
  color: #fff;
  white-space: nowrap;
}
.foot__marquee .marquee__track em { font-style: italic; }

.foot__rest {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding-bottom: 0;
  /* no border-bottom — was leaving a visible rule line at the foot of the
     footer block */
}

.foot__links {
  display: flex; gap: 28px;
  justify-content: flex-end;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.14em;
  text-transform: uppercase;
}
.foot__links a { transition: color var(--dur) var(--ease-out); }
.foot__links a:hover { color: var(--accent); }

.foot__base {
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  margin-top: 24px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.6;
}

@media (max-width: 720px) {
  .foot__planet { height: clamp(360px, 60vh, 540px); }
  .foot__rest { justify-content: flex-start; }
  .foot__links { justify-content: flex-start; flex-wrap: wrap; gap: 16px 24px; }
}

/* ---------- case study ---------- */
/* ─── Project case page (H&M /projects/ style) ────────────────────
   - Centered super-light uppercase serif title
   - Cover image directly below, overlapping the title's lower edge
   - Discipline pill-tags in mono uppercase
   - Centered narrow intro paragraph in light sans
   - Stacked full-width media with generous margins
   - Two-up "charmer" related-project cards
*/

.case-header {
  text-align: center;
  /* 140px floor so mobile reads tight without feeling crowded; 220px
     ceiling on huge monitors. Title sits below the nav halo for the
     small fade overlap we want, not far below it. */
  padding: clamp(140px, 13vw, 220px) 0 0;
}
.case-header__wrapper {
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 var(--pad-x);
}
/* Match story-hero cap so non-story projects don't dwarf story projects on big monitors. */
.case-header__title {
  font-family: var(--serif);
  font-weight: 400;
  /* Title sized 15% smaller across all responsive views (was 56-124px) */
  font-size: clamp(48px, 8.5vw, 106px);
  line-height: 0.95;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  margin: 0 auto;
  color: var(--ink);
  max-width: 50%;
}
@media (max-width: 720px) {
  .case-header__title { max-width: 100%; }
}
.case-header__title em { font-style: italic; }
.case-header__media {
  display: block;
  width: 100%;
  height: auto;
  margin: clamp(-18px, -1.4vw, -11px) auto 0;
  pointer-events: none;
  user-select: none;
  position: relative;
  z-index: 2;
}

/* centered intro paragraph */
.case-intro {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--pad-x) clamp(64px, 9vw, 128px);
  text-align: center;
}
.case-intro p {
  font-family: var(--sans);
  font-weight: 300;
  font-size: clamp(18px, 1.55vw, 22px);
  line-height: 1.45;
  letter-spacing: 0.005em;
  color: var(--ink);
  margin: 0 0 1em;
}
.case-intro p:last-child { margin-bottom: 0; }

/* stacked full-width media */
.case-media {
  width: 100%;
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 var(--pad-x);
}
.case-media__item {
  margin: 0 0 clamp(48px, 7vw, 120px);
  width: 100%;
}
.case-media__item:last-child { margin-bottom: clamp(80px, 12vw, 152px); }
.case-media__img {
  display: block;
  width: 100%;
  height: auto;
}

/* case body stack — mixed-aspect tiles for product / reel media.
   Slot a <div class="case-mesh ph-<slug>"> for a placeholder, or swap
   in <img data-cover data-video="…mp4"> when a real asset arrives.
   width:100% is critical here: <main> on project pages is display:flex
   column, and the auto cross-axis margins below would otherwise absorb
   all free space (since our children have aspect-ratio + zero
   inline content), collapsing the section to 2×pad-x wide. */
.case-stack {
  width: 100%;
  max-width: 1440px;
  margin: 0 auto clamp(64px, 9vw, 128px);
  padding: 0 var(--pad-x);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(16px, 2vw, 32px);
}
.case-stack__item {
  position: relative;
  margin: 0;
  border-radius: clamp(12px, 1.4vw, 22px);
  overflow: hidden;
  isolation: isolate;
  background: var(--bg-deep, #0a0a0a);
}
.case-stack__item--wide   { grid-column: 1 / -1; aspect-ratio: 16 / 9; }
.case-stack__item--tall   { aspect-ratio: 4 / 5; }
.case-stack__item--square { aspect-ratio: 1 / 1; }
.case-stack__item > .case-mesh,
.case-stack__item > img,
.case-stack__item > video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
@media (max-width: 720px) {
  .case-stack { grid-template-columns: 1fr; gap: 14px; }
  .case-stack__item--tall,
  .case-stack__item--square { aspect-ratio: 4 / 5; }
}

/* placeholder gradient — anchored on --bg so the tile always matches
   the page colour, just a darker hue. Two soft blooms in even darker
   tones layered over a slightly-darker-than-page base, plus a faint
   diagonal line grain. initProjectTheme() updates --bg from the cover
   at runtime so this tracks each project's actual sampled colour. */
.case-mesh {
  background: var(--bg-deep, #1a1a1a);  /* fallback when color-mix isn't supported */
  background:
    radial-gradient(120% 80% at 30% 20%, color-mix(in oklab, var(--bg) 80%, black 20%) 0%, transparent 60%),
    radial-gradient(100% 100% at 80% 90%, color-mix(in oklab, var(--bg) 65%, black 35%) 0%, transparent 55%),
    color-mix(in oklab, var(--bg) 88%, black 12%);
}
.case-mesh::after {
  content: "";
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(45deg, rgba(0,0,0,0.04) 0 1px, transparent 1px 6px);
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* "More projects" — exact same card style as the home archive grid.
   Reuses .archive__row + .archive__item so the cover-image View
   Transition morphs cleanly into the destination project's hero
   (cards are the same size on the source and destination pages).
   Initial state: 1 row of 3 cards visible; subsequent rows hidden
   behind a "See more" button. */
.case-related {
  width: 100%;
  margin: 0 auto;
  padding: 0;
}
.case-related__heading {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft, #888);
  margin: 0 0 clamp(20px, 2.4vw, 32px);
  padding: 0 var(--pad-x);
}
.case-related__more {
  display: block;
  margin: clamp(28px, 3vw, 48px) auto 0;
  padding: 12px 28px;
  background: transparent;
  border: 1px solid var(--ink, currentColor);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink, currentColor);
  cursor: pointer;
  transition: background 220ms var(--ease-out), color 220ms var(--ease-out);
}
.case-related__more:hover,
.case-related__more:focus {
  background: var(--ink, currentColor);
  color: var(--bg, #131313);
}
.case-related__more[hidden] { display: none; }

/* ---------- contact ---------- */
.contact {
  padding: 160px var(--pad-x) 100px;
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--gutter);
}
.contact__title {
  font-family: var(--serif);
  font-size: clamp(48px, 9vw, 124px);
  line-height: 0.95;
  letter-spacing: -0.02em;
}
.contact__form {
  display: grid; gap: 24px;
}
.contact__row {
  display: grid; gap: 8px;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 12px;
}
.contact__row label {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-soft);
}
.contact__row input,
.contact__row textarea,
.contact__row select {
  background: transparent;
  border: 0;
  font: inherit;
  color: inherit;
  font-size: 18px;
  padding: 4px 0;
  outline: none;
  resize: vertical;
  font-family: var(--serif);
}
.contact__row textarea { min-height: 120px; }
.contact__submit {
  justify-self: start;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.18em;
  text-transform: uppercase;
  background: var(--ink); color: var(--bg);
  padding: 16px 28px;
  border-radius: 999px;
  transition: background var(--dur) var(--ease-out);
}
.contact__submit:hover { background: var(--accent); }
.contact__info { display: grid; gap: 32px; align-content: start; }
.contact__info h4 {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-soft);
  margin-bottom: 8px;
}
.contact__info p { font-family: var(--serif); font-size: 22px; }

/* ---------- contact: intro + department list ---------- */
.contact-intro {
  padding: clamp(120px, 14vw, 200px) var(--pad-x) clamp(48px, 6vw, 80px);
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--gutter);
  align-items: end;
}
.contact-intro__lede {
  font-family: var(--serif);
  font-size: clamp(40px, 6vw, 88px);
  line-height: 1;
  letter-spacing: -0.02em;
  margin: 0;
  max-width: 16ch;
}
.contact-intro__note {
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: 38ch;
  margin: 0;
}

.dept-list {
  padding: 0 var(--pad-x);
  border-top: 1px solid var(--rule);
}
.dept-list__item {
  display: grid;
  grid-template-columns: 5fr 2fr 4fr 3fr;
  gap: var(--gutter);
  align-items: baseline;
  padding: clamp(24px, 3.6vw, 48px) 0;
  border-bottom: 1px solid var(--rule);
}
.dept-list__heading {
  font-family: var(--serif);
  font-size: clamp(28px, 4.4vw, 64px);
  letter-spacing: -0.01em;
  line-height: 0.95;
  margin: 0;
}
.dept-list__heading em { font-style: italic; color: var(--accent); }
.dept-list__person {
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink-soft);
  letter-spacing: 0.005em;
}
.dept-list__email {
  font-family: var(--sans);
  font-size: 15px;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 2px;
  justify-self: start;
  transition: color var(--dur, 200ms) ease, border-color var(--dur, 200ms) ease;
}
.dept-list__email:hover { color: var(--accent); border-color: var(--accent); }
.dept-list__phone {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  justify-self: end;
}
@media (max-width: 720px) {
  .contact-intro { grid-template-columns: 1fr; gap: 24px; }
  .dept-list__item { grid-template-columns: 1fr; gap: 10px; padding: 28px 0; }
  .dept-list__phone { justify-self: start; }
}

/* 2-col services block (capabilities, lighter than .caps) */
.svc-grid {
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 6vw, 80px) var(--gutter);
  border-top: 1px solid var(--rule);
}
.svc-grid__item {}
.svc-grid__num {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-bottom: 16px;
}
.svc-grid__name {
  font-family: var(--serif);
  font-size: clamp(28px, 3.4vw, 44px);
  letter-spacing: -0.01em;
  line-height: 1;
  margin: 0 0 18px;
}
.svc-grid__list {
  list-style: none;
  padding: 0;
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.55;
}
.svc-grid__list li {
  padding: 6px 0;
  border-top: 1px solid var(--rule);
}
.svc-grid__list li:first-child { border-top: 0; }
@media (max-width: 720px) { .svc-grid { grid-template-columns: 1fr; } }
@media (max-width: 720px) {
  .contact { grid-template-columns: 1fr; }
}

/* ---------- page transitions (native, cross-document) ---------- */
/* Browsers that support cross-document View Transitions get a quick fade
   between pages. Browsers that don't fall through to a normal page load
   (which is fast and clean — no overlay jank). */
@view-transition { navigation: auto; }

/* Default cross-document fade — kept subtle and quick so nav between
   any two pages feels like one continuous surface. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 360ms;
  animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
}

/* Named pairs (cover-<slug>) morph the cover image between the home
   archive tile and the project header. Slightly slower + same easing
   as the rest of the site so the morph reads as a cohesive movement,
   not a new page load. */
::view-transition-group(*) {
  animation-duration: 580ms;
  animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
}
::view-transition-group(root) {
  animation-duration: 360ms;
}

/* ---------- custom elements (hide undefined to avoid FOUC) ---------- */
six-nav:not(:defined),
six-footer:not(:defined),
six-carousel:not(:defined) { visibility: hidden; }

/* ---------- reveal ---------- */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
  transition-delay: var(--delay, 0ms);
}
.reveal.is-in { opacity: 1; transform: translateY(0); }

.reveal-clip {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
}
.reveal-clip > span {
  display: inline-block;
  transform: translateY(110%);
  transition: transform 1000ms var(--ease-in-out);
  transition-delay: var(--delay, 0ms);
}
.reveal-clip.is-in > span { transform: translateY(0); }

/* ---------- motion preferences ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .reveal-clip > span { transform: none; }
}

/* ---------- placeholder palette utility classes ---------- */
.ph-warm     { --ph-base: #e6c9a3; --ph-a: #f0d5af; --ph-b: #7a5232; }
.ph-cool     { --ph-base: #c4cdd1; --ph-a: #dde3e6; --ph-b: #424c52; }
.ph-ink      { --ph-base: #1a1a1a; --ph-a: #303030; --ph-b: #000; }

/* ---------- carousel (swipe + autoplay + progress ring) ---------- */
.carousel {
  padding: clamp(80px, 12vw, 160px) 0 clamp(60px, 9vw, 100px);
}
.carousel__head {
  padding: 22px var(--pad-x) 0;
  display: flex; align-items: baseline; justify-content: space-between;
  border-top: 1px solid var(--rule);
  margin-bottom: 56px;
  gap: 24px;
  flex-wrap: wrap;
}
.carousel__title {
  font-family: var(--serif);
  font-size: clamp(40px, 6vw, 88px);
  line-height: 1;
  letter-spacing: -0.02em;
  max-width: 18ch;
}
.carousel__title em { font-style: italic; color: var(--accent); }

.carousel__track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding: 0 var(--pad-x);
  gap: var(--gutter);
  scroll-behavior: smooth;
}
.carousel__track::-webkit-scrollbar { display: none; }

/* slide: rounded card, text centered top, media below */
.carousel__slide {
  flex: 0 0 calc(100% - var(--pad-x) * 2);
  scroll-snap-align: start;
  background: var(--bg-deep);
  border-radius: clamp(20px, 2.6vw, 32px);
  padding: clamp(48px, 7vw, 96px) clamp(28px, 5vw, 64px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(32px, 5vw, 64px);
  margin: 0;
}
.carousel__copy {
  text-align: center;
  max-width: 30ch;
  will-change: transform, opacity;
}
.carousel__copy .eyebrow { display: block; margin-bottom: 14px; }
.carousel__copy h3 {
  font-family: var(--serif);
  font-size: clamp(28px, 3.6vw, 52px);
  line-height: 1.08;
  letter-spacing: -0.01em;
  margin-bottom: 14px;
}
.carousel__copy h3 em { font-style: italic; color: var(--accent); }
.carousel__copy p {
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: 36ch;
  margin: 0 auto;
}

.carousel__media {
  position: relative;
  width: 100%;
  max-width: 540px;
  aspect-ratio: 1 / 1;
  border-radius: 14px;
  overflow: hidden;
  background: rgba(19,19,19,0.04);
}
.carousel__media .ph { position: absolute; inset: 0; }

/* controls: dots pill on left, play pill on right — both light gray, same height */
.carousel__controls {
  --ctrl-h: 44px;
  display: flex; align-items: center; justify-content: center;
  gap: 12px;
  padding: 44px var(--pad-x) 0;
}
.carousel__dots {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  list-style: none;
  margin: 0;
  background: var(--glass-bg-dark);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-dark);
  height: var(--ctrl-h);
  padding: 0 22px;
  border-radius: 999px;
}
.carousel__dots li { display: block; }
.carousel__dots button {
  display: block;
  width: 8px; height: 8px;
  padding: 0; border: 0; cursor: pointer;
  border-radius: 999px;
  background: var(--ink-mute);
  position: relative;
  overflow: hidden;
  transition: width 380ms var(--ease-out), background 380ms var(--ease-out);
}
.carousel__dots button.is-active {
  width: 40px;
  background: var(--surface-strong);
}
.carousel__dots button.is-active::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--ink);
  border-radius: 999px;
  transform: scaleX(var(--progress, 0));
  transform-origin: left center;
}

.carousel__play {
  background: var(--glass-bg-dark);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-dark);
  border: 0;
  width: var(--ctrl-h); height: var(--ctrl-h);
  border-radius: 999px;
  display: inline-grid; place-items: center;
  color: var(--ink);
  cursor: pointer;
  transition: background var(--dur) var(--ease-out);
}
.carousel__play:hover { background: var(--surface-strong); }
.carousel__icon {
  width: 14px; height: 14px;
  fill: currentColor;
}
.carousel.is-playing .icon-play { display: none; }
.carousel.is-paused  .icon-pause { display: none; }

@media (max-width: 720px) {
  .carousel__slide { padding: 40px 24px; gap: 28px; }
  .carousel__copy h3 { font-size: 26px; }
  .carousel__media { max-width: 100%; }
  .carousel__controls { --ctrl-h: 40px; gap: 10px; }
  .carousel__dots { padding: 0 18px; gap: 8px; }
  .carousel__dots button.is-active { width: 32px; }
}

/* ---------- per-project theme tokens ----------
   Set as CSS fallback so case study pages render in their theme even
   before JS runs. JS may upgrade these by sampling the actual cover
   image once it loads. Each preset declares: --bg (page background),
   --bg-deep (slightly darker for inset surfaces), --ink (foreground),
   plus the soft / mute / rule variants computed from --ink. */


[data-project="monzo"] {
  --bg: #485242;
  --bg-deep: #3a4434;
  --ink: rgb(239, 236, 229);
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-monzo { --ph-base: #485242; --ph-a: #606a5a; --ph-b: #1c2616; }

[data-project="cometeer"] {
  --bg: #886569;
  --bg-deep: #7a575b;
  --ink: rgb(239, 236, 229);
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-cometeer { --ph-base: #886569; --ph-a: #a07d81; --ph-b: #5c393d; }

[data-project="current-rebrand"] {
  --bg: #a2a3a6;
  --bg-deep: #949598;
  --ink: rgb(19, 19, 19);
  --ink-soft: rgba(19, 19, 19, 0.62);
  --ink-mute: rgba(19, 19, 19, 0.38);
  --rule: rgba(19, 19, 19, 0.16);
}
.ph-current-rebrand { --ph-base: #a2a3a6; --ph-a: #babbbe; --ph-b: #76777a; }

[data-project="current"] {
  --bg: #5d5d2c;
  --bg-deep: #4f4f1e;
  --ink: rgb(239, 236, 229);
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-current { --ph-base: #5d5d2c; --ph-a: #757544; --ph-b: #313100; }

[data-project="current-nft-rewards"] {
  --bg: #8fb0ab;
  --bg-deep: #81a29d;
  --ink: rgb(19, 19, 19);
  --ink-soft: rgba(19, 19, 19, 0.62);
  --ink-mute: rgba(19, 19, 19, 0.38);
  --rule: rgba(19, 19, 19, 0.16);
}
.ph-current-nft-rewards { --ph-base: #8fb0ab; --ph-a: #a7c8c3; --ph-b: #63847f; }

[data-project="quipbrush"] {
  --bg: #7d584a;
  --bg-deep: #6f4a3c;
  --ink: rgb(239, 236, 229);
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-quipbrush { --ph-base: #7d584a; --ph-a: #957062; --ph-b: #512c1e; }

[data-project="quipcare"] {
  --bg: #78645a;
  --bg-deep: #6a564c;
  --ink: rgb(239, 236, 229);
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-quipcare { --ph-base: #78645a; --ph-a: #907c72; --ph-b: #4c382e; }

[data-project="vimeo-ios"] {
  --bg: #989eb2;
  --bg-deep: #8a90a4;
  --ink: rgb(19, 19, 19);
  --ink-soft: rgba(19, 19, 19, 0.62);
  --ink-mute: rgba(19, 19, 19, 0.38);
  --rule: rgba(19, 19, 19, 0.16);
}
.ph-vimeo-ios { --ph-base: #989eb2; --ph-a: #b0b6ca; --ph-b: #6c7286; }

[data-project="daily-harvest"] {
  --bg: #cdc6c5;
  --bg-deep: #bfb8b7;
  --ink: rgb(19, 19, 19);
  --ink-soft: rgba(19, 19, 19, 0.62);
  --ink-mute: rgba(19, 19, 19, 0.38);
  --rule: rgba(19, 19, 19, 0.16);
}
.ph-daily-harvest { --ph-base: #cdc6c5; --ph-a: #e5dedd; --ph-b: #a19a99; }

[data-project="vimeo-androidtv"] {
  --bg: #747270;
  --bg-deep: #666462;
  --ink: rgb(239, 236, 229);
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-vimeo-androidtv { --ph-base: #747270; --ph-a: #8c8a88; --ph-b: #484644; }

[data-project="glamsquad-booking"] {
  --bg: #746b6c;
  --bg-deep: #665d5e;
  --ink: rgb(239, 236, 229);
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-glamsquad-booking { --ph-base: #746b6c; --ph-a: #8c8384; --ph-b: #483f40; }

/* ============ Feed rail (homepage top) ============ */
/* All three feed measurements share the same clamp so the badge, the
   first rail card, and the vertical breathing room above the section
   all read as one unified spacing rhythm. */
.feed-section {
  /* Shared inset for the rail's first card AND the head badge — defined
     once here so they can never drift apart on any viewport. Bumped
     floor from 80 to 120 so mobile feels more clearly inset. */
  --rail-inset: clamp(120px, 14vw, 220px);
  padding: clamp(80px, 12vw, 200px) 0 clamp(40px, 5vw, 64px);
}
.feed-rail {
  display: flex;
  gap: clamp(10px, 1vw, 16px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  /* Generous left inset so the first card doesn't sit flush against the
     page padding edge — gives the rail a clearer "carousel" read. */
  padding: 0 var(--pad-x) 4px var(--rail-inset);
  /* scroll-padding so scroll-snap doesn't yank scrollLeft past the
     left padding and slam the first card flush against the viewport
     edge — without this, scroll-snap-align:start aligns each item to
     the scroll port's start (which by default is *inside* the padding). */
  scroll-padding-inline-start: var(--rail-inset);
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
}
.feed-rail::-webkit-scrollbar { display: none; }
.feed-rail__item {
  flex: 0 0 auto;
  /* Fixed height; width is driven by each image's natural aspect ratio
     so every card sits at the same height in the rail but each asset
     reads at its own proportions instead of being object-fit-cropped. */
  height: clamp(380px, 50vw, 560px);
  scroll-snap-align: start;
  background: var(--surface);
  overflow: hidden;
  position: relative;
  border-radius: clamp(20px, 2.4vw, 28px);
  transition: transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
  cursor: pointer;
  display: block;
}
.feed-rail__item:hover { transform: translateY(-4px); }
.feed-rail__item img {
  height: 100%;
  width: auto;
  display: block;
  filter: saturate(0.96);
  transition: filter 240ms ease;
}
.feed-rail__item:hover img { filter: saturate(1.04); }
@media (max-width: 720px) {
  .feed-rail__item { height: clamp(360px, 70vw, 480px); }
}
@media (prefers-reduced-motion: reduce) {
  .feed-rail__item { transition: none; }
  .feed-rail__item:hover { transform: none; }
}

/* ============ H&M-style homepage layout ============ */

/* — Feed rail controls (carousel-style) — */
.feed-section__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: clamp(20px, 2vw, 32px) var(--pad-x) 0;
}
.feed-section__controls .carousel__dots {
  --ctrl-h: 40px;
}
.feed-section__controls .carousel__play { --ctrl-h: 40px; }
.feed-section__controls.is-playing .icon-play { display: none; }
.feed-section__controls.is-paused .icon-pause { display: none; }

/* Subtle hover feedback on the dots — same visual change as tap
   (bg shifts to surface-strong) without the width expansion. Each
   dot you hover lights up slightly so you know it's clickable. */
@media (hover: hover) {
  .carousel__dots button:not(.is-active):hover {
    background: var(--surface-strong);
  }
}
@media (max-width: 720px) {
  .feed-section__controls { gap: 10px; --ctrl-h: 36px; }
  .feed-section__controls .carousel__dots { padding: 0 14px; gap: 8px; }
  .feed-section__controls .carousel__dots button.is-active { width: 32px; }
}

/* — Archive grid (row blocks) —
   Each .archive__row is its own 2-col grid. Two patterns:
   --double  → two 16:9 rectangles, side-by-side.
   --triple-left / --triple-right → one ~square (8:9, fills both rows of the
   block) on left or right, plus two stacked 16:9 rectangles on the other side.
   Two stacked 16:9s on a 50vw column = 56.25vw tall, which matches an 8:9 tile
   on the other 50vw column — so heights line up cleanly. */
.archive {
  display: flex;
  flex-direction: column;
  gap: 0;
  background: var(--bg-deep, #0a0a0a);
}
.archive__row {
  display: grid;
  gap: 0;
  grid-template-columns: 1fr 1fr;
}
/* Lead row — featured square on the left, two stacked projects on the
   right. The square spans both rows; the right-side cards are 2:1 each
   so they sum to the same height as the square. */
.archive__row--lead {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
}
.archive__row--lead .archive__item:nth-child(1) {
  grid-row: 1 / span 2;
  aspect-ratio: 1 / 1;
}
.archive__row--lead .archive__item:nth-child(2),
.archive__row--lead .archive__item:nth-child(3) {
  /* 2:1 wide so two stacked cards equal the square's height */
  aspect-ratio: 2 / 1;
}
/* Trailing solo row (e.g. odd-count overflow). 16:9 wide, full row. */
.archive__row--solo {
  grid-template-columns: 1fr;
  grid-template-rows: auto;
}
.archive__row--solo .archive__item:nth-child(1) {
  grid-row: auto;
  grid-column: auto;
  aspect-ratio: 16 / 9;
}
.archive__item {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  text-decoration: none;
  color: #fff;
  background: var(--bg-deep, #0a0a0a);
  isolation: isolate;
}
.archive__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 1;
  z-index: 0;
  transition: transform 800ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.archive__item:hover .archive__image,
.archive__item:focus .archive__image { transform: scale(1.015); }
/* Default: bottom-up scrim so the white caption reads on any image
   without obscuring the top half. Hover deepens it slightly. */
.archive__item::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.62) 0%,
    rgba(0, 0, 0, 0.32) 38%,
    rgba(0, 0, 0, 0)    72%
  );
  z-index: 1;
  pointer-events: none;
  transition: opacity 280ms linear;
}
.archive__item:hover::after,
.archive__item:focus::after {
  opacity: 1.18;     /* perceived depth bump on hover */
}
.archive__caption {
  position: absolute;
  left: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  padding: clamp(20px, 2.4vw, 44px);
  z-index: 3;
  /* Title + excerpt cap at 50% of the card so each line breathes */
  max-width: 50%;
  /* visible by default — no hover required */
  opacity: 1;
  transform: translateY(0);
  transition: transform 360ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.archive__item:hover .archive__caption,
.archive__item:focus .archive__caption {
  transform: translateY(-2px);  /* subtle lift, keeps the affordance */
}
/* Title + excerpt now share the same regular body type — same size,
   same weight, same family. Title only differs by colour weight on
   accessibility (white vs cream-with-alpha). Excerpt clamps at 2
   lines so a longer sentence doesn't blow the card out. */
.archive__title,
.archive__excerpt {
  font-family: var(--sans);
  font-size: clamp(14px, 1.05vw, 17px);
  font-weight: 400;
  letter-spacing: 0.015em;
  line-height: 1.4;
  margin: 0;
  color: #fff;
}
.archive__title { margin-bottom: 6px; }
.archive__excerpt {
  color: rgba(255, 255, 255, 0.78);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
@media (max-width: 720px) {
  /* Single-column on mobile. The square lead only kicks in once
     the 2-per-row breakpoint takes over above 720px. Below, every
     card — including the first — is the standard 4:3 stacked tile. */
  .archive__row,
  .archive__row--lead { grid-template-columns: 1fr; grid-template-rows: none; }
  .archive__row--lead .archive__item:nth-child(1) {
    grid-row: auto;
    aspect-ratio: 4 / 3;
  }
  .archive__row--lead .archive__item:nth-child(2),
  .archive__row--lead .archive__item:nth-child(3) {
    aspect-ratio: 4 / 3;
  }
  .archive__item { aspect-ratio: 4 / 3; }
}

/* Section spacer between hero and discipline bar */

/* ---------- lightbox (gallery view for feed images) ----------
   Minimal dark glass overlay matching the rest of the site's frosted UI.
   Click backdrop or close button or hit ESC to dismiss; arrows or swipe
   to step. Reuses the borderless glass-pill treatment used by the nav
   and cursor — no rules, just inset highlight + drop shadow + blur. */
.lightbox {
  position: fixed; inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, 0.78);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
          backdrop-filter: blur(24px) saturate(180%);
  color: rgba(239, 236, 229, 0.92);
  opacity: 0;
  transition: opacity 220ms var(--ease-in-out);
}
.lightbox.is-open { opacity: 1; }
.lightbox[hidden] { display: none; }

.lightbox__stage {
  width: min(92vw, 1280px);
  height: min(86vh, 1280px);
  position: relative;
  overflow: hidden;
}
/* 3-slide stitched track — prev / current / next side by side, the
   track translates to centre the current. */
.lightbox__track {
  display: flex;
  width: 100%;
  height: 100%;
  transform: translate3d(-100%, 0, 0);
  transition: transform 320ms cubic-bezier(0.65, 0, 0.35, 1);
  will-change: transform;
}
.lightbox__track > .lightbox__img {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: auto;
}

/* No browser focus ring on default open — the dialog auto-focuses the
   close button (or used to) and Chrome would draw a blue square. We
   skip the auto-focus in JS and replace the default ring with a
   subtle custom one for keyboard users. */
.lightbox__close,
.lightbox__nav { outline: none; }
.lightbox__close:focus-visible,
.lightbox__nav:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.5);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .lightbox__track { transition: none; }
}

.lightbox__nav,
.lightbox__close {
  position: absolute;
  display: inline-grid; place-items: center;
  width: 44px; height: 44px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  /* Light glass over the dark backdrop — same recipe as the rest of
     the site's glass UI, so the lightbox buttons read as part of the
     same material system. */
  background: var(--glass-bg-light);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-light);
  color: rgba(239, 236, 229, 0.95);
  cursor: pointer;
  transition: background 220ms var(--ease-out);
}
.lightbox__nav:hover,
.lightbox__close:hover { background: rgba(255, 255, 255, 0.78); }
.lightbox__nav svg,
.lightbox__close svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* Lightbox prev / next stack at the bottom right (next outermost,
   prev tucked just inside it). Close stays top right. */
.lightbox__nav--prev,
.lightbox__nav--next {
  bottom: clamp(20px, 3vw, 48px);
  top: auto;
  transform: none;
}
.lightbox__nav--next { right: clamp(20px, 3vw, 48px); left: auto; }
.lightbox__nav--prev { right: calc(clamp(20px, 3vw, 48px) + 54px); left: auto; }
.lightbox__close    { top: clamp(20px, 3vw, 48px); right: clamp(20px, 3vw, 48px); }

.lightbox__counter {
  position: absolute;
  bottom: clamp(20px, 3vh, 36px);
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  color: rgba(239, 236, 229, 0.7);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

@media (max-width: 720px) {
  /* Touch: keep the arrows visible (smaller, hugged to the edges) so a
     tap is still an option alongside swipe. */
  .lightbox__nav,
  .lightbox__close { width: 38px; height: 38px; }
  .lightbox__nav svg,
  .lightbox__close svg { width: 14px; height: 14px; }
  .lightbox__nav--next { right: 20px; left: auto; }
  .lightbox__nav--prev { right: calc(20px + 46px); left: auto; }
  .lightbox__close { top: 22px; right: 22px; }
  .lightbox__stage { width: 96vw; height: 78vh; }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox,
  .lightbox__img { transition: none; }
}

/* ---------- page-load reveal (every page, every load) ----------
   Replaces the home splash. Subtle, gentle: <main> fades in + tiny
   lift on first paint. Universal across home / project / info pages.
   Honours prefers-reduced-motion. */
@keyframes page-reveal {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: no-preference) {
  main { animation: page-reveal 720ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
  /* Skip on case study pages — the title already has its own
     reveal-clip slide-up + the cover gets a View Transition morph from
     the home tile. Stacking another <main> fade on top makes the
     header read as jumpy. */
  html[data-project] main { animation: none; }
}

/* ---------- live feed badge (pulsing dot) ---------- */
.feed-section__head {
  /* Anchored to the rail's --rail-inset so the badge always sits exactly
     above the first card's left edge — no possibility of drift. */
  padding: 0 var(--pad-x) clamp(14px, 1.6vw, 22px) var(--rail-inset);
  display: flex;
  justify-content: flex-start;
  text-align: left;
}
.feed-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px 6px 12px;
  border-radius: 999px;
  background: var(--surface);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.feed-badge__dot {
  position: relative;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #e84545;
  flex: none;
}
/* radar-style ping — a clone of the dot scales up and fades, on loop */
.feed-badge__dot::after {
  content: "";
  position: absolute;
  inset: 0;
  background: inherit;
  border-radius: inherit;
  animation: feed-pulse 1.8s cubic-bezier(0.16, 0.84, 0.44, 1) infinite;
}
@keyframes feed-pulse {
  0%   { transform: scale(1);   opacity: 0.55; }
  100% { transform: scale(3.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .feed-badge__dot::after { animation: none; }
}

/* ---------- feed control: drag-to-scrub the rail ----------
   Hold + drag horizontally on the dots pill to scrub the feed.
   The control scales up with a small overshoot so the gesture reads
   as bouncy / liquid, not stiff. */
.feed-section__controls {
  transform-origin: center bottom;
  /* ease-out-back curve: overshoots ~6% before settling, gives the
     scale-up a soft bounce — the "liquid" feel of native iOS controls */
  transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
  touch-action: pan-y;
}
.feed-section__controls.is-dragging {
  transform: scale(1.18);
}
.feed-section__controls.is-dragging .carousel__dots,
.feed-section__controls.is-dragging .carousel__play {
  cursor: grabbing;
}
.feed-section__controls .carousel__dots { cursor: grab; }

[data-project="stealth-luxury-auction"] {
  --bg: #1c1614;
  --bg-deep: #0e0806;
  --ink: #efece5;
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.2);
}
.ph-stealth-luxury-auction { --ph-base: #1c1614; --ph-a: #342e2c; --ph-b: #000000; }

/* ---------- share FAB ----------
   Floating glass pill anchored bottom-right on every page. Tap →
   navigator.share() on Web Share API browsers (mobile Safari, Android
   Chrome); falls back to clipboard copy + toast on desktop. */
.share-fab {
  position: fixed;
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  right: calc(20px + env(safe-area-inset-right, 0px));
  z-index: 100;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 0;
  display: grid;
  place-items: center;
  cursor: pointer;
  background: var(--glass-bg-dark);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-dark);
  color: #efece5;
  transition: transform 240ms cubic-bezier(0.34, 1.56, 0.64, 1),
              background 220ms var(--ease-out),
              color 220ms var(--ease-out),
              box-shadow 220ms var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
/* Light-themed pages (Current rebrand, Daily Harvest, etc.) — match the
   nav's white-glass treatment so the FAB harmonises with the surface
   instead of punching a dark dot through a light hero. */
html[data-base-theme="light"] .share-fab {
  background: var(--glass-bg-light);
  box-shadow: var(--glass-shadow-light);
  color: #131313;
}
html[data-base-theme="light"] .share-fab__toast {
  background: var(--glass-bg-light);
  box-shadow: var(--glass-shadow-light);
  color: #131313;
}
.share-fab:hover { transform: scale(1.06); }
.share-fab:active { transform: scale(0.94); }
.share-fab:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.share-fab__icon {
  width: 18px; height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Tiny upward nudge so the arrow looks centred against the box base. */
  transform: translateY(-1px);
}
.share-fab__toast {
  position: absolute;
  right: calc(100% + 10px);
  top: 50%;
  transform: translate(8px, -50%);
  white-space: nowrap;
  background: var(--glass-bg-dark);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-dark);
  padding: 8px 14px;
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #efece5;
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms var(--ease-out),
              transform 220ms var(--ease-out);
}
.share-fab.is-toasted .share-fab__toast {
  opacity: 1;
  transform: translate(0, -50%);
}
@media (prefers-reduced-motion: reduce) {
  .share-fab,
  .share-fab__toast { transition: none; }
  .share-fab:hover,
  .share-fab:active { transform: none; }
}

/* ============================================================
   Interactive primitives — <six-stepper>, <six-toggle>,
   <six-prototype>. Composed inside .case-stack tiles to give
   each project a touchable signature moment.
   ============================================================ */

/* --- six-stepper --------------------------------------- */
six-stepper {
  position: absolute;
  inset: 0;
  display: block;
  background: var(--bg-deep, #0a0a0a);
  isolation: isolate;
  overflow: hidden;
}
.six-stepper__track {
  display: flex;
  width: 100%;
  height: 100%;
  transform: translateX(calc(var(--i, 0) * -100%));
  transition: transform 560ms cubic-bezier(0.34, 1.04, 0.5, 1);
  will-change: transform;
}
.six-stepper__slide {
  flex: 0 0 100%;
  position: relative;
  height: 100%;
  overflow: hidden;
}
.six-stepper__slide img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.six-stepper__caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: clamp(14px, 2vw, 24px) clamp(16px, 2.4vw, 28px) calc(clamp(54px, 6vw, 80px) + 8px);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #efece5;
  background: linear-gradient(to top, rgba(0,0,0,0.66) 0%, rgba(0,0,0,0) 100%);
  pointer-events: none;
  z-index: 2;
}
.six-stepper__controls {
  --ctrl-h: 36px;
  position: absolute;
  bottom: clamp(12px, 1.6vw, 22px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 10px;
}
.six-stepper__controls .carousel__dots { padding: 0 14px; gap: 8px; height: var(--ctrl-h); }
.six-stepper__controls .carousel__play { width: var(--ctrl-h); height: var(--ctrl-h); }

/* --- six-toggle (before/after slider) ------------------ */
six-toggle {
  position: absolute;
  inset: 0;
  overflow: hidden;
  isolation: isolate;
  cursor: ew-resize;
  background: var(--bg-deep, #0a0a0a);
  user-select: none;
  -webkit-user-select: none;
  touch-action: pan-y;
}
.six-toggle__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
.six-toggle__clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Position derived from the host's --toggle-pos so the clip, seam,
     and handle all stay locked together as the user drags. */
  clip-path: inset(0 calc(100% - var(--toggle-pos, 50%)) 0 0);
}
.six-toggle__tag {
  position: absolute;
  top: clamp(10px, 1.4vw, 18px);
  z-index: 3;
  padding: 6px 12px;
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  background: var(--glass-bg-dark);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-dark);
  color: #efece5;
  pointer-events: none;
}
.six-toggle__tag--before { left: clamp(10px, 1.4vw, 18px); }
.six-toggle__tag--after  { right: clamp(10px, 1.4vw, 18px); }
/* Two independent elements driven by --toggle-pos on the host:
   - .six-toggle__seam tracks the position EXACTLY (the visible split).
   - .six-toggle__handle is CLAMPED so the 44px grip stays inside the
     frame at both ends. The seam keeps moving past the handle as the
     user drags toward the edge — that's the correct visual feedback
     and matches how Apple / NYT before-after sliders behave. */
.six-toggle__seam {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--toggle-pos, 50%);
  width: 2px;
  transform: translateX(-50%);
  background: rgba(255, 255, 255, 0.85);
  pointer-events: none;
  z-index: 3;
}
.six-toggle__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  /* 64px hit-target wide enough to grab on touch. The whole button is
     transparent — only the grip orb inside is visible. */
  width: 64px;
  /* Clamp keeps the grip 32px in from each edge so its 44px circle
     can't poke outside the frame at 0% / 100%. */
  left: clamp(32px, var(--toggle-pos, 50%), calc(100% - 32px));
  transform: translateX(-50%);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: ew-resize;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
}
.six-toggle__handle-grip {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--glass-bg-dark);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-dark);
  position: relative;
  display: grid;
  place-items: center;
  color: #efece5;
}
.six-toggle__handle-grip::before,
.six-toggle__handle-grip::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 0; height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  transform: translateY(-50%);
}
.six-toggle__handle-grip::before { left: 11px;  border-right: 6px solid currentColor; }
.six-toggle__handle-grip::after  { right: 11px; border-left:  6px solid currentColor; }
.six-toggle__handle:focus-visible { outline: 2px solid #efece5; outline-offset: 4px; }
six-toggle.is-dragging .six-toggle__layer { transition: none; }

/* --- six-prototype (device frame) ---------------------- */
six-prototype {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--bg-deep, #0a0a0a);
  padding: clamp(14px, 2vw, 28px);
  isolation: isolate;
}
.six-prototype__device {
  position: relative;
  height: 100%;
  display: grid;
  place-items: center;
}
/* iPhone frame: tall card, rounded, with a small notch pill. */
.six-prototype__device--iphone {
  aspect-ratio: 9 / 19.5;
  height: 100%;
  max-height: 100%;
  background: #0a0a0a;
  border: 1.5px solid rgba(255, 255, 255, 0.18);
  border-radius: 32px;
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.6),
              inset 0 0 0 6px rgba(0, 0, 0, 0.7);
  padding: 8px;
  overflow: hidden;
}
.six-prototype__device--iphone .six-prototype__notch {
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  width: 28%;
  height: 22px;
  background: #000;
  border-radius: 999px;
  z-index: 2;
}
/* Android TV frame: 16:9 with thin bezel. */
.six-prototype__device--androidtv {
  aspect-ratio: 16 / 9;
  width: 100%;
  max-width: 100%;
  background: #0a0a0a;
  border: 1.5px solid rgba(255, 255, 255, 0.18);
  border-radius: 12px;
  padding: 10px;
}
/* Web frame: browser-like header dots + window. */
.six-prototype__device--web {
  aspect-ratio: 16 / 10;
  width: 100%;
  max-width: 100%;
  background: #0a0a0a;
  border: 1.5px solid rgba(255, 255, 255, 0.18);
  border-radius: 12px;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.six-prototype__device--web::before {
  content: "";
  height: 26px;
  background:
    radial-gradient(circle at 14px 50%, #ff5f57 0 5px, transparent 5px),
    radial-gradient(circle at 30px 50%, #febc2e 0 5px, transparent 5px),
    radial-gradient(circle at 46px 50%, #28c840 0 5px, transparent 5px),
    rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 12px 12px 0 0;
  flex: none;
}
.six-prototype__screen {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 24px;
  overflow: hidden;
  isolation: isolate;
}
.six-prototype__device--androidtv .six-prototype__screen,
.six-prototype__device--web .six-prototype__screen {
  border-radius: 6px;
  flex: 1 1 auto;
}

/* Light-themed pages: invert the device frame for contrast. */
html[data-base-theme="light"] .six-prototype__device {
  background: #fff;
  border-color: rgba(0, 0, 0, 0.18);
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.18),
              inset 0 0 0 6px rgba(255, 255, 255, 0.7);
}
html[data-base-theme="light"] .six-prototype__device--iphone .six-prototype__notch {
  background: #1a1a1a;
}

@media (prefers-reduced-motion: reduce) {
  .six-stepper__slide { transition: none; }
}



/* Project template — neutral dark fallback. initProjectTheme() samples
   the cover at runtime and overrides these, so the values only matter
   for the brief moment before JS mounts. Keeping them neutral means
   any cover image works without preset edits. */
[data-project="project-template"] {
  --bg: #131313;
  --bg-deep: #0a0a0a;
  --ink: #efece5;
  --ink-soft: rgba(239, 236, 229, 0.7);
  --ink-mute: rgba(239, 236, 229, 0.4);
  --rule: rgba(239, 236, 229, 0.18);
}
.ph-project-template { --ph-base: #0e1c24; --ph-a: #1a313e; --ph-b: #03070a; }

/* ============================================================
   Story layout — Instrument-style case study (long, scroll-driven,
   theme-changing). Used by halcyon.html. Self-contained .story-*
   namespace so it doesn't collide with the existing .case-* layout.
   ============================================================ */

main.story {
  display: block;        /* opt out of the case-stack flex column */
  width: 100%;
}
main.story::after { content: none; }

/* Eyebrow / typography */
.story-eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft, rgba(255,255,255,0.6));
  display: inline-block;
}
.story-h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(36px, 5vw, 72px);
  line-height: 1.04;
  letter-spacing: -0.02em;
  margin: 0;
}
.story-h2--narrow { max-width: 22ch; }
.story-h3 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(28px, 3.6vw, 52px);
  line-height: 1.08;
  letter-spacing: -0.015em;
  margin: 12px 0 0;
}
.story-h3--small { font-size: clamp(20px, 1.8vw, 26px); }
.story-h4 {
  font-family: var(--sans);
  font-weight: 500;
  font-size: clamp(18px, 1.5vw, 22px);
  letter-spacing: -0.005em;
  line-height: 1.25;
  margin: 18px 0 8px;
}
.story-body {
  font-family: var(--sans);
  font-weight: 300;
  font-size: clamp(16px, 1.2vw, 19px);
  line-height: 1.55;
  color: var(--ink-soft, rgba(255,255,255,0.72));
  margin: 18px 0 0;
  max-width: 56ch;
}
.story-caption {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
  margin: 24px 0 0;
}

/* 1 — HERO */
.story-hero {
  position: relative;
  /* On a 27" monitor 100svh is ~1440px — way too tall for a cover.
     Cap so a story hero stays at viewport-poster scale, not poster-poster. */
  min-height: clamp(640px, 92svh, 1080px);
  width: 100%;
  background: var(--bg-deep, #0a0a0a);
  color: #efece5;
  display: grid;
  align-items: end;
  overflow: hidden;
  isolation: isolate;
}
.story-hero__media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  z-index: -1;
}
.story-hero__shade {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(0,0,0,0.18) 0%,
    rgba(0,0,0,0.10) 32%,
    rgba(0,0,0,0.62) 100%);
  z-index: 0;
  pointer-events: none;
}
.story-hero__copy {
  position: relative; z-index: 1;
  padding: clamp(80px, 10vw, 140px) var(--pad-x) clamp(80px, 12vw, 160px);
  display: grid;
  gap: clamp(14px, 2vw, 22px);
  max-width: 1440px;
  margin: 0 auto;
  width: 100%;
}
.story-hero__title {
  font-family: var(--serif);
  font-weight: 400;
  /* Sized 15% smaller across all responsive views (was 64-168px) */
  font-size: clamp(54px, 10.2vw, 143px);
  line-height: 0.94;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  margin: 0;
}
.story-hero__title span { display: inline-block; }
.story-hero__tagline {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(20px, 2.4vw, 32px);
  letter-spacing: -0.01em;
  line-height: 1.25;
  max-width: 28ch;
  margin: 0;
  color: rgba(239, 236, 229, 0.86);
}
.story-hero__scroll {
  position: absolute;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(239, 236, 229, 0.72);
  z-index: 2;
  animation: story-scroll-pulse 2.4s ease-in-out infinite;
}
@keyframes story-scroll-pulse {
  0%, 100% { transform: translate(-50%, 0); opacity: 0.5; }
  50%      { transform: translate(-50%, 6px); opacity: 0.95; }
}

/* 2 — SETUP (intro + meta, 2-col on desktop) */
.story-setup {
  background: #efece5;
  color: #131313;
  padding: clamp(80px, 10vw, 160px) var(--pad-x);
}
.story-setup__intro,
.story-setup__meta {
  max-width: 1440px;
  margin: 0 auto;
}
.story-setup {
  display: grid;
  grid-template-columns: 8fr 4fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}
.story-setup__intro { padding-left: 0; }
.story-setup__intro .story-eyebrow { color: rgba(19,19,19,0.6); margin-bottom: 22px; }
.story-setup__intro .story-body { color: rgba(19,19,19,0.72); }
.story-setup__meta {
  display: grid;
  gap: 18px;
  margin: 0;
}
.story-setup__meta div {
  display: grid;
  gap: 4px;
  padding-top: 14px;
  border-top: 1px solid rgba(19,19,19,0.18);
}
.story-setup__meta dt {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(19,19,19,0.55);
}
.story-setup__meta dd {
  margin: 0;
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 400;
  line-height: 1.4;
  color: #131313;
}
@media (max-width: 900px) {
  .story-setup { grid-template-columns: 1fr; gap: 40px; }
}

/* 3 + 11 — BAND (full-bleed colour band with text overlay) */
.story-band {
  position: relative;
  width: 100%;
  min-height: 80vh;
  display: grid;
  align-items: center;
  overflow: hidden;
  isolation: isolate;
  padding: clamp(80px, 10vw, 160px) var(--pad-x);
  color: #efece5;
}
.story-band--midnight { background: #1a1d3a; }
.story-band--cream {
  background: #efece5;
  color: #131313;
}
.story-band__media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: -1;
  filter: brightness(0.7) saturate(0.94);
}
.story-band--cream .story-band__media { filter: brightness(0.96) saturate(0.96); }
.story-band__copy {
  position: relative;
  max-width: 1440px;
  margin: 0 auto;
  width: 100%;
}
.story-band__copy--bottom { align-self: end; }
.story-quote-lead {
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(28px, 4.4vw, 64px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  margin: 0;
  max-width: 18ch;
}

/* 4 — SCREENS RAIL (horizontal scroll-snap of phone-aspect cards) */
.story-screens {
  background: #131313;
  color: #efece5;
  padding: clamp(80px, 10vw, 140px) 0;
}
.story-screens__head {
  /* Uniform section-head rhythm — same as every other story-* head */
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-screens__rail {
  display: flex;
  gap: clamp(12px, 1.4vw, 22px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline-start: var(--pad-x);
  padding: clamp(40px, 5vw, 72px) var(--pad-x);
  scrollbar-width: none;
}
.story-screens__rail::-webkit-scrollbar { display: none; }
.story-screens__phone {
  flex: 0 0 auto;
  width: clamp(220px, 28vw, 360px);
  scroll-snap-align: start;
  display: grid;
  gap: 14px;
  margin: 0;
}
.story-screens__phone img {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  border-radius: clamp(20px, 2.4vw, 32px);
  background: #0a0a0a;
}
.story-screens__phone h4 {
  font-family: var(--sans);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.01em;
  margin: 0;
  color: #efece5;
}
.story-screens__phone p {
  font-family: var(--sans);
  font-weight: 300;
  font-size: 14px;
  line-height: 1.4;
  margin: 0;
  color: rgba(239, 236, 229, 0.62);
}

/* 5 — PAIR (image + text side-by-side) */
.story-pair {
  background: #131313;
  color: #efece5;
  padding: clamp(60px, 8vw, 120px) var(--pad-x) clamp(80px, 10vw, 140px);
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: clamp(32px, 4vw, 72px);
  align-items: center;
  max-width: 1440px;
  margin: 0 auto;
}
.story-pair__media {
  margin: 0;
  border-radius: clamp(12px, 1.4vw, 24px);
  overflow: hidden;
}
.story-pair__media img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}
.story-pair__copy { display: grid; gap: 14px; }
@media (max-width: 900px) {
  .story-pair { grid-template-columns: 1fr; gap: 32px; }
}

/* 6 — QUOTE (centred, light bg) */
.story-quote {
  background: #efece5;
  color: #131313;
  padding: clamp(80px, 12vw, 200px) var(--pad-x);
  text-align: center;
}
.story-quote blockquote {
  margin: 0 auto;
  max-width: 24ch;
}
.story-quote blockquote p {
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(28px, 4vw, 64px);
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 0;
}
.story-quote cite {
  display: block;
  margin: 32px 0 0;
  font-family: var(--mono);
  font-style: normal;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(19,19,19,0.55);
}

/* 7 — REEL (autoplay stepper as the "video") */
.story-reel {
  background: #131313;
  color: #efece5;
  padding: clamp(60px, 8vw, 120px) var(--pad-x);
}
.story-reel__frame {
  position: relative;
  max-width: 1440px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  border-radius: clamp(12px, 1.4vw, 24px);
  overflow: hidden;
  background: #000;
  isolation: isolate;
}

/* 8 — FRAME (numbered list 01 / 02 / 03) */
.story-frame {
  background: #efece5;
  color: #131313;
  padding: clamp(80px, 10vw, 160px) var(--pad-x);
  max-width: 1440px;
  margin: 0 auto;
}
.story-frame .story-h2 { color: #131313; margin-bottom: clamp(40px, 6vw, 80px); }
.story-frame__list {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(28px, 3vw, 56px);
}
.story-frame__list li {
  display: grid;
  gap: 0;
}
.story-frame__num {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.22em;
  color: rgba(19,19,19,0.45);
}
.story-frame__list .story-h4 { color: #131313; }
.story-frame__list p {
  font-family: var(--sans);
  font-weight: 300;
  font-size: 15px;
  line-height: 1.55;
  color: rgba(19,19,19,0.7);
  margin: 0;
}
@media (max-width: 900px) {
  .story-frame__list { grid-template-columns: 1fr; gap: 36px; }
}

/* 9 — TOGGLE (wrap around <six-toggle>) */
.story-toggle {
  background: #131313;
  color: #efece5;
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
}
.story-toggle__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-toggle__stage {
  position: relative;
  max-width: 1200px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  border-radius: clamp(12px, 1.4vw, 24px);
  overflow: hidden;
  isolation: isolate;
}

/* 10 — STATS (3 big numbers in a row) */
/* Full-width band: bg fills the viewport on huge monitors, but the grid
   itself stays capped at 1440px via padding-inline math. Drop max-width
   + margin auto — those caused the bg to leave gutters of page-bg on
   wide screens, which read as a mismatched container. */
.story-stats {
  background: #131313;
  color: #efece5;
  padding-block: clamp(80px, 10vw, 140px);
  padding-inline: max(var(--pad-x), calc((100% - 1440px) / 2));
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(28px, 4vw, 80px);
  border-top: 1px solid rgba(255,255,255,0.08);
}
.story-stat { display: grid; gap: 12px; }
.story-stat__num {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(52px, 8vw, 128px);
  line-height: 0.95;
  letter-spacing: -0.04em;
}
.story-stat__num span {
  font-size: 0.4em;
  font-weight: 400;
  color: rgba(239,236,229,0.6);
  margin-left: 4px;
}
.story-stat__label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(239, 236, 229, 0.55);
  max-width: 24ch;
}
@media (max-width: 900px) {
  .story-stats { grid-template-columns: 1fr; gap: 36px; }
}

/* 13 — UP NEXT (single big card) */
.story-next {
  background: #131313;
}
.story-next__card {
  position: relative;
  display: block;
  aspect-ratio: 21 / 9;
  overflow: hidden;
  isolation: isolate;
  text-decoration: none;
  color: #fff;
}
.story-next__card .archive__image {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 800ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.story-next__card:hover .archive__image,
.story-next__card:focus .archive__image { transform: scale(1.02); }
.story-next__card::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top,
    rgba(0,0,0,0.62) 0%,
    rgba(0,0,0,0.32) 36%,
    rgba(0,0,0,0)    72%);
  pointer-events: none;
}
.story-next__overlay {
  position: absolute;
  left: 0; bottom: 0;
  padding: clamp(28px, 4vw, 64px) var(--pad-x);
  z-index: 2;
  display: grid;
  gap: 8px;
  color: #fff;
  max-width: 720px;
}
.story-next__overlay .story-eyebrow { color: rgba(255,255,255,0.7); }
.story-next__title {
  font-family: var(--serif);
  font-size: clamp(48px, 8vw, 128px);
  font-weight: 400;
  line-height: 0.95;
  letter-spacing: -0.03em;
  margin: 0;
  color: #fff;
}
.story-next__caption {
  font-family: var(--sans);
  font-weight: 300;
  font-size: 15px;
  color: rgba(255,255,255,0.84);
}
@media (max-width: 900px) {
  .story-next__card { aspect-ratio: 4 / 3; }
}

/* ---------- More projects (2-col archive cards) ---------- */
/* Wraps the .archive grid as a project-page section, matching the
   home grid's 2-col cards exactly (size, scrim, captions). */
.story-related {
  /* Sits flush against the credits section above — no padding. The
     archive grid inside fills edge-to-edge from the dark/light seam. */
  background: #131313;
  color: #efece5;
  padding: 0;
}

/* Dark-section text overrides.
   These sections hardcode bg #131313 (so they stay dark regardless of
   the page's auto-theme), but their child elements still inherit
   eyebrow / body colours from var(--ink-soft) which on a light-themed
   page resolves to dark text — invisible on dark bg. Force cream
   inside every hardcoded-dark section so headings, eyebrows, and body
   copy all read on the dark surface. */
:is(.story-screens, .story-tape, .story-pin, .story-columns,
    .story-pip, .story-stats, .story-toggle, .story-pair,
    .story-reel, .story-wallet, .story-related) {
  /* Eyebrow + body text — cream with alpha for hierarchy */
  --story-dark-eyebrow: rgba(239, 236, 229, 0.62);
  --story-dark-body:    rgba(239, 236, 229, 0.72);
}
:is(.story-screens, .story-tape, .story-pin, .story-columns,
    .story-pip, .story-stats, .story-toggle, .story-pair,
    .story-reel, .story-wallet, .story-related) .story-eyebrow {
  color: var(--story-dark-eyebrow);
}
:is(.story-screens, .story-tape, .story-pin, .story-columns,
    .story-pip, .story-stats, .story-toggle, .story-pair,
    .story-reel, .story-wallet, .story-related) .story-body,
:is(.story-screens, .story-tape, .story-pin, .story-columns,
    .story-pip, .story-stats, .story-toggle, .story-pair,
    .story-reel, .story-wallet, .story-related) p {
  color: var(--story-dark-body);
}
:is(.story-screens, .story-tape, .story-pin, .story-columns,
    .story-pip, .story-stats, .story-toggle, .story-pair,
    .story-reel, .story-wallet, .story-related)
:is(h1, h2, h3, h4, h5, h6) {
  color: #efece5;
}

/* Hairline between adjacent dark sections so stacked dark blocks
   (screens+tape, wallet+pin, stats+related) read as distinct rather
   than one giant black wall. Sub-pixel cream rule, barely there. */
:is(.story-screens, .story-tape, .story-pin, .story-columns,
    .story-pip, .story-stats, .story-toggle, .story-pair,
    .story-reel, .story-wallet, .story-related) {
  border-top: 1px solid rgba(239, 236, 229, 0.06);
}

/* ============================================================
   Showcase patterns — Oxbow case study. Ten different ways to
   display mobile screens, plus a wallet card stack. Each section
   is self-contained and theme-aware via the --bg / --ink tokens.
   ============================================================ */

/* shared phone shape */
.show-phone {
  display: block;
  aspect-ratio: 9 / 19.5;
  border-radius: clamp(18px, 2vw, 28px);
  background: #0a0a0a;
  object-fit: cover;
  width: 100%;
}

/* ---------- 2 — MASONRY PARALLAX ---------- */
.story-mosaic {
  background: #efece5;
  color: #131313;
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
  overflow: hidden;
}
.story-mosaic__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-mosaic__head .story-eyebrow { color: rgba(19,19,19,0.6); }
.story-mosaic__head .story-h3 { color: #131313; }
.story-mosaic__grid {
  max-width: 1440px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2vw, 32px);
  align-items: start;
}
.story-mosaic__cell {
  margin: 0;
  transform: translate3d(0, var(--scroll-shift, 0), 0);
  transition: transform 60ms linear;
  will-change: transform;
}
.story-mosaic__cell:nth-child(3n+2) { margin-top: clamp(40px, 6vw, 96px); }
.story-mosaic__cell:nth-child(3n+3) { margin-top: clamp(20px, 3vw, 56px); }
.story-mosaic__cell img { box-shadow: 0 24px 48px rgba(19,19,19,0.18); }
@media (max-width: 720px) {
  .story-mosaic__grid { grid-template-columns: repeat(2, 1fr); gap: 16px; }
  .story-mosaic__cell:nth-child(2n) { margin-top: 40px; }
}
@media (prefers-reduced-motion: reduce) {
  .story-mosaic__cell { transform: none !important; }
}

/* ---------- 4 — TAPE (auto-scroll marquee of phones, 2 rows) ---------- */
.story-tape {
  background: #131313;
  color: #efece5;
  /* Uniform section rhythm — match every other story-* section */
  padding: clamp(80px, 10vw, 140px) 0;
  overflow: hidden;
}
.story-tape__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-tape__row {
  display: flex;
  overflow: hidden;
  margin-bottom: clamp(14px, 2vw, 22px);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.story-tape__row .marquee__track {
  display: flex;
  gap: clamp(14px, 1.6vw, 22px);
  flex: 0 0 auto;
  padding-right: clamp(14px, 1.6vw, 22px);
  animation: tape-slide 48s linear infinite;
}
.story-tape__row--reverse .marquee__track {
  animation-direction: reverse;
  animation-duration: 60s;
}
.story-tape__row:hover .marquee__track { animation-play-state: paused; }
.story-tape__phone {
  flex: 0 0 auto;
  width: clamp(140px, 16vw, 200px);
  margin: 0;
}
.story-tape__phone img {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  border-radius: 18px;
  background: #0a0a0a;
}
@keyframes tape-slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .story-tape__row .marquee__track { animation: none; }
}

/* ---------- 5 — VERTICAL TICKER COLUMNS ---------- */
.story-columns {
  background: #131313;
  color: #efece5;
  /* Uniform section rhythm — match every other story-* section */
  padding: clamp(80px, 10vw, 140px) 0;
  overflow: hidden;
  position: relative;
}
.story-columns__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-columns__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(12px, 1.4vw, 22px);
  height: clamp(520px, 70vh, 760px);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
  padding: 0 var(--pad-x);
}
.story-columns__col {
  display: flex;
  flex-direction: column;
  gap: clamp(12px, 1.4vw, 22px);
  animation: columns-up 40s linear infinite;
}
.story-columns__col--down { animation: columns-down 50s linear infinite; }
.story-columns__col--slow { animation-duration: 60s; }
.story-columns__col--fast { animation-duration: 32s; }
.story-columns__col img {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  border-radius: 14px;
  background: #0a0a0a;
}
.story-columns__grid:hover .story-columns__col { animation-play-state: paused; }
@keyframes columns-up {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}
@keyframes columns-down {
  from { transform: translateY(-50%); }
  to   { transform: translateY(0); }
}
@media (max-width: 720px) {
  .story-columns__grid { grid-template-columns: repeat(3, 1fr); height: 600px; }
  .story-columns__col:last-child { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .story-columns__col { animation: none !important; }
}

/* ---------- 7 — CALLOUTS (single hero phone with annotations) ---------- */
.story-callouts {
  background: #efece5;
  color: #131313;
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
  /* Pin labels are absolute on the stage and would extend past the phone
     on narrow viewports — clip at the section so they can never push the
     document's scrollable width. The labels are still visible on hover
     because they sit inside the section's content rect. */
  overflow: hidden;
}
.story-callouts__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-callouts__head .story-eyebrow { color: rgba(19,19,19,0.6); }
.story-callouts__head .story-h3 { color: #131313; }
.story-callouts__stage {
  position: relative;
  max-width: 380px;
  margin: 0 auto;
}
.story-callouts__phone {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  border-radius: 32px;
  background: #0a0a0a;
  box-shadow: 0 40px 80px rgba(19,19,19,0.22);
}
.story-callouts__pin {
  position: absolute;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: rgba(255,255,255,0.92);
  border: 1px solid rgba(19,19,19,0.18);
  cursor: pointer;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: #131313;
  padding: 0;
  z-index: 2;
  transition: transform 240ms cubic-bezier(0.2,0.8,0.2,1), box-shadow 240ms ease;
  box-shadow: 0 6px 16px rgba(19,19,19,0.18);
}
.story-callouts__pin::before {
  content: "";
  position: absolute;
  inset: -8px;
  border-radius: 50%;
  border: 1px solid rgba(19,19,19,0.18);
  animation: callout-pulse 2.6s ease-in-out infinite;
}
.story-callouts__pin:hover,
.story-callouts__pin:focus-visible { transform: scale(1.15); }
.story-callouts__pin .story-callouts__label {
  position: absolute;
  left: 30px;
  top: 50%;
  transform: translateY(-50%) translateX(-6px);
  background: #131313;
  color: #efece5;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0;
  padding: 8px 12px;
  border-radius: 8px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms ease, transform 200ms ease;
}
.story-callouts__pin:hover .story-callouts__label,
.story-callouts__pin:focus-visible .story-callouts__label {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
.story-callouts__pin--right .story-callouts__label {
  left: auto; right: 30px;
  transform: translateY(-50%) translateX(6px);
}
.story-callouts__pin--right:hover .story-callouts__label,
.story-callouts__pin--right:focus-visible .story-callouts__label {
  transform: translateY(-50%) translateX(0);
}
@keyframes callout-pulse {
  0%, 100% { transform: scale(1);   opacity: 0.6; }
  50%      { transform: scale(1.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .story-callouts__pin::before { animation: none; }
}

/* ---------- 11 — WALLET (card stack via <six-card-fan>) ---------- */
.story-wallet {
  background: #131313;
  color: #efece5;
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
  overflow: hidden;
}
.story-wallet__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-wallet__stage {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  place-items: center;
  min-height: clamp(360px, 46vw, 520px);
}

/* ---------- 3 — PIN (sticky phone, scrolling text blocks) ---------- */
.story-pin {
  background: #131313;
  color: #efece5;
  padding: clamp(80px, 10vw, 140px) 0;
}
.story-pin__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-pin__grid {
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 var(--pad-x);
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}
.story-pin__phone-wrap {
  position: sticky;
  top: clamp(80px, 14vh, 140px);
  align-self: start;
}
.story-pin__stack {
  position: relative;
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  aspect-ratio: 9 / 19.5;
  border-radius: clamp(20px, 2.4vw, 32px);
  overflow: hidden;
  background: #000;
  box-shadow: 0 40px 80px rgba(0,0,0,0.45);
}
.story-pin__stack img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.story-pin__stack img:nth-child(1)             { opacity: 1; }
.story-pin__stack.is-screen-0 img              { opacity: 0; }
.story-pin__stack.is-screen-0 img:nth-child(1) { opacity: 1; }
.story-pin__stack.is-screen-1 img              { opacity: 0; }
.story-pin__stack.is-screen-1 img:nth-child(2) { opacity: 1; }
.story-pin__stack.is-screen-2 img              { opacity: 0; }
.story-pin__stack.is-screen-2 img:nth-child(3) { opacity: 1; }
.story-pin__stack.is-screen-3 img              { opacity: 0; }
.story-pin__stack.is-screen-3 img:nth-child(4) { opacity: 1; }
.story-pin__steps {
  display: grid;
  gap: clamp(60vh, 80vh, 88vh);
  padding: 30vh 0;
}
.story-pin__step {
  display: grid;
  gap: 14px;
  max-width: 38ch;
  opacity: 0.4;
  transition: opacity 400ms ease;
}
.story-pin__step.is-active { opacity: 1; }
.story-pin__step .story-eyebrow { color: var(--ink-mute); }
@media (max-width: 900px) {
  /* On a single-column grid the phone-wrap collapses to 0×0 because the
     stack inside is width:100% and the wrap inherits align-self:start —
     classic shrink-wrap circular dep. Force explicit width + keep the
     wrap sticky so the cross-fade still works while text scrolls past. */
  .story-pin__grid { grid-template-columns: 1fr; gap: 24px; }
  .story-pin__phone-wrap {
    position: sticky;
    top: clamp(72px, 12vh, 96px);
    width: 100%;
    max-width: 200px;
    margin: 0 auto;
    align-self: start;
    z-index: 1;
  }
  .story-pin__stack { max-width: 200px; }
  /* Each step needs its own scroll-region so the IO can swap screens
     cleanly. 60vh per gap + 18vh top/bottom breathing. */
  .story-pin__steps { gap: 60vh; padding: 18vh 0 24vh; }
  .story-pin__step { opacity: 0.4; max-width: none; text-align: center; margin: 0 auto; }
  .story-pin__step.is-active { opacity: 1; }
}

/* ---------- 6 — FAN STACK (<six-fan-stack>) ---------- */
.story-fan {
  background: #efece5;
  color: #131313;
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
  overflow: hidden;
}
.story-fan__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid;
  gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-fan__head .story-eyebrow { color: rgba(19,19,19,0.6); }
.story-fan__head .story-h3 { color: #131313; }
.story-fan__stage {
  max-width: 1200px;
  margin: 0 auto;
  display: grid; place-items: center;
  min-height: clamp(380px, 50vw, 540px);
}
six-fan-stack {
  display: block;
  position: relative;
  width: 100%;
  max-width: 600px;
  text-align: center;
}
.six-fan-stack__deck {
  position: relative;
  width: 100%;
  height: clamp(360px, 48vw, 480px);
  background: transparent;
  border: 0;
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
}
.six-fan-stack__card {
  position: absolute;
  width: clamp(140px, 18vw, 200px);
  margin: 0;
  z-index: var(--z, 1);
  transform: translate3d(0, var(--ty, 0), 0) rotate(var(--rot, 0));
  transform-origin: 50% 100%;
  transition: transform 600ms cubic-bezier(0.22, 0.61, 0.36, 1);
  filter: drop-shadow(0 18px 30px rgba(19,19,19,0.22));
}
.six-fan-stack__card img {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  border-radius: 22px;
  background: #0a0a0a;
  display: block;
}
.six-fan-stack__card figcaption {
  position: absolute;
  left: 50%;
  bottom: -28px;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(19,19,19,0.55);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 240ms ease;
}
six-fan-stack.is-open .six-fan-stack__card {
  transform: translate3d(var(--slide, 0), 0, 0) rotate(0);
}
six-fan-stack.is-open .six-fan-stack__card figcaption { opacity: 1; }
.six-fan-stack__hint {
  display: block;
  margin-top: 16px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(19,19,19,0.55);
}
@media (max-width: 720px) {
  .six-fan-stack__card { width: clamp(110px, 30vw, 160px); }
  six-fan-stack.is-open .six-fan-stack__card { --slide: calc(var(--slide-base, 78%) * 0.62); }
}
@media (prefers-reduced-motion: reduce) {
  .six-fan-stack__card { transition: none; }
}

/* ---------- 8 — TRACK (scroll-jack horizontal) ---------- */
.story-track {
  background: #efece5;
  color: #131313;
  /* Section height = pin (100vh) + scroll travel for the rail. 200vh
     was 280vh — trimmed so the section's vertical footprint matches
     the rest of the story-* rhythm and the user doesn't scroll three
     screens for one block. The rail still fully scroll-jacks. */
  height: 200vh;
  position: relative;
}
.story-track__pin {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  grid-template-columns: 100%;
  grid-template-rows: auto auto;
  /* Centre the head + rail vertically inside the 100vh pin so the
     leftover whitespace splits symmetrically above the head and below
     the rail rather than piling at the bottom. align-content:start was
     pushing everything to the top, leaving an empty bottom slab while
     the user finished the scroll-jack. */
  align-content: center;
  padding-block: clamp(80px, 10vw, 140px);
  overflow: hidden;
}
.story-track__head {
  /* Full column-width container; the inner eyebrow + h3 cap themselves
     at 720 and centre via auto margins. Match the same vertical rhythm
     as every other section head (40-72px bottom). */
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  text-align: center;
}
.story-track__head .story-eyebrow,
.story-track__head .story-h3 {
  display: block;
  max-width: 1440px;
  margin-inline: auto;
}
.story-track__head .story-eyebrow { margin-bottom: 12px; }
.story-track__head .story-eyebrow { color: rgba(19,19,19,0.6); }
.story-track__head .story-h3 { color: #131313; }
.story-track__rail {
  display: flex;
  gap: clamp(20px, 2vw, 36px);
  padding: 0 calc(50vw - 90px);
  align-items: center;
  transform: translate3d(calc(var(--p, 0) * -180vw), 0, 0);
  will-change: transform;
}
.story-track__phone {
  flex: 0 0 auto;
  width: clamp(180px, 22vw, 260px);
  margin: 0;
  display: grid;
  gap: 12px;
  text-align: center;
}
.story-track__phone img {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  border-radius: 24px;
  background: #0a0a0a;
  box-shadow: 0 30px 60px rgba(19,19,19,0.18);
}
.story-track__phone h4 {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  margin: 0;
  color: #131313;
}
.story-track__phone p {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(19,19,19,0.55);
  margin: 0;
}
@media (prefers-reduced-motion: reduce) {
  .story-track { height: auto; }
  .story-track__pin { position: relative; top: auto; height: auto; }
  .story-track__rail {
    transform: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding: 0 var(--pad-x);
  }
  .story-track__phone { scroll-snap-align: start; }
}

/* ---------- 9 — PIP (sticky floating phone over editorial copy) ---------- */
.story-pip {
  background: #131313;
  color: #efece5;
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
  position: relative;
}
.story-pip__grid {
  max-width: 1440px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}
.story-pip__copy {
  display: grid;
  gap: clamp(28px, 4vw, 48px);
}
.story-pip__copy h3 { margin: 0; }
.story-pip__copy p {
  font-family: var(--sans);
  font-weight: 300;
  font-size: clamp(16px, 1.2vw, 19px);
  line-height: 1.6;
  margin: 0;
  /* Pull from the dark-section body var defined globally so the copy
     stays cream on the section's hardcoded #131313 bg even when the
     project's --ink-soft token resolves to dark text (light-cover
     projects, e.g. Cometeer). Source-order specificity meant the
     project token was winning over the :is(...) override above. */
  color: var(--story-dark-body, rgba(239,236,229,0.72));
  max-width: 56ch;
}
.story-pip__phone {
  position: sticky;
  top: clamp(80px, 14vh, 140px);
  width: 100%;
  max-width: 280px;
  justify-self: end;
  border-radius: clamp(20px, 2.4vw, 32px);
  overflow: hidden;
  background: #000;
  box-shadow: 0 30px 80px rgba(0,0,0,0.55);
  aspect-ratio: 9 / 19.5;
}
.story-pip__phone six-stepper { display: block; height: 100%; width: 100%; }
.story-pip__phone .six-stepper__track,
.story-pip__phone .six-stepper__slide,
.story-pip__phone .six-stepper__slide img { height: 100%; }
.story-pip__phone .six-stepper__controls { display: none; }
@media (max-width: 900px) {
  .story-pip__grid { grid-template-columns: 1fr; }
  .story-pip__phone { position: relative; top: 0; max-width: 220px; justify-self: center; }
}

/* ---------- 10 — SPREAD (overlap → spread on hover) ---------- */
.story-spread {
  background: #efece5;
  color: #131313;
  padding: clamp(80px, 10vw, 140px) var(--pad-x);
  overflow: hidden;
}
.story-spread__head {
  max-width: 720px;
  margin: 0 auto clamp(40px, 5vw, 72px);
  padding: 0 var(--pad-x);
  display: grid; gap: 14px;
  text-align: center;
  justify-items: center;
}
.story-spread__head .story-eyebrow { color: rgba(19,19,19,0.6); }
.story-spread__head .story-h3 { color: #131313; }
.story-spread__deck {
  max-width: 1200px;
  margin: 0 auto;
  position: relative;
  height: clamp(420px, 48vw, 560px);
  display: grid;
  place-items: center;
}
.story-spread__phone {
  position: absolute;
  width: clamp(180px, 18vw, 240px);
  margin: 0;
  border-radius: 24px;
  overflow: hidden;
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
  filter: drop-shadow(0 24px 40px rgba(19,19,19,0.18));
  /* collapsed */
  --x: 0px; --r: 0deg;
  transform: translate3d(var(--x), 0, 0) rotate(var(--r));
}
.story-spread__phone img {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  border-radius: 24px;
  background: #0a0a0a;
  display: block;
}
.story-spread__phone:nth-child(1) { --x: -16px; --r: -8deg; z-index: 1; }
.story-spread__phone:nth-child(2) { --x: -8px;  --r: -3deg; z-index: 2; }
.story-spread__phone:nth-child(3) { --x: 0;     --r: 0;     z-index: 3; }
.story-spread__phone:nth-child(4) { --x: 8px;   --r: 3deg;  z-index: 2; }
.story-spread__phone:nth-child(5) { --x: 16px;  --r: 8deg;  z-index: 1; }
.story-spread__deck:hover .story-spread__phone:nth-child(1),
.story-spread__deck:focus-within .story-spread__phone:nth-child(1) { --x: -42vw; --r: 0; }
.story-spread__deck:hover .story-spread__phone:nth-child(2),
.story-spread__deck:focus-within .story-spread__phone:nth-child(2) { --x: -21vw; --r: 0; }
.story-spread__deck:hover .story-spread__phone:nth-child(3),
.story-spread__deck:focus-within .story-spread__phone:nth-child(3) { --x: 0;     --r: 0; }
.story-spread__deck:hover .story-spread__phone:nth-child(4),
.story-spread__deck:focus-within .story-spread__phone:nth-child(4) { --x: 21vw;  --r: 0; }
.story-spread__deck:hover .story-spread__phone:nth-child(5),
.story-spread__deck:focus-within .story-spread__phone:nth-child(5) { --x: 42vw;  --r: 0; }
.story-spread__hint {
  display: block;
  text-align: center;
  margin-top: 24px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(19,19,19,0.55);
}
@media (hover: none), (prefers-reduced-motion: reduce) {
  .story-spread__deck {
    height: auto;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
    place-items: stretch;
  }
  .story-spread__phone {
    position: relative;
    --x: 0; --r: 0;
    transform: none;
    width: 100%;
  }
  .story-spread__hint { display: none; }
}

/* ---------- WALLET CARDS — six-card-fan + .oxbow-card variants ---------- */
six-card-fan {
  display: block;
  position: relative;
  width: 100%;
  max-width: 760px;
  text-align: center;
}
.six-card-fan__deck {
  position: relative;
  width: 100%;
  height: clamp(280px, 32vw, 380px);
  background: transparent;
  border: 0;
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
}
.six-card-fan__card {
  position: absolute;
  margin: 0;
  width: clamp(220px, 24vw, 320px);
  aspect-ratio: 1.586 / 1;          /* ISO/IEC 7810 ID-1 */
  border-radius: 16px;
  z-index: var(--z, 1);
  transform: translate3d(0, var(--ty, 0), 0) rotate(var(--rot, 0));
  transform-origin: 50% 100%;
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
  filter: drop-shadow(0 20px 36px rgba(0,0,0,0.5));
  overflow: hidden;
  isolation: isolate;
}
.six-card-fan__card figcaption {
  position: absolute;
  left: 50%;
  bottom: -26px;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(239,236,229,0.55);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 320ms ease;
}
six-card-fan.is-open .six-card-fan__card {
  transform: translate3d(var(--slide, 0), 0, 0) rotate(0);
}
six-card-fan.is-open .six-card-fan__card figcaption { opacity: 1; }
.six-card-fan__hint {
  display: block;
  margin-top: 18px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(239,236,229,0.55);
}
@media (max-width: 720px) {
  .six-card-fan__card { width: clamp(180px, 60vw, 260px); }
  six-card-fan.is-open .six-card-fan__card {
    /* Tighten the open spread on small screens so cards stay on-canvas. */
    transform: translate3d(calc(var(--slide, 0) * 0.5), 0, 0) rotate(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .six-card-fan__card { transition: none; }
}

/* Card faces — drawn entirely in CSS, no images. */
.oxbow-card {
  color: rgba(239,236,229,0.92);
}
.oxbow-card__brand {
  position: absolute;
  top: 18px; left: 22px;
  font-family: var(--serif);
  font-size: clamp(20px, 2.2vw, 28px);
  font-weight: 400;
  letter-spacing: -0.02em;
}
.oxbow-card__chip {
  position: absolute;
  top: 60%; left: 22px;
  width: clamp(34px, 4vw, 44px);
  aspect-ratio: 4 / 3;
  border-radius: 6px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.4), rgba(255,255,255,0.08)),
    linear-gradient(180deg, #d4ad6c, #9c773f);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.18);
}
.oxbow-card__num {
  position: absolute;
  bottom: 38px; left: 22px; right: 22px;
  font-family: var(--mono);
  font-size: clamp(11px, 1vw, 13px);
  letter-spacing: 0.18em;
  opacity: 0.78;
}
.oxbow-card__name {
  position: absolute;
  bottom: 16px; left: 22px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  opacity: 0.75;
}

/* Variant 1 — Brushed copper / monogram */
.oxbow-card--copper {
  background:
    radial-gradient(120% 80% at 30% 10%, rgba(255,255,255,0.18), transparent 50%),
    repeating-linear-gradient(115deg, rgba(0,0,0,0.05) 0 2px, transparent 2px 4px),
    linear-gradient(135deg, #c0855e 0%, #8c5a3a 60%, #6b4129 100%);
  color: #fff8ee;
}
.oxbow-card--copper .oxbow-card__chip {
  background:
    linear-gradient(135deg, rgba(255,255,255,0.4), rgba(255,255,255,0.05)),
    linear-gradient(180deg, #f1c98a, #b9854c);
}

/* Variant 2 — Gradient mesh */
.oxbow-card--gradient {
  background:
    radial-gradient(80% 50% at 80% 20%, rgba(64,148,148,0.55), transparent 60%),
    radial-gradient(60% 60% at 20% 80%, rgba(34,76,98,0.7),  transparent 60%),
    linear-gradient(140deg, #0e1c24 0%, #112a3a 100%);
}
.oxbow-card--gradient::after {
  content: "";
  position: absolute;
  top: -40%; left: -30%;
  width: 140%; height: 80%;
  background: linear-gradient(120deg, transparent 40%, rgba(255,255,255,0.18) 50%, transparent 60%);
  transform: rotate(-12deg);
  pointer-events: none;
}

/* Variant 3 — Embossed monochrome (off-white) */
.oxbow-card--embossed {
  background:
    radial-gradient(120% 80% at 20% 0%, #ffffff, #ece7df 60%, #d8d2c8 100%);
  color: rgba(19,19,19,0.78);
}
.oxbow-card--embossed .oxbow-card__brand {
  color: rgba(19,19,19,0.18);
  text-shadow:
    0 1px 0 rgba(255,255,255,0.9),
    0 -1px 0 rgba(0,0,0,0.08);
}
.oxbow-card--embossed .oxbow-card__chip {
  background:
    linear-gradient(135deg, rgba(255,255,255,0.6), rgba(0,0,0,0.06)),
    linear-gradient(180deg, #cdc5b6, #a89e8a);
}
.oxbow-card--embossed .oxbow-card__num,
.oxbow-card--embossed .oxbow-card__name { color: rgba(19,19,19,0.42); }

/* Variant 4 — Holographic foil */
.oxbow-card--foil {
  background:
    conic-gradient(from var(--foil-angle, 220deg),
      #5cd0c8, #c08fff, #ffb38a, #ffe07a, #84e6c5, #5cd0c8);
  color: #131313;
  animation: foil-drift 14s linear infinite;
}
.oxbow-card--foil .oxbow-card__brand { color: rgba(19,19,19,0.78); }
.oxbow-card--foil .oxbow-card__num,
.oxbow-card--foil .oxbow-card__name { color: rgba(19,19,19,0.5); }
.oxbow-card--foil .oxbow-card__shimmer {
  position: absolute; inset: 0;
  background:
    repeating-linear-gradient(120deg,
      rgba(255,255,255,0.18) 0 2px,
      rgba(255,255,255,0)    2px 6px);
  mix-blend-mode: soft-light;
  pointer-events: none;
}
@property --foil-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 220deg;
}
@keyframes foil-drift {
  from { --foil-angle: 0deg; }
  to   { --foil-angle: 360deg; }
}
@media (prefers-reduced-motion: reduce) {
  .oxbow-card--foil { animation: none; }
}

/* ============================================================
   Desktop & large-monitor calibration
   ------------------------------------------------------------
   Reference: hugoandmarie.com + instrument.com, both of which let
   imagery go edge-to-edge but cap typography and add breathing
   room on >=1440px viewports. We do the same here.

   Tablet (720-1280) is intentionally left to fluid clamp() — those
   sizes already read well. The new rules pick up at 1280 and 1600.
   ============================================================ */

@media (min-width: 1280px) {
  /* Captions sit a touch higher off the corner — keeps them clear of
     the cover edge on portrait tiles where the scrim is shorter. */
  .archive__caption { padding: clamp(24px, 1.6vw, 32px); }

  /* Feed-section gets real margins, not just padding. Frames the rail
     instead of letting it bleed into the screen edge. */
  .feed-section { padding-inline: clamp(0px, 2vw, 40px); }
}

@media (min-width: 1600px) {
  /* Archive grid + feed-section stay edge-to-edge on every viewport
     (no max-width cap). Only the inner copy on a few content sections
     cap at 1600 so the type doesn't drift off-centre on huge monitors. */
  .story-hero__copy,
  .case-header__wrapper,
  .story-setup { max-width: var(--content-max); }
}

/* ============================================================
   CTA buttons + sticky bottom bar (project template)
   ============================================================ */

/* Modifier: extra top spacing between the case-header cover image
   and the intro paragraph. Use on the project template + any case
   that wants more breathing room before the description. */
.case-intro--spaced {
  padding-top: clamp(48px, 6vw, 96px);
}

/* Inline CTA row — sits inside .case-intro under the description. */
.case-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: clamp(28px, 3.6vw, 48px);
  align-items: center;
}

/* Pill button base — same h/radius as the carousel-controls pill
   so the button lockup reads as part of the same family. */
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 22px;
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: background 200ms var(--ease-out),
              color      200ms var(--ease-out),
              transform  200ms var(--ease-out);
}
/* The icon hides by default — buttons are label-led. The bar's narrow-
   width media query swaps these to icon-only. */
.cta__icon { width: 14px; height: 14px; flex: none; display: none; }
.cta__label { display: inline; }
.cta--primary {
  background: var(--ink, #131313);
  color: var(--bg, #efece5);
  border: 1px solid var(--ink, #131313);
}
.cta--primary:hover { transform: translateY(-1px); }
.cta--secondary {
  background: transparent;
  color: var(--ink, #131313);
  border: 1px solid var(--rule, rgba(19,19,19,0.18));
}
.cta--secondary:hover { background: rgba(19,19,19,0.06); }
.cta--link {
  height: auto;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--ink-mute, rgba(19,19,19,0.5));
  letter-spacing: 0.04em;
  text-transform: none;
  font-size: 13px;
  font-family: var(--sans);
}
.cta--link::after { content: " ↗"; }
.cta--link:hover { color: var(--ink, #131313); }

/* Sticky bottom CTA bar — slim glass pill centred at the bottom of the
   viewport, with link buttons + an inline share button (.cta-bar__share).
   When this bar is present on a project page, initShareFab() skips the
   standalone .share-fab so there is exactly one share affordance. Total
   bar height ~42px (4px padding + 34px buttons).

   Theming mirrors .nav: --bar-bg / --bar-shadow / --bar-ink / --bar-rule
   default to dark glass, and are overridden by [data-base-theme="light"]
   (page-level, set by initProjectTheme from the cover image) and
   [data-theme="dark"|"light"] (section-level, set by initCtaBar() based
   on which data-nav-theme section currently sits behind the bar). The
   bar's children (.cta and .cta-bar__share) read these vars so a single
   theme attribute switches the whole pill. */
.case-cta-bar {
  --bar-bg:     var(--glass-bg-dark);
  --bar-shadow: var(--glass-shadow-dark);
  --bar-ink:    #efece5;
  --bar-rule:   rgba(255, 255, 255, 0.22);
  --bar-rule-h: rgba(255, 255, 255, 0.08);
  position: fixed;
  left: 50%;
  bottom: clamp(16px, 2vw, 28px);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 4px 4px 4px;
  border-radius: 999px;
  background: var(--bar-bg);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--bar-shadow);
  color: var(--bar-ink);
  z-index: 60;
  /* Fade in once the user has scrolled past the case-header — opacity
     is bumped by JS on .is-visible. CSS-only fallback keeps it visible. */
  opacity: 1;
  transition: opacity 320ms var(--ease-out),
              transform 320ms var(--ease-out),
              background 220ms var(--ease-out),
              box-shadow 220ms var(--ease-out),
              color      220ms var(--ease-out);
}
/* Light theme — page-wide (cover-derived) and section-override variants.
   Section override always wins because [data-theme] is more specific than
   the bare base-theme rule and is set explicitly by initCtaBar(). */
html[data-base-theme="light"] .case-cta-bar:not([data-theme="dark"]),
.case-cta-bar[data-theme="light"] {
  --bar-bg:     var(--glass-bg-light);
  --bar-shadow: var(--glass-shadow-light);
  --bar-ink:    #131313;
  --bar-rule:   rgba(19, 19, 19, 0.22);
  --bar-rule-h: rgba(19, 19, 19, 0.06);
}
/* Dark section override pulls the bar back to dark glass even when the
   page's base theme is light (e.g. a dark stats band under the bar). */
.case-cta-bar[data-theme="dark"] {
  --bar-bg:     var(--glass-bg-dark);
  --bar-shadow: var(--glass-shadow-dark);
  --bar-ink:    #efece5;
  --bar-rule:   rgba(255, 255, 255, 0.22);
  --bar-rule-h: rgba(255, 255, 255, 0.08);
}
.case-cta-bar.is-hidden {
  opacity: 0;
  transform: translateX(-50%) translateY(12px);
  pointer-events: none;
}
/* In-bar link buttons — slimmer than the in-hero version. Colours read
   from the bar's --bar-* tokens so they flip with the bar's theme. */
.case-cta-bar .cta { height: 34px; padding: 0 14px; font-size: 11px; letter-spacing: 0.14em; transition: background 200ms var(--ease-out), color 200ms var(--ease-out), border-color 200ms var(--ease-out), transform 200ms var(--ease-out); }
.case-cta-bar .cta--primary {
  background: var(--bar-ink);
  color: var(--bar-bg);
  border-color: var(--bar-ink);
}
.case-cta-bar .cta--secondary {
  background: transparent;
  color: var(--bar-ink);
  border-color: var(--bar-rule);
}
.case-cta-bar .cta--secondary:hover { background: var(--bar-rule-h); }
/* Inline share button — circle on the trailing edge of the bar. Same
   visual weight as a .cta--secondary so the pill reads as one row. */
.cta-bar__share {
  position: relative;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid var(--bar-rule);
  background: transparent;
  color: var(--bar-ink);
  display: grid;
  place-items: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background  200ms var(--ease-out),
              border-color 200ms var(--ease-out),
              color       200ms var(--ease-out),
              transform   240ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.cta-bar__share:hover { background: var(--bar-rule-h); transform: scale(1.04); }
.cta-bar__share:active { transform: scale(0.94); }
.cta-bar__share:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.cta-bar__icon {
  width: 14px; height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: translateY(-1px);
}
.cta-bar__toast {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translate(-50%, 4px);
  white-space: nowrap;
  background: var(--bar-bg);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  box-shadow: var(--bar-shadow);
  padding: 6px 12px;
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bar-ink);
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms var(--ease-out),
              transform 220ms var(--ease-out),
              background 220ms var(--ease-out),
              color      220ms var(--ease-out);
}
.cta-bar__share.is-toasted .cta-bar__toast {
  opacity: 1;
  transform: translate(-50%, 0);
}
@media (prefers-reduced-motion: reduce) {
  .cta-bar__share { transition: none; }
  .cta-bar__share:hover,
  .cta-bar__share:active { transform: none; }
}

/* Mobile: keep the centred pill, hug content, single row only. Cap
   max-width so the bar can never escape the viewport edges. flex-wrap
   stays nowrap so the share circle never drops to a second row — when
   labels would push past the viewport the narrow-width rule below
   swaps them out for icons. */
@media (max-width: 720px) {
  .case-cta-bar {
    bottom: clamp(12px, 3vw, 18px);
    max-width: calc(100vw - 24px);
    flex-wrap: nowrap;
    justify-content: center;
  }
}
/* In the bar, the lockup is always: first two as labelled pills (Demo,
   Case Study — the prominent CTAs), Website as a 34×34 icon button,
   share as the 34×34 icon circle. Same rhythm at every viewport so
   users learn the position once. The in-hero .case-cta keeps all three
   buttons labelled — it has plenty of horizontal room. */
.case-cta-bar [data-cta-brand] {
  width: 34px;
  height: 34px;
  padding: 0;
  gap: 0;
}
.case-cta-bar [data-cta-brand] .cta__icon { display: block; }
.case-cta-bar [data-cta-brand] .cta__label { display: none; }


/* =========================================================
   Desktop-pattern sample (six-humans/projects/desktop-patterns.html)
   Ten reusable blocks for showing desktop/web designs.
   Placeholder gradients stand in for screenshots.

   Naming:
     .desk-browser           — generic browser-chrome wrapper
     .desk-browser--lg/--sm/--pad/--pin/--zoom/--tilt — variants
     .desk-ph .desk-ph--NN   — placeholder gradients (10 colourways)
     .story-desk-<pattern>   — the 10 sections, mirroring .story-* naming
     .desk-pin               — desktop callout pin (07)
     .desk-laptop / .desk-tablet / .desk-phone — diorama devices (03)
   ========================================================= */

.story--desk-sample { padding-bottom: 120px; }
.story--desk-sample .case-header { padding-bottom: 0; }

.desk-sample__hero { padding: clamp(80px, 12vh, 140px) clamp(24px, 6vw, 80px) 40px; }
.desk-sample__hero-frame {
  margin-top: clamp(28px, 5vh, 56px);
  display: flex; justify-content: center;
}

/* ---------- browser chrome (shared) ---------- */

.desk-browser {
  position: relative;
  width: 100%;
  background: #16161a;
  border-radius: 14px;
  overflow: hidden;
  box-shadow:
    0 1px 0 rgba(255,255,255,0.04) inset,
    0 24px 60px -20px rgba(0,0,0,0.55),
    0 8px 24px -6px rgba(0,0,0,0.35);
  border: 1px solid rgba(255,255,255,0.06);
  isolation: isolate;
}
.desk-browser__bar {
  display: flex; align-items: center; gap: 8px;
  height: 32px;
  padding: 0 14px;
  background: linear-gradient(180deg, #1f1f24, #16161a);
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.desk-browser__dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: rgba(255,255,255,0.18);
  flex: 0 0 auto;
}
.desk-browser__dot:nth-child(1) { background: #ff5f57; }
.desk-browser__dot:nth-child(2) { background: #febc2e; }
.desk-browser__dot:nth-child(3) { background: #28c840; }
.desk-browser__url {
  margin-left: 14px;
  font-family: var(--mono);
  font-size: 11px;
  color: rgba(255,255,255,0.55);
  letter-spacing: 0.04em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.desk-browser__view {
  position: relative;
  aspect-ratio: 16 / 10;
  width: 100%;
}
.desk-browser__stack {
  position: relative;
  aspect-ratio: 16 / 10;
  width: 100%;
}
.desk-browser__stack > .desk-browser__view {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 480ms var(--ease-out, cubic-bezier(.2,.8,.2,1));
}
.desk-browser__stack > .desk-browser__view.is-on { opacity: 1; }

.desk-browser--lg { max-width: 1100px; }
.desk-browser--sm { max-width: 100%; }
.desk-browser--sm .desk-browser__bar { height: 22px; padding: 0 8px; gap: 5px; }
.desk-browser--sm .desk-browser__dot { width: 6px; height: 6px; }
.desk-browser--pad { max-width: 1180px; }

/* ---------- placeholder gradients (10 colourways) ---------- */

.desk-ph {
  background: linear-gradient(135deg, #2a2a32 0%, #14141a 100%);
  position: relative;
}
.desk-ph::before, .desk-ph::after {
  content: ""; position: absolute;
  border-radius: 50%;
  filter: blur(40px);
  opacity: 0.65;
  pointer-events: none;
}
.desk-ph::before { width: 60%; height: 70%; left: -10%; top: -10%; }
.desk-ph::after  { width: 50%; height: 60%; right: -10%; bottom: -10%; }
.desk-ph--01::before { background: #ff7b54; }   .desk-ph--01::after { background: #4f46e5; }
.desk-ph--02::before { background: #06b6d4; }   .desk-ph--02::after { background: #f59e0b; }
.desk-ph--03::before { background: #d946ef; }   .desk-ph--03::after { background: #14b8a6; }
.desk-ph--04::before { background: #f43f5e; }   .desk-ph--04::after { background: #6366f1; }
.desk-ph--05::before { background: #84cc16; }   .desk-ph--05::after { background: #0ea5e9; }
.desk-ph--06::before { background: #f97316; }   .desk-ph--06::after { background: #8b5cf6; }
.desk-ph--07::before { background: #ec4899; }   .desk-ph--07::after { background: #22d3ee; }
.desk-ph--08::before { background: #eab308; }   .desk-ph--08::after { background: #ef4444; }
.desk-ph--09::before { background: #10b981; }   .desk-ph--09::after { background: #f472b6; }
.desk-ph--10::before { background: #3b82f6; }   .desk-ph--10::after { background: #fb923c; }

/* ---------- shared section head ---------- */

.story-desk-zoom__head, .story-desk-pin__head, .story-desk-diorama__head,
.story-desk-tilt__head, .story-desk-rail__head, .story-desk-hover__head,
.story-desk-callouts__head, .story-desk-pan__head, .story-desk-stack__head,
.story-desk-steps__head {
  max-width: 720px;
  margin: 0 auto clamp(28px, 5vh, 60px);
  padding: 0 clamp(24px, 5vw, 60px);
  text-align: center;
}
.story-desk-zoom, .story-desk-pin, .story-desk-diorama, .story-desk-tilt,
.story-desk-rail, .story-desk-hover, .story-desk-callouts,
.story-desk-pan, .story-desk-stack, .story-desk-steps,
.story-desk-outro {
  padding: clamp(80px, 12vh, 140px) 0;
}
.story-desk-outro {
  text-align: center;
  padding-top: clamp(60px, 8vh, 100px);
  display: flex; flex-direction: column; align-items: center; gap: 20px;
}
.story-desk-outro__copy { max-width: 560px; padding: 0 24px; }

/* ---------- 01 — ZOOM-OUT HERO ---------- */
.story-desk-zoom { background: #f5f1e8; color: #131313; }
.story-desk-zoom__stage {
  height: 200vh;          /* sticky scroll runway */
  position: relative;
  margin-top: -40px;
}
.desk-browser--zoom {
  position: sticky;
  top: 12vh;
  margin: 0 auto;
  width: min(72vw, 1100px);
  transform: scale(var(--zoom-scale, 0.34));
  transform-origin: 50% 35%;
  transition: transform 80ms linear;
  will-change: transform;
}

/* ---------- 02 — STICKY-FRAME PIN ---------- */
.story-desk-pin { background: #0c0c10; color: #efece5; }
.story-desk-pin__grid {
  display: grid;
  grid-template-columns: 6fr 5fr;
  gap: clamp(40px, 6vw, 80px);
  max-width: 1280px; margin: 0 auto;
  padding: 0 clamp(24px, 5vw, 80px);
  align-items: start;
}
.story-desk-pin__frame-wrap { position: relative; }
.desk-browser--pin {
  position: sticky;
  top: clamp(72px, 14vh, 120px);
  width: 100%;
}
.story-desk-pin__steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(60vh, 70vh, 80vh);
}
.story-desk-pin__step {
  opacity: 0.35;
  transition: opacity 360ms var(--ease-out);
  max-width: 460px;
}
.story-desk-pin__step.is-active { opacity: 1; }
.story-desk-pin__step h4 {
  margin: 8px 0 12px;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(28px, 4vw, 40px);
  letter-spacing: -0.01em;
  line-height: 1.1;
}
.story-desk-pin__step p { font-size: 16px; line-height: 1.5; opacity: 0.85; }

@media (max-width: 900px) {
  .story-desk-pin__grid { grid-template-columns: 1fr; }
  .desk-browser--pin { position: sticky; top: clamp(72px, 14vh, 96px); max-width: 560px; margin: 0 auto; }
  .story-desk-pin__steps { gap: 40vh; }
}

/* ---------- 03 — MULTI-DEVICE DIORAMA ---------- */
.story-desk-diorama { background: #ece6d8; color: #131313; }
.story-desk-diorama__stage {
  position: relative;
  max-width: 1100px;
  margin: 0 auto;
  padding: clamp(40px, 6vh, 80px) clamp(24px, 6vw, 80px);
  perspective: 1400px;
  transform-style: preserve-3d;
}
.desk-diorama__device {
  position: absolute;
  transition: transform 600ms var(--ease-out);
  will-change: transform;
}
.desk-diorama__device--desktop {
  position: relative;
  width: 100%;
  transform: rotateX(8deg) rotateY(-8deg) translate3d(var(--mx, 0px), var(--my, 0px), 0);
  transform-origin: center;
}
.desk-diorama__device--laptop {
  width: 38%;
  bottom: -8%; left: -2%;
  transform: rotateX(14deg) rotateY(10deg) translate3d(var(--mx, 0px), var(--my, 0px), 0);
  z-index: 2;
}
.desk-laptop {
  position: relative;
  border-radius: 10px 10px 4px 4px;
  background: #1a1a1f;
  padding: 8px 8px 0;
  box-shadow: 0 30px 60px -20px rgba(0,0,0,0.4);
}
.desk-laptop__screen {
  aspect-ratio: 16 / 10;
  border-radius: 4px;
  overflow: hidden;
}
.desk-laptop__hinge {
  height: 14px;
  margin: 0 -22px -8px;
  background: linear-gradient(180deg, #1a1a1f 0%, #0a0a0c 100%);
  border-radius: 0 0 14px 14px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}
.desk-diorama__device--tablet {
  width: 22%;
  top: 12%; right: -2%;
  transform: rotate(8deg) translate3d(var(--mx, 0px), var(--my, 0px), 0);
  z-index: 3;
}
.desk-tablet {
  aspect-ratio: 4 / 5.6;
  border-radius: 18px;
  border: 8px solid #1a1a1f;
  box-shadow: 0 24px 40px -12px rgba(0,0,0,0.4);
  overflow: hidden;
}
.desk-diorama__device--phone {
  width: 12%;
  bottom: 4%; right: 22%;
  transform: rotate(-6deg) translate3d(var(--mx, 0px), var(--my, 0px), 0);
  z-index: 4;
}
.desk-phone {
  aspect-ratio: 9 / 19.5;
  border-radius: 18px;
  border: 5px solid #1a1a1f;
  box-shadow: 0 20px 36px -10px rgba(0,0,0,0.4);
  overflow: hidden;
}
@media (max-width: 720px) {
  .desk-diorama__device--laptop { width: 50%; bottom: -16%; }
  .desk-diorama__device--tablet { width: 32%; right: -6%; }
  .desk-diorama__device--phone  { width: 16%; bottom: -10%; right: 18%; }
}

/* ---------- 04 — TILTED UNFLATTEN ---------- */
.story-desk-tilt { background: #0c0c10; color: #efece5; }
.story-desk-tilt__stage {
  max-width: 1180px; margin: 0 auto;
  padding: 0 clamp(24px, 5vw, 80px);
  perspective: 1800px;
  perspective-origin: 50% 30%;
}
.desk-browser--tilt {
  width: 100%;
  transform-origin: 50% 100%;
  transform: rotateX(var(--tilt-deg, 38deg));
  transition: transform 80ms linear;
  will-change: transform;
}

/* ---------- 05 — SCROLL-SNAP RAIL ---------- */
.story-desk-rail { background: #14141a; color: #efece5; }
.story-desk-rail__rail {
  display: flex;
  gap: clamp(20px, 3vw, 36px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline-start: clamp(24px, 5vw, 80px);
  padding: 0 clamp(24px, 5vw, 80px) 24px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.story-desk-rail__rail::-webkit-scrollbar { display: none; }
.story-desk-rail__card {
  scroll-snap-align: start;
  flex: 0 0 min(72vw, 720px);
  display: grid; gap: 14px;
}
.story-desk-rail__card h4 { margin: 0; font-family: var(--serif); font-weight: 400; font-size: 22px; }
.story-desk-rail__card p { margin: 0; font-size: 14px; opacity: 0.7; }

/* ---------- 06 — HOVER PREVIEW GRID ---------- */
.story-desk-hover { background: #f5f1e8; color: #131313; }
.story-desk-hover__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 2vw, 32px);
  max-width: 1280px; margin: 0 auto;
  padding: 0 clamp(24px, 5vw, 80px);
}
.story-desk-hover__cell {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  display: grid; gap: 12px;
  cursor: pointer;
  text-align: left;
  transition: transform 380ms var(--ease-out);
  will-change: transform;
}
.story-desk-hover__cell:hover,
.story-desk-hover__cell:focus-visible { transform: scale(1.04); outline: none; }
.story-desk-hover__cell:focus-visible .desk-browser { box-shadow: 0 0 0 2px #131313, 0 24px 60px -20px rgba(0,0,0,0.5); }
.story-desk-hover__label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #131313;
  opacity: 0.7;
}
@media (max-width: 720px) {
  .story-desk-hover__grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- 07 — DESKTOP CALLOUTS ---------- */
.story-desk-callouts { background: #0c0c10; color: #efece5; }
.story-desk-callouts__layout {
  display: grid;
  grid-template-columns: 7fr 4fr;
  gap: clamp(40px, 5vw, 80px);
  max-width: 1280px; margin: 0 auto;
  padding: 0 clamp(24px, 5vw, 80px);
  align-items: start;
}
.story-desk-callouts__stage { position: relative; }
.desk-pin {
  position: absolute;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: rgba(255,255,255,0.92);
  color: #0c0c10;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  border: 0;
  display: grid; place-items: center;
  cursor: pointer;
  box-shadow: 0 0 0 2px rgba(255,255,255,0.18), 0 6px 16px rgba(0,0,0,0.4);
  z-index: 2;
  transform: translate(-50%, -50%);
}
.desk-pin:hover { transform: translate(-50%, -50%) scale(1.15); }
.story-desk-callouts__notes {
  list-style: none;
  margin: 0; padding: 0;
  display: grid; gap: 18px;
}
.story-desk-callouts__notes li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 14px;
  align-items: start;
  font-size: 15px;
  line-height: 1.5;
}
.story-desk-callouts__notes span {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.4);
  display: grid; place-items: center;
  font-family: var(--mono);
  font-size: 12px;
}
.story-desk-callouts__notes p { margin: 0; opacity: 0.85; }
@media (max-width: 900px) {
  .story-desk-callouts__layout { grid-template-columns: 1fr; }
}

/* ---------- 08 — HORIZONTAL PAN ---------- */
.story-desk-pan { background: #14141a; color: #efece5; }
.story-desk-pan__pin {
  height: 300vh;          /* runway: while pinned, the track scrolls 0→100% */
  position: relative;
}
.story-desk-pan__viewport {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid; place-items: center;
  padding: 0 clamp(24px, 5vw, 80px);
}
.story-desk-pan__viewport .desk-browser--pad { width: min(96%, 1180px); }
.desk-browser__view--pan { overflow: hidden; }
.desk-pan-track {
  display: flex;
  height: 100%;
  width: 400%;
  transform: translate3d(var(--pan-x, 0%), 0, 0);
  transition: transform 80ms linear;
  will-change: transform;
}
.desk-pan-panel {
  flex: 0 0 25%;
  height: 100%;
  position: relative;
  display: flex; align-items: flex-end;
}
.desk-pan-panel__cap {
  position: relative;
  z-index: 2;
  padding: clamp(20px, 3vw, 36px);
  background: linear-gradient(180deg, transparent, rgba(0,0,0,0.45));
  width: 100%;
}
.desk-pan-panel__cap h4 {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin: 0 0 6px;
  color: rgba(255,255,255,0.7);
}
.desk-pan-panel__cap p {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(20px, 2.6vw, 28px);
  line-height: 1.2;
  margin: 0;
  color: #fff;
}
.story-desk-pan__counter {
  position: absolute;
  bottom: 18%; right: clamp(28px, 6vw, 80px);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  color: rgba(255,255,255,0.7);
  background: rgba(0,0,0,0.4);
  padding: 6px 12px;
  border-radius: 999px;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}

/* ---------- 09 — STACKED CARDS ---------- */
.story-desk-stack { background: #ece6d8; color: #131313; }
.story-desk-stack__column {
  max-width: 1100px; margin: 0 auto;
  padding: 0 clamp(24px, 5vw, 80px);
  display: grid; gap: clamp(40px, 8vh, 80px);
}
.story-desk-stack__card {
  position: sticky;
  top: calc(80px + var(--idx, 0) * 28px);
  display: grid; gap: 14px;
}
.story-desk-stack__card p {
  font-size: 14px; opacity: 0.7; max-width: 520px; margin: 0;
  font-family: var(--mono); letter-spacing: 0.04em;
}

/* ---------- 10 — STEP-THROUGH PROTOTYPE ---------- */
.story-desk-steps { background: #0c0c10; color: #efece5; }
.story-desk-steps__stage {
  max-width: 1180px; margin: 0 auto;
  padding: 0 clamp(24px, 5vw, 80px);
  display: grid; gap: 24px;
}
.story-desk-steps__pills {
  display: flex; flex-wrap: wrap; gap: 10px;
  justify-content: center;
}
.story-desk-steps__pill {
  appearance: none;
  border: 1px solid rgba(255,255,255,0.15);
  background: rgba(255,255,255,0.04);
  color: #efece5;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 12px 18px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 220ms var(--ease-out), border-color 220ms var(--ease-out), color 220ms var(--ease-out);
}
.story-desk-steps__pill:hover { background: rgba(255,255,255,0.10); }
.story-desk-steps__pill.is-active {
  background: #efece5;
  color: #0c0c10;
  border-color: #efece5;
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .desk-browser--zoom { transform: none !important; position: static; width: 100%; max-width: 1100px; margin: 0 auto; }
  .story-desk-zoom__stage { height: auto; }
  .desk-browser--tilt { transform: none !important; }
  .desk-pan-track { transform: none !important; }
  .story-desk-pan__pin { height: auto; }
  .story-desk-pan__viewport { position: static; height: auto; padding: 24px clamp(24px, 5vw, 80px); }
  .story-desk-stack__card { position: static; }
  .desk-browser__stack > .desk-browser__view { transition: none; }
}


