/* ==========================================================================
   LA WALLET — CASE STUDY (self-contained page stylesheet)

   TABLE OF CONTENTS — jump by searching the banner text:
     1. DESIGN TOKENS        — every color, type, and spacing value (light + dark)
     2. BASE                 — reset, page frame, root type scaling, page veil
     3. CASCADE ANIMATIONS   — load + scroll-in reveal helpers
     4. SITE NAV             — sticky top nav, theme toggle, hamburger
     5. MOBILE MENU
     6. HERO                 — metadata hero (sticky, carousel)
     7. PAGE NAV             — floating bottom section nav
     8. CONTENT SHELL        — white card (light) / dark surface
     9. CASE PRIMITIVES      — headline / subheading / body / metadata
    10. OVERVIEW
    11. THE PROBLEM
    12. CORE TENSION + SOLUTION
    13. FEATURE WALKTHROUGH  — full-bleed bands (Designs), Synthesis, Design System
    14. GALLERY              — stage + thumb rail + caption + chips
    15. LIGHTBOX
    16. RESULTS
    17. REFLECTION
    18. EXPLORE MORE
    19. CONTACT FOOTER
    20. COPYRIGHT TIP
    21. REDUCED MOTION

   BREAKPOINTS (from the Figma frame widths 1920 / 768 / 402):
     mobile  <= 767px   -> @media (max-width: 767px)
     tablet  768-1023px -> @media (max-width: 1023px)
     desktop >= 1024px  -> default / @media (min-width: 1024px)
   ========================================================================== */


/* ==========================================================================
   1. DESIGN TOKENS
   Light mode on :root, dark overrides on [data-theme='dark'].
   Change a value here and it propagates through the whole page.
   ========================================================================== */
:root {
  /* ---- Palette / page chrome (LIGHT) --------------------------------- */
  --violet-50: #f4e9ff;        /* Figma violet/50 */
  --menu-hover-bg: var(--violet-50); /* nav row hover tint, light (Dave 2026-09-07) */
  --frame: #0e011c;            /* dark plum behind the light card + footer strip */
  --bg: #fbfafd;               /* shell background */
  --surface: #ffffff;          /* cards, hero details panel */
  --band-tint: #f4f1f8;        /* tinted walkthrough bands (surface-2) */
  --band-plain: #fbfafd;       /* plain walkthrough bands (= bg) */
  --band-surface: #ffffff;     /* Design System band (= surface) */
  --panel-tension: #edeaf1;    /* Core Tension panel fill (neutral-100) */
  --panel-reflect: #edeaf1;    /* Reflection card fill */
  --border: #e9e5f0;           /* card + shell borders */

  /* ---- Palette / text (LIGHT) ---------------------------------------- */
  --fg: #1e0c32;               /* headlines, item titles, metadata values */
  --fg-body: #5e5072;          /* body copy */
  --fg-subhead: #5e5072;       /* section subheadings */
  --fg-muted: #5e5072;         /* hero subtitle + stats */
  --fg-subtle: #978aaa;        /* role-card icon, hero client name */
  --fg-label: #75608c;         /* metadata labels, quote roles, placeholder text.
                                  Figma says #a899b9 (neutral-400) but that fails
                                  AA (2.6:1) — darkened along the same hue to pass
                                  4.5:1 on every light surface it sits on */

  /* ---- Palette / accents (LIGHT) ------------------------------------- */
  --primary: #6a00d1;          /* problem icons, stat values, gallery buttons */
  --primary-bright: #8200ff;   /* walkthrough eyebrows, primary CTA */
  --primary-hover: #9226ff;    /* primary CTA hover */
  --amber: #ffc20a;            /* gallery active-thumb ring (BOTH modes), nav hover */
  --icon-results: #978aaa;     /* results stat + quote glyphs */
  --hero-bullet: #9747ff;      /* hero stat bullets */
  --tag-border: #d2d2d2;       /* hero category pill borders */
  --xm-band: #f4f1f8;          /* Explore More band fill */
  --xm-client: #9747ff;        /* Explore More client label */
  --xm-stat: #5e5072;          /* Explore More stat text */
  --xm-marker: #9747ff;        /* Explore More list bullets (both modes) */

  /* ---- Palette / gallery (LIGHT) ------------------------------------- */
  --gal-surface: #f4f1f8;      /* stage behind letterboxed images */
  --gal-ph-bg: #ece7f4;        /* placeholder slide / thumb fill */
  --gal-ring: #ffc20a;         /* active thumb ring (amber in BOTH modes) */
  --gal-btn-bg: #6a00d1;       /* lightbox close chip */
  --gal-btn-bg-hover: #8200ff;
  --gal-btn-fg: #ffffff;
  --chip-bg: rgba(255, 255, 255, 0.7);  /* on-image expand/link chips (both modes) */
  --chip-bg-hover: #ffffff;
  --chip-fg: #6a00d1;
  --tooltip-bg: #0e011c;       /* chip tooltips */
  --tooltip-fg: #ffffff;

  /* ---- Palette / lightbox (LIGHT) ------------------------------------ */
  --lb-panel-bg: rgba(255, 255, 255, 0.84); /* frosted fullscreen panel */
  --lb-fg: #1e0c32;
  --lb-body: #5e5072;
  --lb-label: #75608c; /* AA-corrected, matches --fg-label */

  /* ---- Palette / fixed chrome (SAME in both modes) -------------------- */
  --nav-fg: #ffffff;               /* nav links over dark backdrops */
  --nav-fg-on-light: #1e0c32;      /* nav links over the light shell */
  --nav-scrim-from: rgba(14, 1, 28, 0.49); /* dark readability scrim */
  --nav-scrim-light: rgba(30, 12, 50, 0.12); /* light-section scrim */
  --nav-ghost-border: rgba(255, 255, 255, 0.5);
  --nav-ghost-border-on-light: rgba(30, 12, 50, 0.5);
  /* Pagenav glass is theme-aware: frosted white here, dark plum overrides
     in the dark block below */
  --pagenav-bg: rgba(255, 255, 255, 0.85);
  --pagenav-border: rgba(30, 12, 50, 0.1);
  --pagenav-fg: rgba(30, 12, 50, 0.72);
  --pagenav-fg-hover: #1e0c32;
  --pagenav-track: rgba(30, 12, 50, 0.12);
  --pagenav-accent: #8200ff;       /* active pill + progress fill (lavender
                                      washes out on white glass) */
  --pagenav-accent-fg: #ffffff;
  --footer-bg: #0e011c;            /* contact footer (always dark) */
  --footer-surface: #1e0c32;
  --footer-border: #3d3350;
  --footer-fg: #ffffff;
  --footer-muted: #b3a0c8;
  --footer-subtle: #978aaa;
  --footer-primary: #8200ff;
  --footer-amber: #ffc20a;
  --footer-input-bg: rgba(0, 0, 0, 0.2);

  /* ---- Shadows (LIGHT; dark zeroes most of them) ---------------------- */
  --shadow-shell: 0 24px 48px rgba(30, 12, 50, 0.18);
  --shadow-media: 0 16px 24px rgba(30, 12, 50, 0.1);
  --shadow-thumb: 0 8px 16px rgba(30, 12, 50, 0.08);
  --shadow-chip: 0 4px 12px rgba(14, 1, 28, 0.25);
  --shadow-tooltip: 0 4px 12px rgba(14, 1, 28, 0.35);
  --shadow-pagenav: 0 12px 32px rgba(30, 12, 50, 0.18);
  --shadow-xm-card: 0 4px 4px rgba(12, 12, 13, 0.05), 0 16px 32px rgba(12, 12, 13, 0.1);
  --shadow-xm-card-hover: 0 8px 8px rgba(12, 12, 13, 0.06), 0 24px 48px rgba(12, 12, 13, 0.14);

  /* ---- Type ------------------------------------------------------------
     Gloock for display, Hanken Grotesk for everything else.
     Sizes in rem: the root px size scales up slightly on tablet/mobile
     (see BASE), so text grows without touching the px-based layout. */
  --font-display: 'Gloock', serif;
  --font-body: 'Hanken Grotesk', sans-serif;
  --fs-hero-title: clamp(2.375rem, 4.5vw, 3.5rem); /* H1 56 desktop */
  --ls-hero-title: 1.008px;                        /* 1.8% of 56px */
  --fs-headline: 2.125rem;   /* H3 34 — section headlines */
  --lh-headline: 1.12;
  --ls-headline: 0.612px;    /* 1.8% of 34px */
  --fs-subhead: 1.25rem;     /* H5 20/600 — section subheadings */
  --lh-subhead: 1.3;
  --fs-h4: 1.625rem;         /* H4 26/600 — caption heads, stat values */
  --lh-h4: 1.2;
  --fs-body: 1.0625rem;      /* Body 17 */
  --lh-body: 24px;
  --fs-value: 1.0625rem;     /* metadata values 17/600 */
  --fs-label: 0.8125rem;     /* 13/600 — metadata labels, eyebrows, quote names */
  --fs-note: 0.9375rem;      /* 15/600 — placeholder labels */
  --fs-tag: 0.75rem;         /* 12/500 — hero pills, quote roles, pagenav */
  --ls-quote-name: 1.56px;   /* 12% of 13px */

  /* ---- Spacing & layout ------------------------------------------------ */
  --content-w: 1184px;       /* section content width */
  --gutter: 48px;            /* shell side padding (desktop) */
  --section-gap: 96px;       /* gap between case sections + shell vertical pad */
  --band-py: 96px;           /* walkthrough band vertical padding */
  --gap-headline: 24px;      /* headline -> section content */
  --gap-text: 12px;          /* subheading -> body stack */
  --gap-para: 12px;          /* extra margin between body paragraphs (24 total) */
  --card-pad: 24px;          /* role card / quote card padding */
  --panel-pad: 28px;         /* tension + solution panel padding */
  --panel-w: 900px;          /* tension/solution/reflection card width */
  --measure: 720px;          /* centered prose measure */
  --hero-details-w: 420px;   /* hero details rail (desktop) */
  --nav-height: 96px;

  /* ---- Radii ----------------------------------------------------------- */
  --r-card: 8px;             /* cards, panels, stat/quote cards */
  --r-media: 12px;           /* gallery stage, problem image */
  --r-thumb: 8px;            /* gallery thumbs */
  --r-big: 20px;             /* reflection card, xm cards */
  --r-shell: 30px;           /* light-mode floating card corners */

  /* ---- Motion ---------------------------------------------------------- */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out-cubic: cubic-bezier(0.33, 1, 0.68, 1);
  --cascade-duration: 600ms;
  --cascade-step: 200ms;
}

/* ---- DARK MODE — values mapped onto the site's coded dark palette
   (#0e011c / #1e0c32 / #3d3350 family), NOT the Figma-file dark tokens,
   so this page matches the nav, footer, and the other case studies. ---- */
:root[data-theme='dark'] {
  --menu-hover-bg: color-mix(in srgb, var(--amber) 14%, transparent); /* nav row hover tint, dark */
  --bg: #0e011c;
  --surface: #1e0c32;
  --band-tint: #1e0c32;
  --band-plain: #0e011c;
  --band-surface: #1e0c32;
  --panel-tension: #3d3350;
  --panel-reflect: #1e0c32;
  --border: #3d3350;

  --fg: #ffffff;
  --fg-body: #ded7e6;        /* neutral-200 */
  --fg-subhead: #edeaf1;     /* mist */
  --fg-muted: #b3a0c8;
  --fg-subtle: #978aaa;
  --fg-label: #a79cb7;         /* site uses #978aaa, but that fails AA (3.7:1)
                                  on the #3d3350 quote cards — lightened along
                                  the same hue to pass 4.5:1 */

  --primary: #ffc20a;        /* problem icons + stat values go amber in dark */
  --primary-bright: #b679ff; /* walkthrough eyebrows */
  --icon-results: #a87a00;   /* amber-700 */
  --hero-bullet: #b679ff;
  --tag-border: #3d3350;
  --xm-band: #0e011c;
  --xm-client: #b3a0c8;
  --xm-stat: #ffffff;

  --gal-surface: #1e0c32;
  --gal-ph-bg: #241238;
  --gal-btn-bg: #b679ff;
  --gal-btn-bg-hover: #c79cff;
  --gal-btn-fg: #1e0c32;

  --lb-panel-bg: rgba(30, 12, 50, 0.84);
  --lb-fg: #ffffff;
  --lb-body: #ded7e6;
  --lb-label: #a79cb7; /* AA-corrected, matches --fg-label */

  /* dark surfaces carry no card shadows (per the dark Figma frames) */
  --shadow-shell: none;
  --shadow-xm-card: none;
  --shadow-xm-card-hover: none;

  /* Pagenav: dark plum glass, lavender accent */
  --pagenav-bg: rgba(30, 12, 50, 0.82);
  --pagenav-border: rgba(255, 255, 255, 0.08);
  --pagenav-fg: rgba(255, 255, 255, 0.75);
  --pagenav-fg-hover: #ffffff;
  --pagenav-track: rgba(255, 255, 255, 0.12);
  --pagenav-accent: #e6d4ff;
  --pagenav-accent-fg: #1e0c32;
  --shadow-pagenav: 0 12px 32px rgba(14, 1, 28, 0.4);
}


/* ==========================================================================
   2. BASE
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

/* Root type scaling: bumps every rem-based text size on smaller screens
   without touching px-based layout (paddings, heights, gaps stay put) */
html { background: var(--frame); font-size: 16px; }

@media (max-width: 1023px) {
  html { font-size: 17px; } /* tablet: +6.25% */
}

@media (max-width: 767px) {
  html { font-size: 17.5px; } /* mobile: +9.4% */

  :root {
    --nav-height: 76px;

    /* ---- Mobile type scale ---------------------------------------------
       The root bump just above is what makes this necessary: every rem size
       lands ~9% larger here, so the desktop scale was rendering section
       headlines at 37px, subheads at 22px and body at 18.6px against the
       fixed 24px --lh-body — a 1.29 ratio, too tight for the long
       walkthrough blocks. Retuning the tokens moves every consumer at once
       and lands the page on the same scale as the homepage card that opens
       it. Rendered px at the 17.5px mobile root:

         headline  1.625rem  -> 28.4px
         subhead   1.125rem  -> 19.7px
         h4        1.25rem   -> 21.9px
         body      0.9375rem -> 16.4px  (~42 chars/line)

       --lh-body goes unitless so leading tracks the size from here down. */
    --fs-headline: 1.625rem;
    --lh-headline: 1.15;
    --ls-headline: 0.5px;   /* still 1.8%, of 28px now */
    --fs-subhead: 1.125rem;
    --lh-subhead: 1.35;
    --fs-h4: 1.25rem;
    --lh-h4: 1.25;
    --fs-body: 0.9375rem;
    --lh-body: 1.5;
    --fs-value: 0.9375rem;
  }
}

/* The dark plum frame shows through the gaps around the light card and
   below the Explore More band, reading as one surface with the footer.
   The frame lives on html only — body stays transparent so the shell's
   hero-colored ::before backing (section 8) can sit between the frame
   and the card's rounded top corners. */
body {
  margin: 0;
  background: transparent;
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

body.menu-open { overflow: hidden; }

img { max-width: 100%; display: block; }

a, button {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

section[id], footer[id] { scroll-margin-top: 96px; }

/* Anchored walkthrough bands ride flush to the viewport top (matches the
   JS ANCHOR_OFFSET_OVERRIDES for the animated ride) */
#digital-drivers-license, #design-system { scroll-margin-top: 0; }

/* Page transition veil: fades internal navigations out and page loads in */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 4000;
  background: var(--bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 600ms ease;
}

html.page-enter body::after {
  opacity: 1;
  transition: none;
}

html.page-leave body::after {
  opacity: 1;
  pointer-events: auto;
}

/* Brief cross-fade while the theme switches (class added by JS) */
html.theme-fade,
html.theme-fade body,
html.theme-fade *:not(img) {
  transition: background-color 300ms ease, color 300ms ease,
    border-color 300ms ease, fill 300ms ease !important;
}


/* ==========================================================================
   3. CASCADE ANIMATIONS
   .cascade — load-time fade-up (hero), staggered via --i
   [data-cascade] — scroll-triggered fade-up, staggered via --d, revealed
   when an ancestor [data-animate-case]/[data-animate] gains .in-view
   ========================================================================== */
.cascade {
  opacity: 0;
  transform: translateY(20px);
  animation: cascade-in var(--cascade-duration) ease-out forwards;
  animation-delay: calc(200ms + var(--i) * var(--cascade-step));
}

@keyframes cascade-in {
  to { opacity: 1; transform: translateY(0); }
}

[data-cascade] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 600ms var(--ease-out-cubic), transform 600ms var(--ease-out-cubic);
  transition-delay: var(--d, 0ms);
}

.in-view [data-cascade] {
  opacity: 1;
  transform: translateY(0);
}


/* ==========================================================================
   4. SITE NAV
   Color follows what's BEHIND the nav (not the theme): white text over
   dark backdrops, plum over the light shell (.on-light toggled by JS).
   ========================================================================== */
.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity 400ms ease-out, transform 400ms ease-out;
  pointer-events: none;
}

/* The top scrims are gone (Dave 2026-09-07); the nav rides bare over the hero */

.site-nav.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.site-nav.is-loaded {
  transition: opacity 600ms ease-out, transform 600ms ease-out;
}

.site-nav.is-hidden {
  opacity: 0;
  transform: translateY(-100%);
  pointer-events: none;
}

.site-nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  height: var(--nav-height);
  padding: 0 48px;
}

/* Bare gradient D in its own frosted tile — the glass adapts to the
   backdrop (via .on-light below), so one mark serves both themes. Squared
   off at 16px against the pill-shaped capsules, and flex centering keeps
   the D on the same midline as the links. */
.site-nav__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 68px;
  height: 68px;
  flex-shrink: 0;
  border-radius: 16px;
  background: rgba(30, 12, 50, 0.85); /* plum frost over dark backdrops; .on-light swaps in the white frost (Dave 2026-09-07) */
  border: 1px solid rgba(255, 255, 255, 0.12);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  transition: background 400ms ease, border-color 400ms ease;
}

.site-nav__logo img {
  display: block;
  height: 38px;
  width: auto;
  transition: filter 400ms ease;
}

/* The mark keeps its full-colour gradient in every state (Dave 2026-09-07);
   the tile's glass flips for contrast, the mark itself does not. */
.site-nav__logo img { filter: none; }

/* Frosted glass capsules: a 999px radius (greater than the height, so it
   renders as a full pill) plus backdrop blur keeps the text legible over
   busy backdrops. The links group hugs its content — the inner flexbox's
   space-between splits the leftover space evenly, so it stays centered
   between the logo and the actions cluster. */
.site-nav__links,
.site-nav__actions {
  border-radius: 999px;
  background: rgba(30, 12, 50, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.12);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  transition: background 400ms ease, border-color 400ms ease;
}

/* Frosted white over light backdrops — same signal as the link colors */
.site-nav.on-light .site-nav__logo,
.site-nav.on-light .site-nav__links,
.site-nav.on-light .site-nav__actions,
.site-nav.on-light .nav-toggle {
  background: rgba(255, 255, 255, 0.55);
  border-color: rgba(30, 12, 50, 0.1);
}

/* The logo tile goes to a 65% white frost over light sections */
.site-nav.on-light .site-nav__logo { background: rgba(255, 255, 255, 0.65); }

/* Over the hero (data-nav-bare; la-wallet.js toggles .is-over-hero and the
   header bakes it in for the first frame) the mark rides bare at 46px,
   while the Contact / Menu frame stays; the tile returns once the shell
   slides over (Dave 2026-09-07). */
.site-nav.is-over-hero .site-nav__logo {
  background: transparent;
  border-color: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.site-nav.is-over-hero .site-nav__logo img { height: 46px; }

.site-nav__links {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 44px;
  height: 56px;
  padding: 0 36px;
}

/* Theme toggle + Contact share one capsule */
.site-nav__actions {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 5px 5px 9px; /* 44px controls + 10px + 2px border = the links capsule's 56px */
  flex-shrink: 0;
}

.nav-link {
  font-family: var(--font-body);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--nav-fg);
  text-decoration: none;
  transition: color 300ms ease;
}

.nav-link__mask {
  display: inline-flex;
  flex-direction: column;
  height: 1.4em;
  overflow: hidden;
}

.nav-link__text {
  display: block;
  transition: transform 350ms var(--ease-out);
}

.nav-link:hover .nav-link__text,
.nav-link:focus-visible .nav-link__text {
  transform: translateY(-100%);
}

.nav-link__text--hover { color: var(--amber); }

.nav-link--contact {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 24px;
  border: 1px solid var(--nav-ghost-border);
  border-radius: 999px; /* capsule, nests concentric inside the actions pill */
  flex-shrink: 0;
  transition: border-color 300ms ease, color 300ms ease;
}

.nav-link--contact:hover { border-color: var(--nav-fg); }

/* Over light backdrops: dark plum text */
.site-nav.on-light .nav-link { color: var(--nav-fg-on-light); }
.site-nav.on-light .nav-link__text--hover { color: var(--primary-bright); }
.site-nav.on-light .nav-link--contact { border-color: var(--nav-ghost-border-on-light); }
.site-nav.on-light .nav-toggle__bar { background: var(--nav-fg-on-light); }
.site-nav.on-light .theme-toggle { color: var(--nav-fg-on-light); }

/* ---- Theme toggle (sun/moon) ------------------------------------------ */
.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--nav-fg);
  flex-shrink: 0;
  transition: color 300ms ease, transform 200ms var(--ease-out);
}

.theme-toggle:hover,
.theme-toggle:focus-visible {
  color: var(--amber);
  transform: scale(1.08);
}

.site-nav.on-light .theme-toggle:hover,
.site-nav.on-light .theme-toggle:focus-visible { color: var(--primary-bright); }

.theme-toggle__icon { width: 22px; height: 22px; }

/* Show the icon of the mode you'd switch TO */
.theme-toggle__icon--sun { display: none; }
:root[data-theme='dark'] .theme-toggle__icon--sun { display: block; }
:root[data-theme='dark'] .theme-toggle__icon--moon { display: none; }

/* Tooltip hangs below the button, since the nav is pinned to the top */
.theme-toggle { position: relative; }

.theme-toggle[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% - 2px);
  right: 0;
  padding: 7px 10px;
  border-radius: 6px;
  background: var(--tooltip-bg);
  color: var(--tooltip-fg);
  font-family: var(--font-body);
  font-size: var(--fs-tag);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  box-shadow: var(--shadow-tooltip);
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 160ms ease, transform 160ms var(--ease-out-cubic);
}

@media (hover: hover) and (pointer: fine) {
  .theme-toggle:hover::after,
  .theme-toggle:focus-visible::after {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 300ms; /* same dwell as the gallery chips */
  }
}

/* ---- Hamburger --------------------------------------------------------- */
/* Frosted glass disc matching the nav capsules (mobile only) */
.nav-toggle {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: 56px;
  height: 56px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  background: rgba(30, 12, 50, 0.35);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 400ms ease, border-color 400ms ease;
}

.nav-toggle:hover,
.nav-toggle:focus,
.nav-toggle:active {
  outline: none;
}

.nav-toggle__bar {
  display: block;
  width: 26px;
  height: 2px;
  border-radius: 2px;
  background: var(--nav-fg);
  /* Closed-state transition = the CLOSING leg: un-rotate the X first,
     then glide the bars back apart (middle bar fades in at the end) */
  transition: rotate 200ms var(--ease-out), translate 200ms var(--ease-out) 160ms,
    opacity 160ms ease 200ms, background-color 300ms ease;
}

/* Hamburger -> X in two beats: outer bars glide to center, THEN rotate.
   translate/rotate are separate properties (not one transform) so each leg
   runs on its own clock — a combined transform swings the bars on a curve. */
.nav-toggle.is-open .nav-toggle__bar {
  transition: translate 200ms var(--ease-out), rotate 200ms var(--ease-out) 160ms,
    opacity 160ms ease, background-color 300ms ease;
}

.nav-toggle.is-open .nav-toggle__bar:nth-child(1) { translate: 0 9px; rotate: 45deg; }
.nav-toggle.is-open .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle.is-open .nav-toggle__bar:nth-child(3) { translate: 0 -9px; rotate: -45deg; }

:root[data-theme='light'] .nav-toggle.is-open .nav-toggle__bar {
  background: var(--nav-fg-on-light);
}

/* The theme toggle beside the X needs the same light-mode flip or it goes
   white-on-white over the open menu's white panel */
:root[data-theme='light'] body.menu-open .theme-toggle {
  color: var(--nav-fg-on-light);
}

/* ---- Nav: tablet + mobile ---------------------------------------------- */
@media (max-width: 1023px) {
  .site-nav__links,
  .site-nav__actions > .nav-link--contact { display: none; }
  .nav-toggle { display: flex; }
  /* Contact drops out, so the actions capsule tightens into a 56px glass
     disc around the toggle, pulled right to pair with the hamburger disc.
     The negative margin trims the 32px flex gap between the two. */
  .theme-toggle__icon { width: 26px; height: 26px; }
  .site-nav__actions { margin-left: auto; margin-right: -16px; padding: 5px; }
  .site-nav__inner { padding: 0 32px; }

  /* Logo drops back to the 56px the toggle and hamburger discs use, so the
     three controls stay a matched set on small screens. The radius scales
     with it (13/56 matches desktop's 16/68) to keep the same corner. */
  .site-nav__logo { width: 56px; height: 56px; border-radius: 13px; }
  .site-nav__logo img { height: 30px; }
  .site-nav.is-over-hero .site-nav__logo img { height: 36px; } /* the bare-hero step-up, scaled to the smaller tile */
}

@media (max-width: 767px) {
  .site-nav__inner { padding: 0 16px; gap: 12px; }
  /* The 12px gap here is already tight — drop the tablet pull-in */
  .site-nav__actions { margin-right: 0; }

  /* Menu controls at Apple's 44x44 minimum tap target, glyphs sized down
     inside — mirrors styles.css. X-state translate shrinks with the bar
     gap (5px gap + 2px bar = 7px from the outer bars to center). */
  .nav-toggle {
    width: 44px;
    height: 44px;
    gap: 5px;
  }

  .nav-toggle__bar { width: 20px; }

  .nav-toggle.is-open .nav-toggle__bar:nth-child(1) { translate: 0 7px; }
  .nav-toggle.is-open .nav-toggle__bar:nth-child(3) { translate: 0 -7px; }

  .site-nav__actions { padding: 0; }
  .theme-toggle__icon { width: 20px; height: 20px; }
}


/* ==========================================================================
   5. MOBILE MENU
   ========================================================================== */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--surface);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform 450ms var(--ease-out), visibility 0s linear 450ms;
  display: flex;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Bleed the panel past the viewport top/bottom so iOS Safari's translucent
   status bar and URL bar sample the panel, not the page behind it. Rides
   inside the panel (moves with the slide), behind its own background.
   la-wallet.js pairs this with a theme-color swap for the solid chrome tint. */
.mobile-menu::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: -120px;
  bottom: -120px;
  z-index: -1;
  background: var(--surface);
}

.mobile-menu.is-open {
  transform: translateY(0);
  visibility: visible;
  transition: transform 450ms var(--ease-out), visibility 0s;
}

.mobile-menu__nav {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  width: 100%;
  margin: auto;
  padding: 112px 24px 48px;
}

/* Mirrors assets/css/styles.css (this page is standalone): each entry is
   an item carrying the cascade; Case Studies and Select Work rows carry a
   chevron that opens a sub-list */
.mobile-menu__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 400ms ease-out, transform 400ms var(--ease-out);
}

.mobile-menu.is-open .mobile-menu__item {
  opacity: 1;
  transform: translateY(0);
  transition-delay: calc(150ms + var(--i) * 70ms);
}

.mobile-menu__link {
  font-family: var(--font-display);
  font-size: 2.125rem;
  letter-spacing: 0.8px;
  color: var(--fg);
  text-decoration: none;
  transition: color 200ms ease;
}

.mobile-menu__link:hover { color: var(--primary-bright); }

.mobile-menu__row {
  position: relative;
  display: flex;
  align-items: center;
}

/* Accordion rows are BUTTONS (Dave 2026-09-07): the whole row, label
   and chevron, toggles the sub-list in place and never navigates. Reset
   the button to read exactly like the plain links beside it. */
button.mobile-menu__row {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

button.mobile-menu__row:focus-visible {
  outline: 2px solid var(--primary-bright);
  outline-offset: 4px;
  border-radius: 4px;
}

/* The chevron is the row's affordance, not a control of its own: it
   turns with the row's aria-expanded */
.mobile-menu__row[aria-expanded='true'] .mobile-menu__expand { color: var(--primary-bright); }
.mobile-menu__row[aria-expanded='true'] .mobile-menu__chevron { transform: rotate(180deg); }

.mobile-menu__expand {
  position: absolute;
  left: 100%;
  top: 50%;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 2px;
  padding: 0;
  border: 0;
  border-radius: 22px;
  background: none;
  color: var(--fg-muted);
  cursor: pointer;
  transition: color 200ms ease;
}

.mobile-menu__row:hover .mobile-menu__expand { color: var(--primary-bright); }

.mobile-menu__chevron { transition: transform 300ms var(--ease-out); }

.mobile-menu__sub {
  display: grid;
  grid-template-rows: 0fr;
  width: 100%;
  transition: grid-template-rows 320ms var(--ease-out);
}

.mobile-menu__sub.is-open { grid-template-rows: 1fr; }

.mobile-menu__sub-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 0;
  overflow: hidden;
}

.mobile-menu__sub-inner > :first-child { margin-top: 12px; }
.mobile-menu__sub-inner > :last-child { margin-bottom: 4px; }

.mobile-menu__sublink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px;
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
  color: var(--fg-muted);
  text-decoration: none;
  transition: color 200ms ease;
}

.mobile-menu__sublink:hover,
.mobile-menu__sublink:focus-visible { color: var(--primary-bright); }
/* Active state (Dave 2026-09-07): where you are, at every width and in
   both themes, in the accent with a 600 weight and a 3px bar in the
   gutter beside the row (colour is never the only signal); an active
   sub-item adds a 6px dot and lights its parent row so the group reads
   active while collapsed. main.js sets it on the homepage as sections
   pass the same offset the scroll rides use; inner pages carry it in the
   markup (aria-current="page" on their own entry). Declared after the
   hover rules so hovering a row never hides it. */
.mobile-menu__link.is-active {
  color: var(--primary-bright);
  font-weight: 600;
}

.mobile-menu__link.is-active::before {
  content: '';
  position: absolute;
  left: calc(-1 * var(--menu-gutter, 32px));
  /* Runs the full row
     (the row link carries the vertical padding now, so the bar is simply
     top 0 to bottom 0) (Dave 2026-09-07) */
  top: 0;
  bottom: 0;
  width: 4px;
  border-radius: 2px;
  background: var(--primary-bright);
}

.mobile-menu__sublink.is-active,
.mobile-menu__sublink[aria-current='page'] { color: var(--primary-bright); }

.mobile-menu__sublink.is-active::before,
.mobile-menu__sublink[aria-current='page']::before {
  content: '';
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 3px;
  background: var(--primary-bright);
}

/* "All Case Studies" / "All Select Work": the parent-level action, first
   in each list, a shade firmer than the entries under it with a hairline
   beneath (Dave 2026-09-07) */
.mobile-menu__sublink--all {
  width: 100%;
  margin-bottom: 4px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  color: var(--fg);
}

.mobile-menu__sublink.is-soon {
  flex-wrap: wrap; /* a long title keeps its line; the pill drops under it */
  justify-content: center;
  row-gap: 2px;
  color: var(--fg-subtle);
  pointer-events: none;
  cursor: default;
}

.mobile-menu__soon {
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 64px;
  background: var(--band-tint);
  color: var(--fg-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.4px;
  line-height: 1.5;
  white-space: nowrap;
}

@media (max-width: 767px) {
  .mobile-menu__link { font-size: 1.75rem; }
}


/* ==========================================================================
   6. HERO — the homepage card expanded to the viewport. Sticky: the
   content shell slides over it. Image left / details right (Figma).
   data-nav-theme-fixed keeps the nav white over the dark photo.
   ========================================================================== */
.csp-hero {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  min-height: 0;
  /* 1080px at the 1920 Figma frame, scaling with the viewport — but never
     taller than the real viewport, so the phone in the hero photos isn't
     pushed under the fold / fixed pagenav */
  height: clamp(720px, 56.25vw, 1080px);
  height: min(clamp(720px, 56.25vw, 1080px), 100vh);
  height: min(clamp(720px, 56.25vw, 1080px), 100svh);
  position: sticky;
  top: 0;
  overflow: hidden;
  background: var(--surface);
}

/* Details on the right (Figma "Case Study" frame: image 1500 / details 420) */
.csp-hero--details-right { flex-direction: row-reverse; }

.csp-hero__details {
  width: var(--hero-details-w);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 36px;
  padding: 48px 36px;
  background: var(--surface);
}

/* Desktop: the hero can be taller than the viewport and is sticky, so cap
   the centering space to the first viewport */
@media (min-width: 1024px) {
  .csp-hero__details {
    align-self: flex-start;
    height: min(100%, 100vh);
    height: min(100%, 100svh);
  }
}

.csp-hero__info {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.csp-hero__media {
  flex: 1;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--bg);
  position: relative; /* carousel overlays stack inside */
}

.csp-hero__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.csp-hero__img--slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1s ease;
}

.csp-hero__img--slide.is-active { opacity: 1; }

/* Hero arrival: plain fade */
.csp-hero--fade { animation: csp-hero-fade 600ms ease-out both; }

@keyframes csp-hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.csp-hero__client {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--fg-subtle);
}

.csp-hero__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-hero-title);
  line-height: normal;
  letter-spacing: var(--ls-hero-title);
  color: var(--fg);
}

.csp-hero__subtitle {
  margin: 0;
  max-width: 720px;
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--fg-muted);
}

.csp-hero__tags {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.csp-hero__tags li {
  border: 1.5px solid var(--tag-border);
  border-radius: 64px;
  padding: 4px 8px;
  font-size: var(--fs-tag);
  font-weight: 500;
  line-height: 1.5;
  color: var(--fg-muted);
  white-space: nowrap;
}

.csp-hero__stats {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.csp-hero__stats li {
  position: relative;
  padding-left: 16px;
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 24px;
  color: var(--fg-muted);
}

/* Hero source line: mouse type. Pinned to the bottom of the details panel
   on desktop (the panel is viewport-height there); in flow after the stats
   on stacked layouts. Same rule as the shared case-study.css (this page is
   self-contained). Light holds the muted token at 85% to clear AA (5.0:1 on
   #ffffff); dark can sit at 75% (4.8:1 on #1e0c32) at this size. */
.csp-hero__source {
  margin: 0;
  font-size: 0.6875rem;
  font-weight: 400;
  line-height: 1.4;
  color: color-mix(in srgb, var(--fg-muted) 85%, transparent);
}

:root[data-theme='dark'] .csp-hero__source {
  color: color-mix(in srgb, var(--fg-muted) 75%, transparent);
}

@media (min-width: 1024px) {
  .csp-hero__details { position: relative; }
  .csp-hero__source {
    position: absolute;
    left: 36px;
    right: 36px;
    bottom: 20px;
  }
}

.csp-hero__stats li::before {
  content: '\2022';
  position: absolute;
  left: 0;
  color: var(--hero-bullet);
}

/* ---- Hero: tablet — image stacks on top, 50/50 viewport split ---------- */
@media (max-width: 1023px) {
  .csp-hero,
  .csp-hero--details-right {
    flex-direction: column-reverse;
    height: auto;
    min-height: 100vh;
    min-height: 100svh;
  }

  .csp-hero__media {
    flex: none;
    width: 100%;
    height: 50vh;
    height: 50svh;
  }

  .csp-hero__details {
    width: 100%;
    flex-shrink: 0;
    justify-content: flex-start;
    min-height: 50vh;
    min-height: 50svh;
  }
}

/* ---- Hero: mobile — reads like the homepage cs-card: image on top, then
   a compact content-height details panel (client, title, body, stats) with
   the card's type scale. Mirrors case-study.css — this page carries its
   own copy. ------------------------------------------------------------- */
@media (max-width: 767px) {
  /* The hero unpins and flows, and drops the full-screen min-height: a
     card hugs its content, so the shell peeks below on taller phones. */
  .csp-hero {
    position: static;
    height: auto;
    min-height: 0;
  }

  .csp-hero__media {
    flex: none;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    min-height: 0;
  }

  .csp-hero__details {
    flex: none;
    min-height: 0;
    padding: 24px 16px 96px; /* bottom clears the fixed pagenav */
    gap: 20px;
  }

  .csp-hero__info { gap: 16px; }
  .csp-hero__client { font-size: 1.25rem; }
  .csp-hero__title { font-size: 2.125rem; line-height: 1.05; }
  .csp-hero__subtitle { font-size: 1.0625rem; }
  .csp-hero__stats li { font-size: 1rem; line-height: 1.4; }
  .csp-hero__tags { display: none; }
}

/* Phone-width hero details step down with the homepage .cs-card 480 block
   so the panel reads like the card that opened it */
@media (max-width: 480px) {
  .csp-hero__details { padding: 20px 16px 96px; gap: 14px; }
  .csp-hero__info { gap: 10px; }
  .csp-hero__client { font-size: 0.9375rem; }
  .csp-hero__title { font-size: 1.625rem; }
  .csp-hero__subtitle { font-size: 0.9375rem; }
  .csp-hero__stats { gap: 6px; }
  .csp-hero__stats li { font-size: 0.875rem; line-height: 1.35; }
}


/* ==========================================================================
   7. PAGE NAV — floating glass bar fixed to the viewport bottom
   ========================================================================== */
.pagenav {
  position: fixed;
  left: 24px;
  right: 24px;
  bottom: 24px;
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  pointer-events: none;
  transition: opacity 250ms ease;
}

/* The full-screen menu is a takeover — the floating page nav (z 120) would
   otherwise ride above the panel (z 90) and the top bar (z 100) */
body.menu-open .pagenav {
  opacity: 0;
  pointer-events: none;
}

body.menu-open .pagenav .pagenav__bar,
body.menu-open .pagenav .pagenav__home { pointer-events: none; }

.pagenav.is-hidden .pagenav__bar,
.pagenav.is-hidden .pagenav__home {
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
}

.pagenav__home {
  pointer-events: auto;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: var(--pagenav-bg);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid var(--pagenav-border);
  border-radius: 10px;
  box-shadow: var(--shadow-pagenav);
  color: var(--pagenav-fg);
  text-decoration: none;
  transition: color 200ms ease, background 200ms ease, opacity 400ms ease, transform 400ms ease;
}

.pagenav__home svg { width: 16px; height: 16px; }

.pagenav__home:hover,
.pagenav__home:focus-visible {
  background: var(--pagenav-accent);
  color: var(--pagenav-accent-fg);
}

.pagenav__bar {
  pointer-events: auto;
  transition: opacity 400ms ease, transform 400ms ease;
  display: flex;
  flex-direction: column;
  max-width: 100%;
  background: var(--pagenav-bg);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid var(--pagenav-border);
  border-radius: 10px;
  overflow: hidden;
  box-shadow: var(--shadow-pagenav);
}

/* The row scrolls horizontally when it overflows (mobile) */
.pagenav__buttons {
  display: flex;
  gap: 4px;
  padding: 6px;
  overflow-x: auto;
  scrollbar-width: none;
}

.pagenav__buttons::-webkit-scrollbar { display: none; }

.pagenav__btn {
  flex-shrink: 0;
  padding: 8px 12px;
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: var(--fs-tag);
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.2px;
  color: var(--pagenav-fg);
  text-decoration: none;
  white-space: nowrap;
  transition: color 200ms ease, background 200ms ease;
}

.pagenav__btn:hover,
.pagenav__btn:focus-visible { color: var(--pagenav-fg-hover); }

.pagenav__btn.is-active {
  background: var(--pagenav-accent);
  color: var(--pagenav-accent-fg);
}

.pagenav__btn.is-active:hover { color: var(--pagenav-accent-fg); }

.pagenav__progress {
  height: 4px;
  width: 100%;
  background: var(--pagenav-track);
}

.pagenav__progress-fill {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--pagenav-accent);
  transform: scaleX(0);
  transform-origin: left center;
}

/* Page-load entrance: the bar rises, then buttons cascade in */
.pagenav--enter .pagenav__bar,
.pagenav--enter .pagenav__home {
  animation: pagenav-rise 700ms var(--ease-out-cubic) 200ms both;
}

.pagenav--enter .pagenav__btn {
  opacity: 0;
  animation: pagenav-btn-in 400ms var(--ease-out-cubic) both;
  animation-delay: calc(600ms + var(--i, 0) * 300ms);
}

@keyframes pagenav-rise {
  from { transform: translateY(50vh); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

@keyframes pagenav-btn-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (max-width: 767px) {
  /* Phones keep the same nav readability scrims as desktop/tablet
     (restored 2026-08-20 alongside the homepage hero-stills change) */

  /* Phone bottom nav hugs the viewport bottom (8px + home-indicator
     clearance) but keeps 20px side gutters, so it still reads as a
     rounded floating bar — just without the shadow halo */
  .pagenav {
    left: 20px;
    right: 20px;
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  }

  /* No home button — the section pills take the full width, each flexing
     to an even share (the row still side-scrolls if the labels genuinely
     can't fit). Desktop/tablet keep the home disc. */
  .pagenav__home { display: none; }

  .pagenav__bar {
    width: 100%;
    box-shadow: none;
  }

  .pagenav__btn {
    flex: 1 0 auto;
    text-align: center;
  }
}


/* ==========================================================================
   8. CONTENT SHELL — floating white card in light mode (rounded, shadow,
   16px reveal strip below), plain dark surface in dark mode
   ========================================================================== */
.csp-shell {
  position: relative;
  background: var(--bg);
}

/* Backing strip behind the shell's top corners: hero-colored (--surface,
   both themes), so the wedges the top radius cuts away read as the hero
   continuing rather than the footer frame. z-index -1 drops it behind the
   shell surface; visible only once the unpinned mobile hero scrolls away
   (desktop's sticky hero paints over it). Needs the transparent body. */
.csp-shell::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--r-shell);
  background: var(--surface);
  z-index: -1;
}

:root[data-theme='light'] .csp-shell {
  margin: 0 0 16px;
  border-radius: var(--r-shell);
  box-shadow: var(--shadow-shell);
}

.csp-shell__inner {
  max-width: calc(var(--content-w) + var(--gutter) * 2);
  margin: 0 auto;
  padding: var(--section-gap) var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--section-gap);
}

/* The contained content keeps its bottom padding so a strip of shell
   background separates the Solution card from the first walkthrough band
   (Figma: section 4 ends with 96px of plain background) */

/* The band above Results runs to its own edge, so Results keeps the
   standard top padding */
.csp-shell__inner--results { padding-top: var(--section-gap); }

@media (max-width: 1023px) {
  :root { --gutter: 24px; --section-gap: 64px; }
}

@media (max-width: 767px) {
  :root { --gutter: 16px; --section-gap: 48px; }
}


/* ==========================================================================
   9. CASE PRIMITIVES — shared type + metadata pieces
   ========================================================================== */
.case-block {
  display: flex;
  flex-direction: column;
  gap: var(--section-gap);
  width: 100%;
}

.case-section {
  display: flex;
  flex-direction: column;
  gap: var(--gap-headline);
  width: 100%;
  scroll-margin-top: 96px;
}

.case-headline {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-headline);
  line-height: var(--lh-headline);
  letter-spacing: var(--ls-headline);
  color: var(--fg);
}

.case-subheading {
  margin: 0;
  font-size: var(--fs-subhead);
  font-weight: 600;
  line-height: var(--lh-subhead);
  color: var(--fg-subhead);
}

.case-body {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--fg-body);
}

/* Metadata label/value pairs */
.case-meta__item {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.case-meta__item dt {
  font-size: var(--fs-label);
  font-weight: 600;
  line-height: normal;
  text-transform: uppercase;
  color: var(--fg-label);
}

.case-meta__item dd {
  margin: 0;
  font-size: var(--fs-value);
  font-weight: 600;
  line-height: 1.4;
  color: var(--fg);
}

/* Neutral gray placeholder block (problem illustration slot) */
.ph-block {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: var(--r-media);
  background: var(--gal-ph-bg);
}


/* ==========================================================================
   10. OVERVIEW — intro left (600px), one Role + metadata card right
   ========================================================================== */
.case-overview__row {
  display: flex;
  align-items: flex-start;
  gap: 72px;
  width: 100%;
}

.case-overview__main {
  width: 600px;
  max-width: 100%;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 30px;
}

.case-overview__intro {
  display: flex;
  flex-direction: column;
  gap: var(--gap-text);
}

/* Paragraph rhythm: 12px flex gap + 12px margin = 24px */
.case-overview__intro .case-body + .case-body { margin-top: var(--gap-para); }

.case-overview__aside {
  flex: 1 1 0;
  min-width: 0;
}

/* One bordered card holding Role + all metadata rows */
.rolecard {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: var(--card-pad);
  border-radius: var(--r-card);
  background: var(--surface);
  border: 1px solid var(--border);
}

.rolecard__role {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.rolecard__header {
  display: flex;
  align-items: center;
  gap: 12px;
}

.rolecard__icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  color: var(--fg-subtle);
}

.rolecard__icon svg { width: 32px; height: 32px; }

@media (max-width: 1023px) {
  .case-overview__row { flex-direction: column; gap: 24px; }
  .case-overview__main { width: 100%; }
  .case-overview__aside { flex: none; width: 100%; }
}

@media (max-width: 767px) {
  .case-overview__row { gap: 48px; }
  .case-overview__main { gap: 48px; }
  .rolecard { padding: 16px; }
}


/* ==========================================================================
   11. THE PROBLEM — centered header, illustration left, stacked items right
   ========================================================================== */
.problem { gap: 48px; }

.problem__header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap-headline);
  width: 100%;
  text-align: center;
}

.problem__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap-text);
  width: 100%;
}

.problem__lede {
  width: var(--panel-w);
  max-width: 100%;
}

.problem__lede .case-body + .case-body { margin-top: var(--gap-para); }

.problem__details {
  display: flex;
  align-items: center;
  gap: 64px;
  width: 100%;
}

.problem__image {
  margin: 0;
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 720 / 488;
  border-radius: 16px;
  overflow: hidden;
}

.problem__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.problem__grid {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 24px;
  flex: 0 1 400px;
  min-width: 0;
}

.problem__item {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* 24px glyph in a 34px-wide box */
.problem__icon {
  width: 34px;
  display: flex;
  justify-content: center;
  color: var(--primary);
}

.problem__icon svg { width: 24px; height: 24px; }

.problem__copy {
  display: flex;
  flex-direction: column;
}

.problem__title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--fg);
}

.problem__desc {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--fg-body);
}

@media (max-width: 1023px) {
  .problem__lede { width: 100%; }
  .problem__details { flex-direction: column; gap: 48px; }
  .problem__image { flex: none; width: 100%; }
  .problem__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 30px; flex: none; width: 100%; }
}

@media (max-width: 767px) {
  .problem__grid { grid-template-columns: 1fr; gap: 24px; }
}


/* ==========================================================================
   12. CORE TENSION + SOLUTION — stacked 900px centered cards.
   Tension: tinted fill, no border. Solution: card fill + border.
   ========================================================================== */
.cts {
  display: flex;
  flex-direction: column;
  gap: 28px;
  align-items: stretch;
  align-self: center;
  width: var(--panel-w);
  max-width: 100%;
}

.panel {
  width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: var(--panel-pad);
  border-radius: var(--r-card);
  scroll-margin-top: 96px;
}

.panel--tension { background: var(--panel-tension); }

.panel--solution {
  background: var(--surface);
  border: 1px solid var(--border);
}

.panel__text {
  display: flex;
  flex-direction: column;
  gap: var(--gap-text);
  width: 100%;
}

.panel__text .case-body + .case-body { margin-top: var(--gap-para); }

@media (max-width: 767px) {
  .panel { padding: 20px; }
}


/* ==========================================================================
   13. FEATURE WALKTHROUGH — full-bleed alternating bands inside the shell
   but outside the max-width inner. Tint / plain / tint / plain, then the
   Synthesis interlude, then the Design System band (surface, centered).
   ========================================================================== */
.walk {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.walk__band {
  display: flex;
  justify-content: center;
  width: 100%;
  padding: var(--band-py) 24px;
  background: var(--band-plain);
  scroll-margin-top: 96px;
}

.walk__band--tint { background: var(--band-tint); }
.walk__band--surface { background: var(--band-surface); }

/* Anchored bands ride flush to the viewport top */
.walk__band[id] { scroll-margin-top: 0; }

.walk__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 48px;
  width: var(--content-w);
  max-width: 100%;
}

/* Header constrained to the gallery hero's column (954 of 1184) so the
   copy aligns with the image edge */
.walk__head {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: calc((954 / 1160) * (100% - 24px));
}

.walk__titleblock {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.walk__eyebrow {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 600;
  line-height: 1;
  text-transform: uppercase;
  color: var(--primary-bright);
}

.walk__headline {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-headline);
  line-height: 1.1;
  letter-spacing: var(--ls-headline);
  color: var(--fg);
}

.walk__body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--fg-body);
}

/* Multi-paragraph band bodies: 8px container gap + 16px margin = 24 */
.walk__body + .walk__body { margin-top: 16px; }

/* Chip row under the body copy. These bands carry static phone images
   rather than a gallery, so there is no stage for chips to sit on —
   the gallery stage's chip pair rendered inline instead: a screenshot
   light/dark mode toggle, then the copy-link chip. */
.walk__chips {
  display: flex;
  gap: 8px;
  align-self: flex-start;
  margin-top: 16px;
}

/* Same box as .gallery__expand / .gallery__link, minus the absolute
   stage positioning */
.walk__chip {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: var(--chip-bg);
  color: var(--chip-fg);
  cursor: pointer;
  box-shadow: var(--shadow-chip);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition: background 200ms ease, transform 200ms var(--ease-out-cubic);
}

/* The copy-link chip goes circular so the switch + link pair read as one
   glass family; gallery stage chips keep the square corner look */
.walk__chip--link { border-radius: 50%; }

.walk__chip:hover,
.walk__chip:focus-visible { background: var(--chip-bg-hover); }

.walk__chip:hover { transform: translateY(-1px); }

.walk__chip svg { width: 16px; height: 16px; }

.walk__chip:focus-visible {
  outline: 2px solid var(--primary-bright);
  outline-offset: 2px;
}

/* The mode chip is a switch: a pill track with sun and moon at either
   end and a knob that slides to the side currently showing. The icon
   under the knob inverts to white; the dimmed far icon is the other mode. */
.walk__chip--mode {
  width: 60px;
  justify-content: space-between;
  padding: 0 8px;
  border-radius: 999px;
}

.walk__switch-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--chip-fg);
  box-shadow: 0 1px 4px rgba(14, 1, 28, 0.35);
  transition: transform 240ms var(--ease-out-cubic);
}

.walk__band[data-img-mode='dark'] .walk__switch-knob { transform: translateX(28px); }

.walk__chip--mode .walk__chip-icon {
  position: relative;
  z-index: 1;
  display: block;
  width: 15px;
  height: 15px;
  opacity: 0.55;
  transition: opacity 240ms ease, color 240ms ease;
}

.walk__band[data-img-mode='light'] .walk__chip-icon--sun,
.walk__band[data-img-mode='dark'] .walk__chip-icon--moon {
  color: #ffffff;
  opacity: 1;
}

/* Chip tooltips: the gallery chips' dark pill, anchored to the row's
   left edge since these sit at the text column edge, not a stage corner */
.walk__chip[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  padding: 7px 10px;
  border-radius: 6px;
  background: var(--tooltip-bg);
  color: var(--tooltip-fg);
  font-family: var(--font-body);
  font-size: var(--fs-tag);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  box-shadow: var(--shadow-tooltip);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity 160ms ease, transform 160ms var(--ease-out-cubic);
}

@media (hover: hover) and (pointer: fine) {
  .walk__chip:hover::after,
  .walk__chip:focus-visible::after {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 300ms;
  }
}

/* Copy confirmation shows immediately on every device */
.walk__chip--link.is-copied::after {
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0ms;
}

/* Centered variant (Design System) */
.walk__band--center .walk__inner { align-items: center; }

.walk__band--center .walk__head {
  align-items: center;
  text-align: center;
  width: var(--panel-w);
}

.walk__band--center .walk__titleblock { align-items: center; }

/* The centered band (TSA) centers its chip row too, and centers each
   chip's tooltip so it doesn't hang off the row's left edge */
.walk__band--center .walk__chips { align-self: center; }
.walk__band--center .walk__chip[data-tooltip]::after {
  left: 50%;
  transform: translate(-50%, 4px);
}
.walk__band--center .walk__chip:hover::after,
.walk__band--center .walk__chip:focus-visible::after,
.walk__band--center .walk__chip--link.is-copied::after {
  transform: translate(-50%, 0);
}

/* The centered band's gallery + caption stay left-aligned to the hero edge */
.walk__band--center .gallery__caption { align-self: flex-start; }

/* Split variant (Digital Driver's License): copy left, two phones right.
   Figma: text 496 / gap 64 / phones 300 + 24 + 300, copy dropped 48px */
.walk__inner--split {
  flex-direction: row;
  align-items: flex-start;
  justify-content: space-between;
  gap: 64px;
}

/* Mirrored split (Vehicle Registration): phones left, copy right.
   DOM keeps copy first for reading order; row-reverse swaps the visual */
.walk__inner--flip { flex-direction: row-reverse; }

.walk__head--side {
  flex: 0 1 496px;
  min-width: 0;
  width: auto;
  padding-top: 48px;
}

.walk__duo {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  flex-shrink: 0;
}

.walk__phone {
  margin: 0;
  width: 300px;
  max-width: 100%;
}

.walk__phone img {
  display: block;
  width: 100%;
  height: auto;
  /* Design-system media shadow; drop-shadow (not box-shadow) so it
     hugs the phone silhouette's transparent rounded corners */
  filter: drop-shadow(var(--shadow-media));
}

/* Quad row (TSA Integration): four phones under a centered header.
   Figma: 4 × 269 with 36px gaps filling the 1184 row */
.walk__quad {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 36px;
  width: 100%;
}

/* Equal frames like the Figma: every cell is the 269:567 rect and the
   screenshot center-crops to fill it (Figma image-fill behavior) */
.walk__quad .walk__phone {
  width: 100%;
  aspect-ratio: 269 / 567;
  overflow: hidden;
  border-radius: 24px;
  /* The frame clips its img, so the shadow lives on the rounded figure;
     the img's silhouette drop-shadow would be clipped away anyway */
  box-shadow: var(--shadow-media);
}

.walk__quad .walk__phone img {
  height: 100%;
  object-fit: cover;
  filter: none;
}

/* ---- Synthesis — centered paragraph interlude -------------------------- */
.walk__micdrop {
  display: flex;
  justify-content: center;
  width: 100%;
  padding: var(--band-py) 24px;
  background: var(--band-plain);
}

.walk__micdrop p {
  margin: 0;
  width: var(--measure);
  max-width: 100%;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  text-align: center;
  color: var(--fg-body);
}

@media (max-width: 1023px) {
  .walk__head,
  .walk__band--center .walk__head { width: 100%; }
  .walk__inner--split { flex-direction: column; gap: 48px; }
  .walk__head--side { flex: none; padding-top: 0; }
  .walk__duo { flex-shrink: 1; }
  .walk__quad { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 30px; max-width: 640px; }
}

@media (max-width: 767px) {
  .walk__band { padding: var(--band-py) 16px; }
  .walk__micdrop { padding: var(--band-py) 16px; }
  .walk__phone { width: min(300px, calc(50% - 12px)); }
  .walk__quad { gap: 16px; }
  .walk__quad .walk__phone { width: 100%; }
}


/* ==========================================================================
   14. GALLERY — hero stage (left) + vertical thumb rail (right) + caption.
   Flex-basis ratios 954:206 reproduce the Figma 1184 row. Placeholders
   (gray + label) render until real screenshots land — the markup contract
   (.gallery__slide img) is unchanged, so images drop straight in.
   ========================================================================== */
.gallery {
  display: flex;
  flex-direction: column;
  gap: 48px;
  width: 100%;
}

.gallery__row {
  display: flex;
  align-items: stretch;
  gap: 24px;
  width: 100%;
}

.gallery__stage {
  position: relative;
  flex: 954 1 0;
  min-width: 0;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-media);
  overflow: hidden;
  background: var(--gal-surface);
  box-shadow: var(--shadow-media);
}

.gallery__slides { position: absolute; inset: 0; }

.gallery__slide {
  position: absolute;
  inset: 0;
  /* kill the UA figure margin — with inset:0 it would inset the image */
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--gal-surface);
  opacity: 0;
  visibility: hidden;
  transition: opacity 400ms var(--ease-out-cubic), visibility 0s linear 400ms;
}

.gallery__slide.is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity 400ms var(--ease-out-cubic);
}

.gallery__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Non-16:9 assets (e.g. portrait phone shots): letterbox, don't crop */
.gallery__slide--contain img { object-fit: contain; }

/* Placeholder (missing/errored image): gray + label */
.gallery__slide--ph img,
.gallery__slide.is-broken img { display: none; }

.gallery__ph-label {
  display: none;
  padding: 0 24px;
  font-family: var(--font-body);
  font-size: var(--fs-note);
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
  color: var(--fg-label);
}

.gallery__slide--ph,
.gallery__slide.is-broken { background: var(--gal-ph-bg); }

.gallery__slide--ph .gallery__ph-label,
.gallery__slide.is-broken .gallery__ph-label { display: block; }

/* ---- Stage chips: copy-link (left) + expand (right) -------------------- */
.gallery__expand,
.gallery__link {
  position: absolute;
  bottom: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: var(--chip-bg);
  color: var(--chip-fg);
  cursor: pointer;
  box-shadow: var(--shadow-chip);
  transition: background 200ms ease, transform 200ms var(--ease-out-cubic);
}

.gallery__expand { right: 12px; }
.gallery__link { right: 52px; } /* expand's 12px inset + 32px chip + 8px gap */

.gallery__expand:hover,
.gallery__expand:focus-visible,
.gallery__link:hover,
.gallery__link:focus-visible { background: var(--chip-bg-hover); }

.gallery__expand:hover,
.gallery__link:hover { transform: translateY(-1px); }

.gallery__expand svg,
.gallery__link svg { width: 16px; height: 16px; }

/* Chip tooltips: dark pill above the control */
.gallery__expand[data-tooltip]::after,
.gallery__link[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 10px);
  right: 0;
  padding: 7px 10px;
  border-radius: 6px;
  background: var(--tooltip-bg);
  color: var(--tooltip-fg);
  font-family: var(--font-body);
  font-size: var(--fs-tag);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  box-shadow: var(--shadow-tooltip);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity 160ms ease, transform 160ms var(--ease-out-cubic);
}

@media (hover: hover) and (pointer: fine) {
  .gallery__expand:hover::after,
  .gallery__expand:focus-visible::after,
  .gallery__link:hover::after,
  .gallery__link:focus-visible::after {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 300ms;
  }
}

/* Copy confirmation shows immediately on every device */
.gallery__link.is-copied::after {
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0ms;
}

/* ---- Thumb rail --------------------------------------------------------- */
.gallery__thumbs {
  display: flex;
  flex-direction: column;
  flex: 206 1 0;
  min-width: 0;
  gap: 24px;
}

.gallery__thumb {
  flex: 1 1 0;
  min-height: 0;
  padding: 0;
  border: 4px solid transparent;
  border-radius: var(--r-thumb);
  overflow: hidden;
  background: var(--gal-ph-bg);
  box-shadow: var(--shadow-thumb);
  cursor: pointer;
  opacity: 0.5;
  transition: opacity 200ms ease, border-color 200ms ease;
}

.gallery__thumb:hover,
.gallery__thumb:focus-visible { opacity: 1; }

.gallery__thumb.is-active {
  opacity: 1;
  border-color: var(--gal-ring);
}

.gallery__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.gallery__thumb.is-broken img { display: none; }

.gallery__thumb-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-family: var(--font-body);
  font-size: var(--fs-tag);
  font-weight: 600;
  color: var(--fg-label);
}

/* ---- Caption below the gallery, hero width ------------------------------ */
.gallery__caption {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: calc((954 / 1160) * (100% - 24px));
}

.gallery__caption-head {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-h4);
  font-weight: 600;
  line-height: var(--lh-h4);
  color: var(--fg);
}

.gallery__caption-body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--fg-body);
}

.gallery__caption-body[hidden] { display: none; }

/* ---- Gallery: tablet + mobile — rail becomes a strip below the hero ---- */
@media (max-width: 1023px) {
  .gallery__caption { width: 100%; }

  .gallery__row { flex-direction: column; gap: 24px; }

  .gallery__stage { flex: none; width: 100%; }

  .gallery__thumbs {
    flex: none;
    flex-direction: row;
    width: 100%;
    gap: 24px;
  }

  .gallery__thumb {
    flex: 1 1 0;
    aspect-ratio: 16 / 9;
  }
}

@media (max-width: 767px) {
  .gallery__stage { border-radius: 8px; }
  .gallery__thumbs { gap: 8px; }
  .gallery__thumb { border-width: 2px; border-radius: 4px; }
  .gallery__expand { display: none; } /* no lightbox; tap a thumb to switch */
  .gallery__link { right: 12px; }
}


/* ==========================================================================
   15. LIGHTBOX — fullscreen frosted overlay built by JS (appended to body,
   outside the shell). The stage + caption share a column so the caption
   tracks the image edge; the whole unit centers as one block.
   ========================================================================== */
.gallery-lightbox {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: none;
  padding: 0;
  background: transparent;
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  opacity: 0;
  transition: opacity 220ms ease;
}

.gallery-lightbox.is-open { display: flex; }
.gallery-lightbox.is-in { opacity: 1; }

.gallery-lightbox__panel {
  position: relative;
  width: 100%;
  height: 100%;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0;
  border-radius: 0;
  background: var(--lb-panel-bg);
  transform: scale(0.94) translateY(10px);
  opacity: 0;
  transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 220ms ease;
}

.gallery-lightbox.is-in .gallery-lightbox__panel {
  transform: none;
  opacity: 1;
}

.gallery-lightbox .gallery--lightbox {
  flex: 1;
  min-height: 0;
  gap: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.gallery-lightbox .gallery__row {
  flex: 0 0 auto;
  min-height: 0;
  width: 100%;
  gap: 24px;
  justify-content: center;
  align-items: flex-start;
}

.gallery-lightbox .gallery__stagecol {
  display: flex;
  flex-direction: column;
  gap: 16px;
  flex: 0 1 auto;
  min-width: 0;
  max-width: calc(100% - 230px); /* room for the 206px rail + gap */
}

.gallery-lightbox .gallery__stage {
  flex: 0 1 auto;
  height: calc(100dvh - 300px);
  aspect-ratio: 16 / 9; /* JS syncs to the active image */
  max-width: 100%;
  border-radius: 0;
  box-shadow: none;
  background: transparent;
}

.gallery-lightbox .gallery__slide { background: transparent; }
.gallery-lightbox .gallery__slide img { object-fit: contain; }

.gallery-lightbox .gallery__thumbs {
  flex: 0 0 206px;
  height: calc(100dvh - 300px);
  justify-content: center;
  gap: 16px;
  overflow: hidden;
  padding: 0;
}

/* Thumbs keep 16:9 but shrink to share the rail height when needed */
.gallery-lightbox .gallery__thumb {
  flex: 0 1 auto;
  min-height: 0;
  aspect-ratio: 16 / 9;
  width: 100%;
}

.gallery-lightbox .gallery__caption {
  flex: 0 0 auto;
  align-items: flex-start;
  text-align: left;
  /* width 0 + min-width 100% keeps long captions from inflating the
     column past the stage's aspect width */
  width: 0;
  min-width: 100%;
  padding: 0;
}

.gallery-lightbox__close {
  position: absolute;
  top: 32px;
  right: 32px;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: var(--gal-btn-bg);
  color: var(--gal-btn-fg);
  cursor: pointer;
  transition: background 200ms ease;
}

.gallery-lightbox__close:hover { background: var(--gal-btn-bg-hover); }
.gallery-lightbox__close svg { width: 18px; height: 18px; }

.gallery-lightbox .gallery__caption-head { color: var(--lb-fg); }
.gallery-lightbox .gallery__caption-body { color: var(--lb-body); }
.gallery-lightbox .gallery__ph-label,
.gallery-lightbox .gallery__thumb-ph { color: var(--lb-label); }
.gallery-lightbox .gallery__expand,
.gallery-lightbox .gallery__link { display: none; }

/* Lightbox at tablet/mobile: stacked — the stage column fills the height,
   the rail becomes a horizontal strip. These out-specify the base rules. */
@media (max-width: 1023px) {
  .gallery-lightbox .gallery__row {
    flex: 1 1 auto;
    gap: 16px;
    align-items: stretch;
    flex-direction: column;
  }

  .gallery-lightbox .gallery__stagecol {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    max-width: none;
  }

  .gallery-lightbox .gallery__stage {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    height: auto;
    max-width: none;
  }

  .gallery-lightbox .gallery__caption { padding: 0 16px; }

  .gallery-lightbox .gallery__thumbs {
    flex: 0 0 auto;
    flex-direction: row;
    height: auto;
    justify-content: flex-start;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 0 16px 12px;
  }

  .gallery-lightbox .gallery__thumb { flex: 0 0 148px; width: auto; }
}


/* ==========================================================================
   16. RESULTS — centered heading, 3-up stat cards, 2-up testimonial cards
   ========================================================================== */
.case-results { gap: 48px; }

.case-results__heading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap-headline);
  width: 100%;
  text-align: center;
}

.case-results__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap-text);
  width: 100%;
}

.case-results__desc {
  width: var(--measure);
  max-width: 100%;
}

.case-results__stats {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
  width: 100%;
}

.rstat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 20px;
  border-radius: var(--r-card);
  background: var(--surface);
  border: 1px solid var(--border);
}

.rstat__icon {
  display: flex;
  color: var(--icon-results);
}

.rstat__icon svg { width: 26px; height: 26px; }

.rstat__value {
  margin: 0;
  font-size: var(--fs-h4);
  font-weight: 600;
  line-height: var(--lh-h4);
  color: var(--primary); /* purple light / amber dark */
}

.rstat__desc {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--fg);
}

/* Supporting line under a stat desc. Uses the AA-corrected label token,
   which clears contrast at this size in both themes. */
.rstat__note {
  margin: 4px 0 0;
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--fg-label);
}

/* Stat grid + its source footnote travel as one flex child so the
   footnote hangs 16px under the cards instead of picking up the
   section's 48px gap. Same .results-source rule as the shared
   case-study.css (this page is self-contained). */
.case-results__statgroup { width: 100%; }

/* Source footnote: 13px quiet line under the stat grid. Light holds the
   body token at 85% to clear AA (4.8:1 on #fbfafd); dark can sit at 65%
   (6.3:1 on #0e011c) — the subtle/label tokens fail AA at this size. */
.results-source {
  margin: 16px 0 0;
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.4;
  text-align: left;
  color: color-mix(in srgb, var(--fg-body) 85%, transparent);
}

:root[data-theme='dark'] .results-source {
  color: color-mix(in srgb, var(--fg-body) 65%, transparent);
}

.case-results__quotes {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  width: 100%;
}

.quote {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: var(--card-pad);
  border-radius: var(--r-card);
  background: var(--surface);
  border: 1px solid var(--border);
}

/* Dark testimonial cards carry no border (their fill is the surface) */
:root[data-theme='dark'] .quote { border-color: transparent; }
:root[data-theme='dark'] .quote,
:root[data-theme='dark'] .rstat { background: #3d3350; }
:root[data-theme='dark'] .rstat { border-color: #3d3350; }

.quote__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  color: var(--icon-results);
}

.quote__icon svg { width: 32px; height: 32px; }

.quote__text {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--fg);
}

:root[data-theme='dark'] .quote__text { color: var(--fg-body); }

.quote__who {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.quote__name {
  margin: 0;
  font-size: var(--fs-label);
  font-weight: 600;
  line-height: normal;
  letter-spacing: var(--ls-quote-name);
  color: var(--fg);
}

:root[data-theme='dark'] .quote__name { color: var(--fg-body); }

.quote__role {
  margin: 0;
  font-size: var(--fs-tag);
  font-weight: 500;
  line-height: 1.5;
  color: var(--fg-label);
}

@media (max-width: 1023px) {
  .case-results__quotes { grid-template-columns: 1fr; }
  .case-results__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 767px) {
  .case-results__stats { grid-template-columns: 1fr; }
  .case-results__desc { width: 100%; }
}


/* ==========================================================================
   17. REFLECTION — 900px centered card, centered text column
   ========================================================================== */
.case-reflection {
  align-items: center;
  text-align: center;
  gap: var(--gap-headline);
  padding: 48px;
  border-radius: var(--r-big);
  background: var(--panel-reflect);
  border: 1px solid var(--border);
  width: var(--panel-w);
  max-width: 100%;
  align-self: center;
}

.case-reflection .case-headline { width: 100%; }

.case-reflection__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap-text);
  width: 100%;
}

.case-reflection__text {
  display: flex;
  flex-direction: column;
  gap: 24px;
  width: 804px;
  max-width: 100%;
}

@media (max-width: 1023px) {
  .case-reflection { padding: 48px 24px; }
}

@media (max-width: 767px) {
  .case-reflection {
    align-items: flex-start;
    text-align: left;
    padding: 16px;
  }

  /* the body's align-items:center still centered the subhead (a shrink-to-fit
     flex item) inside the otherwise left-aligned card */
  .case-reflection__body { align-items: flex-start; }
}


/* ==========================================================================
   18. EXPLORE MORE — full-bleed band, last section of the shell. Rounded
   bottom corners in light mode close the white card; the .xm-wrap backing
   paints the footer color behind the corner wedges.
   ========================================================================== */
.xm-wrap {
  width: 100%;
  background: var(--frame);
}

.xm {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  padding: var(--band-py) 24px;
  background: var(--xm-band);
}

:root[data-theme='light'] .xm { border-radius: 0 0 var(--r-shell) var(--r-shell); }

.xm__inner {
  width: var(--content-w);
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 48px;
}

.xm__title { width: 100%; }

.xm__cards {
  display: flex;
  gap: 48px;
  width: 100%;
}

/* The whole card is a single anchor */
.xm-card {
  flex: 1;
  min-width: 0;
  height: 600px;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  border-radius: var(--r-big);
  box-shadow: var(--shadow-xm-card);
  transition: transform 250ms var(--ease-out), box-shadow 250ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .xm-card:hover,
  .xm-card:focus-visible {
    transform: translateY(-4px);
    box-shadow: var(--shadow-xm-card-hover);
  }
}

.xm-card__media {
  display: block;
  flex: 1;
  min-height: 0;
  border-radius: var(--r-big) var(--r-big) 0 0;
  overflow: hidden;
  position: relative; /* carousel slides stack inside */
}

.xm-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Card carousel — the same stacked crossfade the homepage case cards use.
   Every slide is absolute, so the media box keeps its own flex height and
   the card footprint is unchanged. JS times .is-active (la-wallet.js §6). */
.cs-carousel img {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1000ms ease;
}

.cs-carousel img.is-active { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  /* JS never rotates slides; the first stays visible with no fade */
  .cs-carousel img { transition: none; }
}

.xm-card__meta {
  /* 194px in the Figma node; min-height (not height) so a wrapping title
     or stat list grows the panel instead of spilling over the image */
  min-height: 194px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 12px;
  padding: 20px;
  border-radius: 0 0 var(--r-big) var(--r-big);
  background: var(--surface);
}

.xm-card__id {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.xm-card__client {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--xm-client);
}

.xm-card__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-headline);
  line-height: var(--lh-headline);
  letter-spacing: var(--ls-headline);
  color: var(--fg);
}

.xm-card__stats {
  margin: 0;
  padding-left: 20px;
  list-style: disc;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 24px;
  color: var(--xm-stat);
}

.xm-card__stats li::marker { color: var(--xm-marker); }

@media (max-width: 1023px) {
  .xm__cards { flex-direction: column; }
  .xm-card { flex: none; width: 100%; }
}

@media (max-width: 767px) {
  .xm { padding: 48px 16px; } /* 16px mobile gutter, sitewide */

  /* Explore cards match the homepage cs-card mobile treatment: the fixed
     600px desktop height goes content-driven — a 16/10 image on top (same
     ratio as the homepage cards) with the details growing below it */
  .xm-card { height: auto; }
  .xm-card__media { flex: none; aspect-ratio: 16 / 10; }
  .xm-card__meta { min-height: 0; }
}

/* --- Mobile type, the bits the tokens don't reach ---------------------------
   The scale itself is retuned on the :root tokens in BASE (section 2). These
   are the few places that hardcode a size or need to sit off the shared step,
   kept in sync with the same rules in assets/css/case-study.css. */
@media (max-width: 767px) {
  /* Stat values share --fs-h4 with the caption heads on desktop, but a "1st"
     or "94%" is the loudest thing in the Results band and shouldn't drop to
     caption size — held one step above */
  .rstat__value { font-size: 1.5rem; }

  /* Problem titles are on --fs-body, so they tracked the body all the way
     down and a card's heading read as part of its own paragraph */
  .problem__title {
    font-size: 1.0625rem;
    line-height: 1.35;
  }

  /* Hardcoded 1.0625rem/24px rather than tokens (sections 8 and 18) */
  .csp-hero__stats li,
  .xm-card__stats li {
    font-size: 0.9375rem;
    line-height: 1.5;
  }
}

/* Phone-width explore cards (~480 down): the mobile sizes read oversized, so
   the whole scale steps down proportionally — same convention as the
   homepage .cs-card block in styles.css */
@media (max-width: 480px) {
  .xm-card__meta { padding: 16px; gap: 10px; }
  .xm-card__name { font-size: 1.625rem; }
  .xm-card__client { font-size: 0.9375rem; }
  .xm-card__stats { font-size: 0.875rem; line-height: 1.35; }

  /* Headings take one more notch on small phones; body copy holds at
     16.4px, the sitewide prose floor */
  .case-headline,
  .walk__headline { font-size: 1.5rem; }

  .case-subheading { font-size: 1.0625rem; }

  .gallery__caption-head { font-size: 1.1875rem; }

  .rstat__value { font-size: 1.375rem; }
}


/* ==========================================================================
   19. CONTACT FOOTER — always dark, in both themes
   ========================================================================== */
.contact {
  position: relative; /* paints above the sticky hero */
  padding: 72px 48px;
  background: var(--footer-bg);
  scroll-margin-top: var(--nav-height);
}

.contact-inner {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
}

.contact__logo-link {
  display: block;
  line-height: 0;
  margin-bottom: 24px;
}

.contact__logo { width: 53px; height: 64px; }

.contact__eyebrow {
  margin: 0;
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 1.56px;
  text-transform: uppercase;
  color: var(--footer-amber);
}

.contact__headline {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.875rem, 4vw, 2.75rem);
  line-height: 1.08;
  letter-spacing: 0.8px;
  color: var(--footer-fg);
}

.contact__desc {
  margin: -8px 0 0;
  max-width: 720px;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--footer-muted);
  orphans: 2;
  widows: 2;
  text-wrap: pretty;
}

.contact-email {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  width: 300px;
  max-width: 100%;
  margin-top: 24px;
  padding: 0 12px;
  border: 2px solid var(--footer-primary);
  border-radius: 4px;
  background: var(--footer-input-bg);
}

.contact-email input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--footer-fg);
  font-family: var(--font-body);
  font-size: 1rem;
  outline: none;
}

.contact-email__copy {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border: 0;
  background: transparent;
  color: var(--footer-fg);
  transition: color 200ms ease;
}

.contact-email__copy:hover { color: var(--footer-amber); }

.contact-email__copy svg { width: 18px; height: 18px; }

.contact-email__toast {
  position: absolute;
  top: -38px;
  left: 50%;
  transform: translateX(-50%) translateY(6px);
  padding: 4px 12px;
  border-radius: 6px;
  background: var(--footer-amber);
  color: #1e0c32;
  font-size: var(--fs-label);
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease, transform 200ms ease;
}

.contact-email__toast.is-shown {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Email group (Dave 2026-09-08): copy box + separate "Email Dave" mailto
   button; mirrors assets/css/styles.css (this page is standalone) */
.contact-email-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 24px;
  max-width: 100%;
}

.contact-email-group .contact-email { margin-top: 0; }

/* .btn is declared later in this file, so the class pair outranks its
   180px min-width (the shared stylesheet declares .btn first) */
.btn.contact-email__mail {
  gap: 8px;
  min-width: 0;
  padding: 0 20px;
}

.contact-email__mail svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.contact-email__copy { position: relative; }

.contact-email__copy[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  right: -4px;
  padding: 7px 10px;
  border-radius: 6px;
  background: var(--tooltip-bg);
  color: var(--tooltip-fg);
  font-family: var(--font-body);
  font-size: var(--fs-tag);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  box-shadow: var(--shadow-tooltip);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity 160ms ease, transform 160ms var(--ease-out-cubic);
}

@media (hover: hover) and (pointer: fine) {
  .contact-email__copy:hover::after {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 300ms;
  }
}

.contact-email__copy:focus-visible::after {
  opacity: 1;
  transform: translateY(0);
}

.contact-email.is-copied .contact-email__copy::after { opacity: 0; }

.contact__note {
  margin: 16px 0 0;
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--footer-muted);
}

.contact-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 24px;
  margin-top: 16px;
}

.contact-social {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: var(--footer-primary);
  color: #ffffff;
  transition: transform 200ms var(--ease-out), background 200ms ease;
}

.contact-social:hover {
  transform: scale(1.05);
  background: var(--primary-hover);
}

.contact-social svg { width: 20px; height: 20px; }

/* Footer hierarchy (Dave 2026-09-08): Email Dave is the one primary button;
   the social circles and Download Resume are ghost buttons (muted white
   stroke, bright white icon/text). Mirrors assets/css/styles.css. */
.contact .contact-social {
  border: 1px solid rgba(255, 255, 255, 0.5);
  background: transparent;
  color: var(--footer-fg);
  transition: transform 200ms var(--ease-out), border-color 250ms ease;
}

.contact .contact-social:hover,
.contact .contact-social:focus-visible {
  background: transparent;
  border-color: var(--footer-fg);
}

.contact__copyright {
  margin: 32px 0 0;
  font-size: var(--fs-tag);
  font-weight: 500;
  line-height: 1.5;
  color: var(--footer-muted);
}

/* ---- Buttons (footer CTA) --------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  min-width: 180px;
  padding: 0 24px;
  border-radius: 8px;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  text-decoration: none;
  transition: background 250ms ease, border-color 250ms ease, transform 250ms var(--ease-out);
}

.btn:hover { transform: translateY(-2px); }

.btn--primary {
  background: var(--footer-primary);
  color: #ffffff;
}

.btn--primary:hover { background: var(--primary-hover); }

.btn--ghost {
  border: 1px solid rgba(255, 255, 255, 0.5);
  color: var(--footer-fg);
}

.btn--ghost:hover { border-color: var(--footer-fg); }

@media (max-width: 767px) {
  .contact { padding: 72px 16px; }
  .contact__desc { font-size: 1.0625rem; }
  .contact-email { width: 100%; }
  .contact-email-group {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }
  .contact-email__mail { width: 100%; }
  /* Column direction turns the panel box's 220px flex-basis into a height,
     so reset it here (it stretched to 440px tall on phones, 2026-09-08) */
  .mobile-menu--panel.mobile-menu--contact .contact-email-group .contact-email { flex: 0 0 auto; } /* extra class: the panel rules sit later in this file */
  .contact-actions .btn { width: 100%; }

  /* This page is standalone, so the shared footer's mobile sizes in
     assets/css/styles.css never reach it — without this the headline sat a
     step larger here (32.8px) than on every other page */
  .contact__headline { font-size: 1.75rem; }
}

@media (max-width: 480px) {
  .contact__headline { font-size: 1.625rem; }
  .contact__desc { font-size: 1rem; }
}


/* ==========================================================================
   20. COPYRIGHT TIP — right-click guard tooltip near the cursor
   ========================================================================== */
.copyright-tip {
  position: fixed;
  z-index: 600; /* above the lightbox (500) */
  max-width: 320px;
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid rgba(130, 0, 255, 0.55);
  background: rgba(30, 12, 50, 0.92);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: #ffffff;
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 600;
  line-height: 1.45;
  box-shadow: 0 12px 32px rgba(14, 1, 28, 0.35);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 250ms ease, transform 250ms ease;
}

.copyright-tip.is-shown {
  opacity: 1;
  transform: translateY(0);
}


/* ==========================================================================
   21. REDUCED MOTION
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  body::after { display: none; }

  .cascade {
    animation: none;
    opacity: 1;
    transform: none;
  }

  [data-cascade] {
    transition: none;
    opacity: 1;
    transform: none;
  }

  .csp-hero--fade {
    animation: none;
    opacity: 1;
  }

  .csp-hero__img--slide { transition: none; }

  .pagenav,
  .pagenav__bar,
  .pagenav__btn,
  .pagenav__home { transition: none; }

  .pagenav--enter .pagenav__bar,
  .pagenav--enter .pagenav__home,
  .pagenav--enter .pagenav__btn {
    animation: none;
    opacity: 1;
  }

  .site-nav,
  .nav-link,
  .nav-link--contact,
  .nav-link__text,
  .mobile-menu,
  .mobile-menu__item,
  .mobile-menu__link,
  .mobile-menu__sub,
  .mobile-menu__chevron,
  .nav-toggle__bar,
  .theme-toggle { transition: none; }

  .gallery__slide,
  .gallery__slide.is-active,
  .gallery__expand,
  .gallery-lightbox,
  .gallery-lightbox__panel { transition: none; }

  .walk__chip { transition: none; }
  .walk__chip:hover { transform: none; }
  .walk__switch-knob { transition: none; }
  .walk__chip--mode .walk__chip-icon { transition: none; }


  .copyright-tip { transition: opacity 200ms ease; transform: none; }
}


/* ==========================================================================
   Mobile reads left-aligned: every centered text block flushes left on
   phones; only the contact footer stays centered. At the end of the file
   so source order beats each base rule. (Mirrors case-study.css.)
   ========================================================================== */
@media (max-width: 767px) {
  .problem__header,
  .case-results__heading,
  .case-results__intro {
    align-items: flex-start;
    text-align: left;
  }

  .walk__band--center .walk__inner { align-items: flex-start; }
  .walk__band--center .walk__head {
    align-items: flex-start;
    text-align: left;
  }

  .walk__micdrop p { text-align: left; }
}

/* Privacy policy link on the copyright line (mirrors styles.css) */
.contact__legal {
  margin-left: 8px;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 200ms ease;
}

.contact__legal:hover,
.contact__legal:focus-visible { color: var(--primary-bright); }

/* ==========================================================================
   Site header + slide-out panels, ported from assets/css/styles.css (Dave
   2026-09-07). Same rules as the homepage with this file's tokens: --fg,
   --nav-fg-on-light, --primary-bright, --surface, --band-tint, --border.
   Breakpoints follow this file (1023 / 767, not 1024 / 640).
   ========================================================================== */

/* --- Homepage header: logo, Contact, Menu (Figma 801:716, Dave 2026-09-07)
   .site-nav--menu scopes the layout to the homepage; the inner pages keep
   the links + theme toggle header above. Two 44px buttons, 8px radius,
   16px apart (--button-gap), 17px semibold white, 16px side padding, each
   as wide as its label. Contact: 10% plum glass, 50% white stroke, 8px
   blur. Menu: solid neutral-900 (Dave 2026-09-07, was the frame's
   violet-700), hamburger before the label. Phones drop
   Contact and the label and keep the violet icon button (the <=640
   block). Gutters tighten so the logo and the pair sit nearer the edges. */
.site-nav--menu .site-nav__inner { padding: 0 24px; }

/* The pair's frame: the logo tile's frosted glass (same fill, stroke,
   blur and a concentric 16px radius). One 8px measure everywhere inside
   it: between the two buttons and on all four sides (Dave 2026-09-07:
   "equally padded"; this pair no longer shares --button-gap with the hero
   CTAs). The frame is on everywhere, heroes included (Dave 2026-09-07:
   one nav system); only its tint, stroke and foreground flip with the
   backdrop via .on-light. The padding is pulled back with a negative
   margin so the buttons sit where they did without it. */
.site-nav--menu .site-nav__actions,
.site-nav--menu.on-light .site-nav__actions {
  gap: 8px;
  margin: -8px;
  padding: 8px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 16px;
  background: rgba(30, 12, 50, 0.35);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
}

.site-nav--menu.on-light .site-nav__actions {
  background: rgba(255, 255, 255, 0.55);
  border-color: rgba(30, 12, 50, 0.1);
}

body.menu-open .site-nav--menu .site-nav__actions {
  border-color: transparent;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.site-nav--menu .nav-link--contact,
.site-nav--menu .nav-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 16px;
  border: 0;
  border-radius: 8px;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  color: #ffffff;
  transition: border-color 300ms ease, color 300ms ease, background 300ms ease,
    padding 250ms var(--ease-out), gap 250ms var(--ease-out), transform 250ms var(--ease-out);
}

.site-nav--menu .nav-link--contact {
  border: 1px solid rgba(255, 255, 255, 0.3); /* a quiet stroke (Dave 2026-09-07; was 0.5), full white on hover */
  background: transparent; /* the frame carries the glass (Dave 2026-09-07) */
}

.site-nav--menu .nav-toggle {
  flex-direction: row;
  gap: 12px;
  width: auto;
  border: 1px solid rgba(255, 255, 255, 0.3); /* the same stroke as Contact over dark backdrops (Dave 2026-09-07) */
  background: #1e0c32;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

/* Hover: labels roll up like the nav links (same mask markup) and the
   label + bars change colour; the stroke and fill stay EXACTLY as at rest
   in every state (Dave 2026-09-07). These rules pin the rest values so the
   generic .nav-link--contact:hover stroke brighten never applies here. */
.site-nav--menu .nav-link--contact:hover { border-color: rgba(255, 255, 255, 0.3); }

.site-nav--menu .nav-toggle:hover,
.site-nav--menu .nav-toggle:focus-visible {
  border-color: rgba(255, 255, 255, 0.3);
  background: #1e0c32;
}

.site-nav--menu .nav-toggle .nav-link__text--hover { color: var(--amber); }

/* The hamburger bars go amber with the label (Dave 2026-09-07); the X in
   the open state keeps its own colour */
.site-nav--menu .nav-toggle:hover .nav-toggle__bar,
.site-nav--menu .nav-toggle:focus-visible .nav-toggle__bar { background: var(--amber); }

/* Over light backdrops the rollover matches Contact's: label and bars in
   the same purple Contact's text rolls to (Dave 2026-09-07) */
.site-nav--menu.on-light .nav-toggle .nav-link__text--hover { color: var(--primary-bright); }
.site-nav--menu.on-light .nav-toggle:hover .nav-toggle__bar,
.site-nav--menu.on-light .nav-toggle:focus-visible .nav-toggle__bar { background: var(--primary-bright); }

.site-nav--menu .nav-toggle.is-open:hover .nav-toggle__bar,
.site-nav--menu .nav-toggle.is-open:focus-visible .nav-toggle__bar { background: #ffffff; }

:root[data-theme='light'] .site-nav--menu .nav-toggle.is-open:hover .nav-toggle__bar,
:root[data-theme='light'] .site-nav--menu .nav-toggle.is-open:focus-visible .nav-toggle__bar { background: var(--nav-fg-on-light); }

.site-nav--menu .nav-toggle:hover .nav-link__text,
.site-nav--menu .nav-toggle:focus-visible .nav-link__text { transform: translateY(-100%); }

.site-nav--menu .nav-link--contact:focus-visible,
.site-nav--menu .nav-toggle:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}

/* Must follow the .on-light block above (same specificity, source order).
   Over light backdrops the pair flips together (Dave 2026-09-07): Menu
   becomes a white button with the dark plum label and bars, Contact reads
   dark. Over dark backdrops Menu keeps its neutral-900 fill and white. */
.site-nav--menu.on-light .nav-toggle {
  border: 1px solid rgba(30, 12, 50, 0.25); /* the same stroke as Contact over light backdrops (Dave 2026-09-07) */
  background: #edeaf1; /* neutral/100 (Dave 2026-09-07; mirrors styles.css) */
  color: var(--nav-fg-on-light);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.site-nav--menu.on-light .nav-toggle:hover,
.site-nav--menu.on-light .nav-toggle:focus-visible {
  border-color: rgba(30, 12, 50, 0.25);
  background: #edeaf1; /* unchanged on hover (Dave 2026-09-07) */
}

.site-nav--menu.on-light .nav-link--contact {
  border-color: rgba(30, 12, 50, 0.25); /* quiet over light backdrops too (was 0.5) */
  color: var(--nav-fg-on-light);
}

.site-nav--menu.on-light .nav-link--contact:hover { border-color: rgba(30, 12, 50, 0.25); } /* stroke stays put on hover (Dave 2026-09-07) */

/* Hamburger beside the label: 18px bars, 4px apart (so the open-state X
   below folds the outer bars 6px to the centre, not the 9px of the 26px
   disc version) */
.nav-toggle__bars {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.site-nav--menu .nav-toggle__bar { width: 18px; }

.site-nav--menu .nav-toggle.is-open .nav-toggle__bar:nth-child(1) { translate: 0 6px; }
.site-nav--menu .nav-toggle.is-open .nav-toggle__bar:nth-child(3) { translate: 0 -6px; }

/* The label collapses (max-width, not display) so it can tween away */
.nav-toggle__label {
  display: block;
  max-width: 80px;
  overflow: hidden;
  transition: max-width 250ms var(--ease-out), opacity 150ms ease;
}

/* Panel open (Dave 2026-09-07): Contact fades and is hidden (it lives in
   the panel meanwhile), Menu slides left to the panel's padding edge
   (main.js measures the distance into --nav-shift) and its label folds
   away so only the bars remain, already crossed into the X by the rules
   above.
   Every step is a transition, so closing plays the same thing backwards;
   the reduced-motion block at the end of the file zeroes them. */
body.menu-open .site-nav--menu .nav-link--contact {
  opacity: 0;
  visibility: hidden;
  transition: opacity 150ms ease, visibility 0s linear 150ms;
}

body.menu-open .site-nav--menu .nav-toggle {
  gap: 0;
  padding: 0 12px; /* 18px bars + 24 + 2px stroke = the 44px square */
  border: 1px solid rgba(255, 255, 255, 0.3); /* ghost X, no fill, a light stroke (Dave 2026-09-07) */
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  transform: translateX(calc(-1 * var(--nav-shift, 0px)));
}

body.menu-open .site-nav--menu .nav-toggle:hover,
body.menu-open .site-nav--menu .nav-toggle:focus-visible {
  border-color: rgba(255, 255, 255, 0.3);
  background: transparent;
}

/* Over the white light-mode panel the ghost X goes dark */
:root[data-theme='light'] body.menu-open .site-nav--menu .nav-toggle {
  border-color: rgba(30, 12, 50, 0.25);
  color: var(--nav-fg-on-light);
}

:root[data-theme='light'] body.menu-open .site-nav--menu .nav-toggle:hover,
:root[data-theme='light'] body.menu-open .site-nav--menu .nav-toggle:focus-visible { border-color: rgba(30, 12, 50, 0.25); }

body.menu-open .site-nav--menu .nav-toggle__label {
  max-width: 0;
  opacity: 0;
}

.site-nav--menu.on-light .nav-toggle__bar { background: var(--nav-fg-on-light); } /* the white Menu button carries dark bars over light backdrops */
/* The homepage X is a ghost button over the panel: dark bars on the white
   light-mode panel, white on the dark one */
:root[data-theme='light'] .site-nav--menu .nav-toggle.is-open .nav-toggle__bar { background: var(--nav-fg-on-light); }

/* --- Slide-out panel (homepage, Dave 2026-09-07) -------------------------
   Right-side panel at every width; the page stays visible behind a dim
   overlay. Items stack left-aligned and slide in from the right; the
   destinations sit at the top and the theme switch in its own divided
   group at the bottom. The nav (z 100) rides over the panel (z 90), so
   the panel pads down past it. */
.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 85;
  background: rgba(14, 1, 28, 0.55);
  opacity: 0;
  visibility: hidden;
  transition: opacity 450ms ease, visibility 0s linear 450ms;
}

.menu-overlay.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 450ms ease, visibility 0s;
}

.mobile-menu--panel {
  inset: 0 0 0 auto;
  width: min(560px, calc(100% - 48px)); /* both panels share this width (Dave 2026-09-07; was 460) */
  flex-direction: column;
  transform: translateX(100%);
  box-shadow: -24px 0 48px rgba(14, 1, 28, 0.35);
  transition: transform 450ms var(--ease-out), visibility 0s linear 450ms;
}

/* The slide-down menu's status-bar bleed (::before, 120px past the top
   and bottom) is pointless on the side panel and, being absolutely
   positioned inside a scroll container, it added 120px of phantom scroll
   even when the content fit. Off here, so the panels only scroll when
   their content really is taller than the viewport (Dave 2026-09-07). */
.mobile-menu--panel::before { content: none; }

.mobile-menu--panel.is-open {
  transform: translateX(0);
  transition: transform 450ms var(--ease-out), visibility 0s;
}

/* Title row: fills the nav-height band, so "Menu" sits on the X's line
   (the X is the header's button, riding over the panel at the panel's
   32px padding edge). The panel's headline: display face at the h3 step
   the modal titles use (Dave 2026-09-07: serif for headlines only, never
   for navigation items). Shared by the menu and contact panels. */
.mobile-menu__head {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  box-sizing: border-box;
  width: 100%;
  height: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
  padding: env(safe-area-inset-top, 0px) 32px 0;
}

.mobile-menu__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.625rem;
  line-height: 1; /* tight box, so its centre is the glyphs' centre, on the X's line */
  color: var(--fg);
}

.mobile-menu--panel .mobile-menu__nav {
  align-items: flex-start;
  gap: 0;
  margin: 0;
  padding: 12px 32px 32px;
  --menu-gutter: 32px; /* where the active bar sits (16px on phones) */
}

/* Each item is a 14px-padded row with a light hairline between rows
   (Dave 2026-09-07: dividers in place of the open 28px gaps) */
.mobile-menu--panel .mobile-menu__nav > .mobile-menu__item {
  padding: 0; /* the row link carries the 14px (Dave 2026-09-07: the hover tint fills the row) */
  border-top: 1px solid var(--border);
}

.mobile-menu--panel .mobile-menu__nav > .mobile-menu__item:first-child { border-top: 0; }

.mobile-menu--panel .mobile-menu__item {
  align-items: flex-start;
  transform: translateX(24px);
}

.mobile-menu--panel.is-open .mobile-menu__item { transform: translateX(0); }

/* Navigation items in the body face, 1.25rem regular (Dave 2026-09-07:
   down from the 1.625rem/600 tile-title step; the full-screen menu on the
   inner pages keeps its serif items) */
.mobile-menu--panel .mobile-menu__link {
  font-family: var(--font-body);
  position: relative; /* anchors the active bar */
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0;
}

/* The active weight has to outrank the 400 above (same specificity, later source) */
.mobile-menu--panel .mobile-menu__link.is-active { font-weight: 600; }

/* Accordion rows fill the panel width: label left, chevron at the right edge */
.mobile-menu--panel .mobile-menu__row {
  width: 100%;
  justify-content: space-between;
}

.mobile-menu--panel .mobile-menu__expand {
  position: static;
  /* The 44px target hangs 9px above and below the 26px label line, so
     accordion rows stand as tall as the plain rows */
  margin: -9px -10px -9px 0;
}

/* Children of an accordion row (Dave 2026-09-07): indented one 16px
   step (12px on phones) and one weight step lighter than the parent
   row's 400, so they read as nested. "All ..." keeps a step over its
   siblings at 400. Hanken Grotesk 300 is requested in the font link for
   this. The indent is padding on the list, so every target keeps its
   full height. */
.mobile-menu--panel .mobile-menu__sub-inner {
  align-items: flex-start;
  --menu-indent: 16px;
  padding-left: var(--menu-indent);
}

.mobile-menu--panel .mobile-menu__sublink {
  padding: 0;
  text-align: left;
  font-weight: 300;
}

.mobile-menu--panel .mobile-menu__sublink--all { font-weight: 400; }

.mobile-menu--panel .mobile-menu__sublink.is-soon { justify-content: flex-start; }

/* Row hover / press (Dave 2026-09-07): every row, accordion parents and
   the children inside them included, tints edge to edge in the panel so
   it reads as one target. --menu-hover-bg is the interactive colour as a
   tint (violet/50 in light, the amber at 14% in dark); the label colour
   is untouched. Rows bleed into the gutters with negative margins and
   matching padding, so the 44px targets and the text edge stay where
   they are. The active bar (left: 0 now that the box starts at the
   panel edge) paints above the tint, so hover never erases it. */
.mobile-menu--panel .mobile-menu__link {
  display: flex;
  align-items: center;
  box-sizing: border-box;
  width: calc(100% + 2 * var(--menu-gutter, 32px));
  padding-top: 14px;
  padding-bottom: 14px;
  margin-left: calc(-1 * var(--menu-gutter, 32px));
  margin-right: calc(-1 * var(--menu-gutter, 32px));
  padding-left: var(--menu-gutter, 32px);
  padding-right: var(--menu-gutter, 32px);
  transition: color 200ms ease, background-color 200ms ease;
}

.mobile-menu--panel .mobile-menu__sub {
  width: calc(100% + 2 * var(--menu-gutter, 32px));
  margin: 0 calc(-1 * var(--menu-gutter, 32px));
}

.mobile-menu--panel .mobile-menu__sub-inner {
  padding-left: calc(var(--menu-gutter, 32px) + var(--menu-indent, 16px));
  padding-right: var(--menu-gutter, 32px);
}

.mobile-menu--panel .mobile-menu__sublink {
  display: flex;
  box-sizing: border-box;
  width: calc(100% + 2 * var(--menu-gutter, 32px) + var(--menu-indent, 16px));
  margin-left: calc(-1 * (var(--menu-gutter, 32px) + var(--menu-indent, 16px)));
  margin-right: calc(-1 * var(--menu-gutter, 32px));
  padding-left: calc(var(--menu-gutter, 32px) + var(--menu-indent, 16px));
  padding-right: var(--menu-gutter, 32px);
  transition: color 200ms ease, background-color 200ms ease;
}

.mobile-menu--panel .mobile-menu__link:hover,
.mobile-menu--panel .mobile-menu__link:active,
.mobile-menu--panel .mobile-menu__sublink:hover,
.mobile-menu--panel .mobile-menu__sublink:active { background-color: var(--menu-hover-bg); }

.mobile-menu--panel .mobile-menu__link::before { left: 0; }

.mobile-menu--panel button.mobile-menu__row:focus-visible {
  outline-offset: -2px;
  border-radius: 0;
}

/* Same ring on the link rows and children (the browser default showed
   through on the first-focused Home row) */
.mobile-menu--panel a.mobile-menu__link:focus-visible,
.mobile-menu--panel .mobile-menu__sublink:focus-visible {
  outline: 2px solid var(--primary-bright);
  outline-offset: -2px;
}

/* Contact panel (Dave 2026-09-07): the footer block, left-aligned. The
   footer centres everything and pins dark tokens; here the theme tokens
   apply, so the panel matches the menu panel in both modes. Multi-line
   copy balances at a text-relative measure, like the hero copy. */
.mobile-menu__contact-body {
  align-items: stretch;
  box-sizing: border-box;
  width: 100%;
  --menu-gutter: 32px; /* the rows below bleed into it (16px on phones) */
  padding: 24px 32px calc(32px + env(safe-area-inset-bottom, 0px)); /* the title row above carries the nav-height band */
}

.mobile-menu--contact .contact-inner {
  max-width: none;
  margin: 0;
  align-items: flex-start;
  text-align: left;
}

.mobile-menu--contact .contact__headline {
  max-width: 20ch;
  text-wrap: balance;
}

.mobile-menu--contact .contact__desc,
.mobile-menu--contact .contact__note {
  max-width: none; /* full content width, the panel's 32px either side (Dave 2026-09-07) */
  text-wrap: balance;
}

/* Regular weight for the availability line in the panel (Dave 2026-09-07; the footer copy keeps its 600) */
.mobile-menu--contact .contact__note { font-weight: 400; }

.mobile-menu--contact .contact-email { width: 100%; }

.mobile-menu--contact .contact-actions {
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 0;
  width: 100%;
}

/* Link rows (LinkedIn, Behance, Instagram, Download Resume): the purple
   disc keeps the icon, the label sits beside it in the body face, and a
   light hairline divides the rows (Dave 2026-09-07). Scoped to the panel
   so it outranks the footer's .contact-social circle, which is declared
   later in the file. */
.mobile-menu--contact .contact-social--row {
  width: auto;
  height: auto;
  justify-content: flex-start;
  gap: 12px;
  /* Bleeds into the panel gutters like the nav rows, so the hairlines and
     the hover tint run edge to edge (Dave 2026-09-07) */
  box-sizing: border-box;
  width: calc(100% + 2 * var(--menu-gutter, 32px));
  margin: 0 calc(-1 * var(--menu-gutter, 32px));
  padding: 10px var(--menu-gutter, 32px);
  border-top: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
  color: var(--fg);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  text-decoration: none;
  transition: color 200ms ease, background-color 200ms ease;
}

/* Link rows (not the email row, which is a div): the same tint as the nav
   rows, label to the accent as before, and the pressed state for touch */
.mobile-menu--contact a.contact-social--row:hover,
.mobile-menu--contact a.contact-social--row:active {
  transform: none;
  background: var(--menu-hover-bg);
  color: var(--primary-bright);
}

/* The panel takes focus on open so the reader starts at its top; no ring
   on the container itself (its controls keep theirs) */
.mobile-menu--panel:focus { outline: none; }

.contact-social__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--primary-bright);
  color: #ffffff;
}

.contact-social__icon svg {
  width: 18px;
  height: 18px;
}

.mobile-menu--contact .contact-social--row:first-child { border-top: 0; }

/* Email row in the contact panel (Dave 2026-09-07): the same disc + label
   shape as the link rows, with the input + copy box in the label's
   place. It sits first in the list but still takes a hairline, because
   the availability note sits above it. Not a link: no hover colour. */
.mobile-menu--contact .contact-actions .contact-email-row {
  border-top: 1px solid var(--border);
  cursor: default;
}

.mobile-menu--contact .contact-email-row .contact-email {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
}

/* Panel email row (Dave 2026-09-08): the same box + primary "Email Dave"
   group as the footer, in the label slot beside the envelope disc. The
   box flexes, the button keeps its size; the <=640 block stacks them. */
.mobile-menu--contact .contact-email-group {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  margin: 0;
  justify-content: flex-start;
}

.mobile-menu--contact .contact-email-group .contact-email {
  flex: 1 1 220px;
  width: auto;
  margin: 0;
}

.mobile-menu--contact .contact-email__mail {
  flex: 0 0 auto;
  padding: 0 16px;
}

/* The email row keeps its rest look on hover (the base .contact-social
   hover fill must not reach the div now that the link rows tint) */
.mobile-menu--contact .contact-email-row:hover,
.mobile-menu--contact .contact-email-row:active {
  transform: none;
  background: transparent;
  color: inherit;
}

/* Settings group: pinned to the bottom on purpose (a setting, not a
   destination), with a firm divider so the space above it reads as
   separation rather than a gap, and a tighter row (Dave 2026-09-07) */
.mobile-menu__settings {
  align-items: stretch;
  box-sizing: border-box;
  margin-top: auto;
  padding: 12px 32px calc(20px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border);
}

/* Theme switch row: glyph, label, then a switch track that follows
   aria-checked (main.js). Reuses .theme-toggle so the id wiring holds. */
.theme-toggle--switch {
  width: 100%;
  height: 44px;
  justify-content: flex-start;
  gap: 12px;
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
}

.theme-toggle--switch:hover,
.theme-toggle--switch:focus-visible {
  color: var(--primary-bright);
  transform: none;
}

.theme-toggle--switch:focus-visible {
  outline: 2px solid var(--primary-bright);
  outline-offset: 2px;
  border-radius: 8px;
}

/* The switch keeps the moon in both modes: the row is the setting itself,
   not a "switch to" affordance like the icon-only nav toggle */
:root .theme-toggle--switch .theme-toggle__icon--moon { display: block; }
:root .theme-toggle--switch .theme-toggle__icon--sun { display: none; }

.theme-toggle__text {
  flex: 1;
  text-align: left;
}

.theme-toggle__track {
  position: relative;
  flex-shrink: 0;
  width: 40px;
  height: 22px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--band-tint);
  transition: background 200ms ease, border-color 200ms ease;
}

.theme-toggle__knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--fg);
  transition: transform 200ms var(--ease-out), background 200ms ease;
}

.theme-toggle--switch[aria-checked='true'] .theme-toggle__track {
  border-color: var(--primary-bright);
  background: var(--primary-bright);
}

.theme-toggle--switch[aria-checked='true'] .theme-toggle__knob {
  transform: translateX(18px);
  background: #ffffff;
}

/* Contact panel copy follows the page theme here (the footer rules above
   pin the footer's always-dark tokens) */
.mobile-menu--contact .contact__headline { color: var(--fg); }
.mobile-menu--contact .contact__desc { color: var(--fg-body); }
.mobile-menu--contact .contact__note { color: var(--fg-muted); }
.mobile-menu--contact .contact-email {
  border-color: var(--primary-bright);
  background: rgba(30, 12, 50, 0.04);
}
.mobile-menu--contact .contact-email input,
.mobile-menu--contact .contact-email__copy { color: var(--fg); }
.mobile-menu--contact .contact-email__copy:hover { color: var(--primary-bright); }
:root[data-theme='dark'] .mobile-menu--contact .contact-email { background: rgba(0, 0, 0, 0.2); }

@media (max-width: 1023px) {
  /* Homepage header: Contact stays, Menu keeps its text label, and the
     capsule sits flush right (no hamburger disc to pair with) */
  .site-nav--menu .site-nav__actions > .nav-link--contact { display: inline-flex; }
  .site-nav--menu .site-nav__actions { margin-right: 0; }
  .site-nav--menu .site-nav__inner { padding: 0 20px; }
}

@media (max-width: 767px) {
  /* Homepage header on phones: Contact drops out and the Menu label gives
     way to the bars (the accessible name stays "Menu"), so the violet
     button is the 44px icon-only square the open state uses everywhere;
     gutters go to 12px */
  .site-nav--menu .site-nav__inner { padding: 0 12px; }

  /* The open panel's edge would slice the logo tile (Dave 2026-09-07), so
     the logo fades out whole while the panel is open and returns on close */
  .site-nav--menu .site-nav__logo {
    transition: background 400ms ease, border-color 400ms ease,
      backdrop-filter 400ms ease, -webkit-backdrop-filter 400ms ease,
      opacity 150ms ease, visibility 0s;
  }
  body.menu-open .site-nav--menu .site-nav__logo {
    opacity: 0;
    visibility: hidden;
    transition: background 400ms ease, border-color 400ms ease,
      backdrop-filter 400ms ease, -webkit-backdrop-filter 400ms ease,
      opacity 150ms ease, visibility 0s linear 150ms;
  }
  .site-nav--menu .site-nav__actions > .nav-link--contact { display: none; } /* Contact lives in the panel on phones (outranks the tablet block's inline-flex) */
  /* With Menu alone in it the frame has nothing to group, so it goes
     (Dave 2026-09-07); the margin and padding cancel so the button stays put */
  .site-nav--menu .site-nav__actions,
  .site-nav--menu.on-light .site-nav__actions {
    margin: 0;
    padding: 0;
    border-color: transparent;
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .site-nav--menu .nav-toggle {
    gap: 0;
    padding: 0 13px;
  }
  .site-nav--menu .nav-toggle__label {
    position: absolute;
    width: 1px;
    height: 1px;
    max-width: none;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  /* Contact panel: the address has 278px in the phone-width panel, so the
     input steps down a size to show every character */
  .mobile-menu--contact .contact-email input { font-size: 0.9375rem; }
}

@media (prefers-reduced-motion: reduce) {
  .menu-overlay,
  .nav-toggle,
  .nav-toggle__label,
  .theme-toggle__track,
  .theme-toggle__knob { transition: none; }

  /* Homepage header pair: the panel-open slide, fade and label fold stand
     still (these outrank the plain selectors above on specificity) */
  .site-nav--menu .nav-link--contact,
  .site-nav--menu .nav-toggle,
  body.menu-open .site-nav--menu .nav-link--contact,
  .site-nav--menu .site-nav__logo,
  body.menu-open .site-nav--menu .site-nav__logo { transition: none; }
}

/* Phones (mirrors the <=640 block in styles.css; this page breaks at 767) */
@media (max-width: 767px) {
  /* ---- Slide-out panel on phones (Dave 2026-09-07; mirrors styles.css) ----------------------
     Full width with 16px gutters; the list is the scroll region and the
     settings group is pinned at the bottom (safe-area aware) so it never
     rides away or covers the last item; type steps
     down one notch while every target stays 44px tall (padding, not
     font size, holds the height). */
  .mobile-menu--panel {
    width: 100%;
    box-shadow: none;
  }

  .mobile-menu--panel:not(.mobile-menu--contact) { overflow: hidden; }

  .mobile-menu__head {
    padding-left: 16px;
    padding-right: 16px;
  }

  .mobile-menu--panel .mobile-menu__nav {
    flex: 1 1 auto;
    min-height: 0;
    --menu-gutter: 16px;
    padding: 4px 16px 24px;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }

  .mobile-menu__settings {
    flex-shrink: 0;
    padding: 12px 16px calc(16px + env(safe-area-inset-bottom, 0px));
    background: var(--surface);
  }

  .mobile-menu__contact-body { padding: 24px 16px calc(20px + env(safe-area-inset-bottom, 0px)); --menu-gutter: 16px; } /* 20 not 24: the panel then fits an 812px phone viewport without a scroll (Dave 2026-09-07) */


  .mobile-menu--panel .mobile-menu__nav > .mobile-menu__item { padding: 0; }

  .mobile-menu--panel .mobile-menu__link {
    display: flex;
    align-items: center;
    width: calc(100% + 2 * var(--menu-gutter, 16px));
    min-height: 52px; /* the 44px target plus the 4px row padding each side, so plain rows match the accordion rows */
    padding-top: 4px;
    padding-bottom: 4px;
    font-size: 1.125rem;
  }

  .mobile-menu--panel .mobile-menu__expand { margin: 0 -10px 0 0; }

  .mobile-menu--panel .mobile-menu__sublink {
    min-height: 44px;
    font-size: 1rem;
  }

  .mobile-menu--panel .mobile-menu__sub-inner { --menu-indent: 12px; }

  /* Menu button on phones: a ghost stroke only, no fill, at roughly a
     quarter of the icon colour (a touch more over the hero stills); the
     8px radius is the button's own (Dave 2026-09-07; mirrors styles.css) */
  .site-nav--menu .nav-toggle,
  .site-nav--menu .nav-toggle:hover,
  .site-nav--menu .nav-toggle:focus-visible {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.3);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .site-nav--menu.is-over-hero .nav-toggle,
  .site-nav--menu.is-over-hero .nav-toggle:hover,
  .site-nav--menu.is-over-hero .nav-toggle:focus-visible { border-color: rgba(255, 255, 255, 0.4); }

  .site-nav--menu.on-light .nav-toggle,
  .site-nav--menu.on-light .nav-toggle:hover,
  .site-nav--menu.on-light .nav-toggle:focus-visible {
    background: transparent;
    border-color: rgba(30, 12, 50, 0.25);
  }

  /* Dark mode (Dave 2026-09-07): the same 6px frost the light on-light
     state carries, tinted with the surface token at 55%, so the white
     icon separates from the hero stills and dense dark content instead
     of competing with them. The ghost stroke stays on top of it. */
  :root[data-theme='dark'] .site-nav--menu .nav-toggle,
  :root[data-theme='dark'] .site-nav--menu .nav-toggle:hover,
  :root[data-theme='dark'] .site-nav--menu .nav-toggle:focus-visible {
    background: color-mix(in srgb, var(--surface) 55%, transparent);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
}

/* Pause button, copied from styles.css (this stylesheet is standalone) for the shared slide controls */
.hero__pause {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--divider-strong, rgba(255, 255, 255, 0.35));
  border-radius: 50%;
  background: transparent;
  color: var(--neutral-200, #ded7e6);
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease;
}

.hero__pause:hover {
  color: var(--fg-default, #ffffff);
  border-color: var(--fg-default, #ffffff);
}

.hero__pause:focus-visible {
  outline: 2px solid var(--primary-bright);
  outline-offset: 2px;
}

/* Progress arc: a 1.5px stroke 3px outside the button's own stroke, drawn
   from 12 o'clock (pathLength 100, dash offset 100 = empty, 0 = full) */
.hero__pause-ring {
  position: absolute;
  inset: -4px;
  width: calc(100% + 8px);
  height: calc(100% + 8px);
  transform: rotate(-90deg);
  pointer-events: none;
  overflow: visible;
}

.hero__pause-ring circle {
  fill: none;
  stroke: var(--neutral-200, #ded7e6);
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  opacity: 0.45; /* quiet by default (Dave 2026-09-07), fuller on hover */
  transition: opacity 200ms ease;
}

.hero__pause:hover .hero__pause-ring circle {
  stroke: var(--fg-default, #ffffff);
  opacity: 0.85;
}

.hero__pause-icon--play { display: none; }
.hero__pause.is-paused .hero__pause-icon--play { display: block; }
.hero__pause.is-paused .hero__pause-icon--pause { display: none; }

/* ==========================================================================
   Slide controls (Dave 2026-09-07): the hero's caption + pause + progress
   ring, plus prev / next arrows, as one glass capsule pinned to a corner
   of a carousel (homepage case study cards, the three case study heroes).
   Built by slide-controls.js. The buttons reuse the hero's .hero__pause
   rules; the capsule pins the dark-band tokens so it reads white-on-dark
   in both themes. The buttons anchor to the outer edge (order: pause,
   prev, next, then the caption growing inward), so captions can change
   length without moving them. Desktop and tablet only.
   ========================================================================== */
.slide-controls {
  --fg-default: #ffffff;
  --neutral-200: #ded7e6;
  --divider-strong: rgba(255, 255, 255, 0.35);
  position: absolute;
  bottom: 20px;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 8px;
  box-sizing: border-box;
  max-width: calc(100% - 40px);
  height: 44px;
  padding: 0 8px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 22px;
  background: rgba(14, 1, 28, 0.6);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
  backdrop-filter: blur(12px) saturate(1.2);
  color: var(--fg-default);
}

.slide-controls--left { left: 20px; }
.slide-controls--right { right: 20px; }

/* Visual order: buttons at the pinned edge, caption growing away from them */
.slide-controls__pause { order: 0; }
.slide-controls__prev { order: 1; }
.slide-controls__next { order: 2; }
.slide-controls__caption { order: 3; }
.slide-controls--right .slide-controls__caption { order: -1; }
.slide-controls--right .slide-controls__pause { order: 3; }

.slide-controls__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--divider-strong);
  border-radius: 50%;
  background: transparent;
  color: var(--neutral-200);
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease;
}

.slide-controls__arrow:hover {
  color: var(--fg-default);
  border-color: var(--fg-default);
}

.slide-controls__arrow:focus-visible {
  outline: 2px solid var(--primary-bright);
  outline-offset: 2px;
}

.slide-controls__caption {
  margin: 0;
  min-width: 0;
  padding: 0 6px 0 2px;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--fg-default);
  opacity: 0.9;
}

.slide-controls--right .slide-controls__caption { padding: 0 2px 0 6px; }
.slide-controls__caption[hidden] { display: none; }

/* Case study heroes (Dave 2026-09-07): hosted on the hero itself (a
   sticky, so positioned, box) and CENTRED, directly above the floating
   page nav, which is a fixed 52px bar 24px off the viewport bottom; at
   desktop the hero fills the viewport, so 96px up (24 + 52 + 20) keeps
   the two apart. Buttons first, caption growing right; a min-width so
   short captions do not shrink the capsule between slides. Anchored to
   the hero, so it scrolls away with it while the page nav stays. */
.csp-hero > .slide-controls,
.slide-controls--center {
  left: 50%;
  right: auto;
  bottom: 96px;
  transform: translateX(-50%);
  min-width: 320px;
  max-width: calc(100% - 48px);
}

.slide-controls--center .slide-controls__caption { flex: 1 1 auto; }

/* Tablet: the hero stacks with the image on top, so the capsule sits
   inside the image, 16px above its bottom edge (the hosts write the
   image height into --csp-media-h) */
@media (min-width: 641px) and (max-width: 1023px) { /* this page's hero stacks at 1023, not 1024 */
  .csp-hero > .slide-controls {
    top: calc(var(--csp-media-h, 0px) - 60px);
    bottom: auto;
  }
}

/* Homepage cards: the stage wraps the card link and hosts the controls
   outside it; it carries the stacking recession transform (main.js) so
   the controls recede with the card */
.cs-card__stage {
  position: relative;
  will-change: transform, filter;
  transform-origin: center top;
}

@media (max-width: 640px) {
  /* Phones: the slideshow runs as before, no controls, no caption */
  .slide-controls { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .slide-controls__arrow,
  .slide-controls__caption { transition: none; }
}

