/* ------ STUDIO SITE STYLES ------ */
/*
 * Layout system + page-transition styles for the By Default agency site.
 * Loads after design-system.css so the cascade resolves last here.
 * Layer: app — does not ship with the design system.
 *
 * Anything reusable across products belongs in assets/css/design-system.css,
 * not here. Keep this file scoped to the agency site.
 *
 * Transition timing uses design system motion primitives (--duration-*,
 * --ease-*) directly. Three speeds by intent:
 *   Hover / focus feedback:  --duration-2xs (100ms) + --ease-out
 *   Layout shifts:           --duration-xs  (200ms) + --ease-out
 *   Surface enter / exit:    --duration-s   (400ms) + --ease-out
 */


/* ------ FOCUS INDICATOR ------ */

/* Keyboard focus indicator — applies to all interactive elements that
   don't define their own focus-visible style. :where() keeps specificity
   at 0 so component-specific focus styles still win. */
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--text-primary);
  outline-offset: 2px;
  /* border-radius: var(--radius-xs); */
}

/* Initial focus lands on the dialog container itself (studio-nav.js openPanel)
   so no interactive element gets a focus ring when the nav opens. role="dialog"
   is only present while the panel is open, so this never affects the closed
   sidebar or the nav links inside it. */
#studio-sidebar[role="dialog"]:focus,
#studio-sidebar[role="dialog"]:focus-visible {
  outline: none;
}



/* ------ TOKENS ------ */

:root {
  /* Studio layout tokens */
  --background-sidebar: var(--background-primary);
  --sidebar-width: 400px;
  --sidebar-collapsed-width: 64px;
  --studio-bar-height: 3.5rem;
  --mobile-bar-height: 56px;
  --mobile-drawer-width: 100vw;
  --post-spacing: var(--space-l);
  --studio-gap: 1rem;
  --studio-gap-2x: 1.5rem;
  --z-sidebar: 50;
  /* Mobile drawer + its backdrop sit above the in-page .page-header
     (hardcoded z=400, above the transition layer at z=300). Without this,
     opening the mobile nav leaves the chrome's eyebrow bar floating on top
     of the drawer. */
  --z-backdrop: 500;
  --z-drawer: 600;
  /* Mobile bar must sit ABOVE the open drawer so the logo + close (X) stay
     visible and the drawer content scrolls underneath it. */
  --z-mobile-bar: 700;
  --bd-video-inset: var(--studio-gap);
  --scroll-offset: var(--studio-gap);
  --duration-stagger: 30ms;
  --sidebar-logo-width: 220px;
  --feed-gap: calc(var(--space-l));
  --studio-page-overlay-color: rgba(0, 0, 0, 0.05);
}


/* Dark mode token overrides */
:root[data-theme="dark"] {
  --background-primary: var(--neutral-900);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --background-primary: var(--neutral-900);
  }
}

/* Canonical sprite-logo contract — every place the studio renders a
   brand logo wraps the <svg> in `.svg-logo`. The wrapper carries
   inline aspect-ratio (from sprite metadata) and is the sizing surface;
   the SVG inside fills it via this single global rule. Together they
   mean: style the wrapper's width OR height in CSS and proportions
   stay correct without per-logo overrides. */
.svg-logo > svg {
  display: block;
  width: 100%;
  height: 100%;
}

.badge { text-transform: none; letter-spacing: normal; }


/* ------ TYPOGRAPHY SCALE ------ */
/*
 * Studio override of the five type-role sizes. Replaces the shared
 * design-system.css definitions (clamp + a ≤959px fixed-size override that
 * froze headlines at 28px across the whole mobile/tablet range). Studio loads
 * after design-system.css, so these win the cascade; design-system.css is
 * untouched and keeps its behaviour for BrandOS.
 *
 * Stepped rem (pulled from the existing --font-* scale) — no fluid font units,
 * so type fully respects browser zoom / font-size (WCAG 1.4.4). Two layers
 * because surfaces differ:
 *
 *   LAYER 1  :root + @media        Universal default. Drives chrome (sidebar,
 *                                  mobile drawer, page-header), modals, toasts —
 *                                  anything OUTSIDE the page content. Steps on
 *                                  the VIEWPORT width.
 *
 *   LAYER 2  .page-wrapper +       The reading column. .page-wrapper is the
 *            @container main-content   consistent child of [data-barba-stage]
 *                                  (the main-content container), so it steps on
 *                                  the real CONTENT width — which already shrinks
 *                                  /grows when the sidebar collapses. It declares
 *                                  its own base so it never inherits a viewport
 *                                  size that's wrong for a narrow column.
 *
 * Rungs chosen to keep headline > title > subline at every tier. px in comments.
 */

/* LAYER 1 — universal default (chrome, drawer, modals). Viewport-stepped. */
:root {
  --headline-size: var(--font-6xl); /* 40px */
  --title-size:    var(--font-3xl); /* 28px */
  --subline-size:  var(--font-l);   /* 20px */
  --body-size:     var(--font-s);   /* 16px */
  --label-size:    var(--font-xs);  /* 14px — a11y floor, never steps */
}

@media (min-width: 769px) {
  :root {
    --headline-size: var(--font-7xl); /* 48px */
    --title-size:    var(--font-5xl); /* 36px */
    --subline-size:  var(--font-2xl); /* 24px */
  }
}

@media (min-width: 1080px) {
  :root {
    --headline-size: var(--font-9xl); /* 64px */
    --title-size:    var(--font-7xl); /* 48px */
    --subline-size:  var(--font-2xl); /* 24px */
    --body-size:     var(--font-m);   /* 18px */
  }
}

/* LAYER 2 — content column. Container-stepped; own base, does NOT inherit L1. */
.page-wrapper {
  --headline-size: var(--font-6xl); /* 40px */
  --title-size:    var(--font-3xl); /* 28px */
  --subline-size:  var(--font-l);   /* 20px */
  --body-size:     var(--font-s);   /* 16px */
  --label-size:    var(--font-xs);  /* 14px — a11y floor, never steps */
}

@container main-content (min-width: 700px) {
  .page-wrapper {
    --headline-size: var(--font-7xl); /* 48px */
    --title-size:    var(--font-5xl); /* 36px */
    --subline-size:  var(--font-2xl); /* 24px */
  }
}

@container main-content (min-width: 1000px) {
  .page-wrapper {
    --headline-size: var(--font-8xl); /* 56px */
    --title-size:    var(--font-7xl); /* 48px */
    --subline-size:  var(--font-2xl); /* 24px */
    --body-size:     var(--font-m);   /* 18px */
  }
}

/* A modal is a full-bleed surface — it uses the Layer 1 default (sized to the
   viewport, not the content column). Authored at <body>/top-layer it gets this
   for free. If a dialog is ever placed INSIDE .page-wrapper and should ignore
   the column scale, reset its role tokens on the dialog element, e.g.:
   dialog, [role="dialog"] { --headline-size: var(--font-9xl); } */


/* ------ BASE TYPOGRAPHY ------ */

.text-title {
  font-size: var(--title-size);
  font-weight: var(--title-weight);
  line-height: var(--title-leading);
  letter-spacing: var(--title-tracking);
}

.text-headline {
  font-size: var(--headline-size);
  font-weight: var(--headline-weight);
  line-height: var(--headline-leading);
  letter-spacing: var(--headline-tracking);
}

.text-label {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  line-height: var(--label-leading);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
}

.text-body {
  font-size: var(--body-size);
  font-weight: var(--body-weight);
  line-height: var(--body-leading);
  letter-spacing: var(--body-tracking);
}

.drop-cap::first-letter,
[data-drop-cap]::first-letter {
  font-family: var(--font-secondary);
}

/* ------ LABEL ROLE ------ */

.label {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  line-height: var(--label-leading);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
}

.label.is-eyebrow {
  font-size: var(--label-size);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--letter-spacing-l);
}

.label.is-mono {
  font-family: var(--font-quaternary);
}

.label.is-serif {
  font-family: var(--font-tertiary);
}


/* ------ LAYOUT GRID ------ */

.layout {
  display: grid;
  grid-template-columns: var(--sidebar-width) 1fr;
  grid-template-areas: "sidebar main";
  min-height: 100vh;
  background: var(--background-primary);
  transition: grid-template-columns var(--duration-xl) var(--ease-out);
}

body.is-sidebar-collapsed .layout {
  grid-template-columns: var(--sidebar-collapsed-width) 1fr;
}


/* ------ INSET (universal gap primitive) ------ */
/*
 * Apply on any element to add a gap on chosen edges. Uses padding so the
 * element's own background fills the gap and the inner content is pushed
 * inward. Works on page wrappers, sections, cards — any block element.
 *
 *   <div data-inset="all">              ← all four sides
 *   <div data-inset="left right">       ← horizontal only
 *   <div data-inset="top right">        ← two specific edges
 *
 * No attribute = full bleed (no inner gap; content sits flush to edges).
 */

[data-inset~="top"]    { padding-top:    var(--studio-gap); }
[data-inset~="right"]  { padding-right:  var(--studio-gap); }
[data-inset~="bottom"] { padding-bottom: var(--studio-gap); }
[data-inset~="left"]   { padding-left:   var(--studio-gap); }
[data-inset="all"]     { padding: var(--studio-gap); }


/* ------ SIDEBAR ------ */

.sidebar {
  grid-area: sidebar;
  position: sticky;
  top: 0;
  width: var(--sidebar-width);
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--background-sidebar);
  z-index: var(--z-sidebar);
  box-sizing: border-box;
  padding: 0 var(--studio-gap);
  transition: width var(--duration-xl) var(--ease-out);
}

.sidebar::after {
  content: "";
  position: absolute;
  top: var(--studio-gap);
  bottom: var(--studio-gap);
  right: 0;
  width: var(--border-s);
  background: var(--border-faded);
  pointer-events: none;
}

.sidebar-inner {
  display: flex;
  flex-direction: column;
  flex: 1 1 0%;
  overflow-y: auto;
  overflow-x: hidden;
  gap: 0;
  scrollbar-width: none;
}

.sidebar-inner::-webkit-scrollbar {
  display: none;
}

/* -- Nav row (top of sidebar — text-only horizontal nav) -- */

.sidebar-header {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  gap: 0;
  flex-shrink: 0;
  min-height: var(--studio-bar-height);
  border-bottom: var(--border-s) solid var(--border-faded);
}

/* Desktop (≥1080): the nav lives inside the scrolling .sidebar-inner (DOM order
   is intro → nav → work). order:-1 lifts it above the intro and sticky pins it
   to the top so it stays visible while intro + work scroll beneath. On tablet
   and mobile this rule doesn't apply, so the nav keeps DOM order — intro on top,
   nav underneath — and scrolls with the content. */
@media (min-width: 1080px) {
  .sidebar-header {
    order: -1;
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--background-sidebar);
  }
}

/* Default state for the two structural triggers. They are revealed
   contextually: .sidebar-burger in the desktop collapsed rail,
   .sidebar-close-row in the tablet overlay. DOM order is
   logo → burger → close-row → inner(intro → nav → work) → footer. The nav
   scrolls in DOM order (intro on top) at tablet/mobile; the desktop @media
   rule above lifts + pins it to the top. */
.sidebar-burger,
.sidebar-close-row {
  display: none;
}

/* Burger: shown in the desktop collapsed rail (alongside the mini logo).
   Click expands the sidebar back to its 400px open state. */
body.is-sidebar-collapsed .sidebar-burger {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-s) 0;
}

/* Footer collapse toggle: hidden in the collapsed rail. The rail burger is
   the only opener — without this the footer button would sit in the rail
   doing nothing (it only ever collapses, never expands). */
body.is-sidebar-collapsed .footer-collapse-toggle {
  display: none;
}

.nav {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  justify-content: space-between;
  gap: var(--space-xs);
  width: 100%;

}

.nav-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--label-size);
  text-transform: uppercase;
  font-weight: var(--font-weight-medium);
  color: var(--text-primary);
  text-decoration: none;
  transition: color var(--duration-2xs) var(--ease-out);
  white-space: nowrap;
  padding: var(--l) var(--s);
  height: 100%;
}

.nav-link:hover,
.nav-link.is-active {
  color: var(--text-accent);
  background-color: color-mix(in srgb, var(--text-primary), var(--alpha-5));
}

/* Home + Playground links — hidden on desktop, shown only in the ≤1079px
   numbered nav (drawer + tablet overlay). Home: the logo links home on desktop.
   Playground: lives in the numbered nav alongside "Home 01", not the compact
   desktop bar (it stays reachable on desktop via the footer Explore nav). */
.nav-link-home,
.nav-link-playground {
  display: none;
}

/* Drawer-only elements (Pages label + per-link page numbers) — hidden on
   desktop / larger devices, revealed only in the ≤768px block below. */
.nav-pages-label {
  display: none;
}

.nav-link-num {
  display: none;
}

/* -- Intro block (logo + intro line, centered) -- */

/* Wrapper around .intro-block — narrows the link's box for visual breathing
   room. Tune padding to taste. */
.intro-block-wrap {
  padding: var(--studio-gap) 0;
}

.intro-block {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xl);
  padding: var(--space-3xl) var(--space-xl);
  text-decoration: none;
  color: var(--text-primary);
  background-color: transparent;
  transition: background-color var(--duration-m) var(--ease-out);
  border-radius: var(--radius-s);
}

a.intro-block:hover {
  background-color: var(--bg-faded-5);
  color: var(--text-primary);
}

.intro-block::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--border-s);
  /* background: var(--border-faded); */
  transition: background-color var(--duration-m) var(--ease-out);
}

.intro-block:hover::after,
.intro-block:has(+ .sidebar-about:hover)::after {
  background-color: transparent;
}

.svg-logo:has([data-logo="by-default-centered"]) {
  width: var(--sidebar-logo-width);
  aspect-ratio: 1050 / 505;
}

.svg-logo:has([data-logo="by-default-centered"]) svg {
  display: block;
  width: 100%;
  height: 100%;
}

.sidebar-intro {
  font-family: var(--font-primary);
  font-weight: inherit;
  color: var(--text-secondary);
  text-align: center;
  margin: 0;
  transition: opacity var(--duration-2xs) var(--ease-out), visibility var(--duration-2xs);
  display: none;
}

/* -- Sidebar about (intro paragraph + read-more) -- */

.sidebar-about {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: calc(var(--studio-gap) * 2) var(--studio-gap);
  text-decoration: none;
  color: var(--text-primary);
  /* border-radius: var(--radius-m); */
  background-color: transparent;
  transition: background-color var(--duration-m) var(--ease-out);
}

.sidebar-about:hover {
  background-color: var(--background-faded);
}

.sidebar-about::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--border-s);
  background: var(--border-faded);
  transition: background-color var(--duration-m) var(--ease-out);
}

.sidebar-about:hover::after {
  background-color: transparent;
}

.sidebar-about-copy {
  color: var(--text-secondary);
  margin: 0;
}

.sidebar-read-more {
  font-weight: var(--font-weight-medium);
  color: var(--text-accent);
  align-self: flex-start;
}

.sidebar-footer {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  min-height: var(--studio-bar-height);
  border-top: var(--border-s) solid var(--border-faded);
  font-size: var(--text-size-s);
  color: var(--text-faded);
  background: var(--background-sidebar);
}

.sidebar-footer p {
  margin: 0;
  transition: opacity var(--duration-2xs) var(--ease-out), visibility var(--duration-2xs);
}

/* -- Nav button role class (token overrides on .button) -- */
.nav-btn {
  --button-bg: transparent;
  --button-border: transparent;
  --button-text-color: var(--text-primary);
  --button-radius: 0;
}

.button.nav-btn:hover {
  background-color: color-mix(in srgb, var(--text-primary), var(--alpha-5));
}


.dark-mode-toggle .dark-mode-icon-dark {
  display: none;
}

body.is-dark-mode .dark-mode-toggle .dark-mode-icon-light {
  display: none;
}

body.is-dark-mode .dark-mode-toggle .dark-mode-icon-dark {
  display: block;
}

.sound-toggle .sound-icon-off {
  display: none;
}

body.is-sound-off .sound-toggle .sound-icon-on {
  display: none;
}

body.is-sound-off .sound-toggle .sound-icon-off {
  display: block;
}


/* -- Sidebar section label -- */

.sidebar-label {
  color: var(--text-faded);
  padding: 0 var(--studio-gap);
  margin: 0 0 var(--space-xs) 0;
  font-weight: var(--title-weight);
  font-size: var(--text-size-l);
  text-transform: none;
  letter-spacing: 0;
  color: inherit;
}

.nav-pages-label {  
    padding: 0 var(--studio-gap);
    margin: 0 0 var(--space-m) 0;
    color: inherit;
}


.sidebar-about .sidebar-label {
  padding-left: 0;
}

/* -- Sidebar slot — case-study + article mini-cards rendered into the
   sidebar from the manifest. Card-style: padded link with a faded
   background, vertical gap between cards. -- */

/* Variant is set on the parent .sidebar-slot, never on the link or its children.
   To switch looks: change one class on the <nav>.
     <nav class="sidebar-slot slot-minimal">  → divider-line look (current default)
     <nav class="sidebar-slot slot-card">     → background-card look */

.sidebar-slot {
  display: flex;
  flex-direction: column;
}

/* Stacked sidebar sections (Case Studies + Playground) — section break above
   each slot after the first. */
.sidebar-slot + .sidebar-slot {
  margin-top: var(--studio-gap);
}

/* -- Base — invariant across variants -- */

.sidebar-slot-link {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--studio-gap);
  text-decoration: none;
  color: var(--text-primary);
  transition: background-color var(--duration-m) var(--ease-out);
}

.sidebar-slot-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--border-s);
  transition: background-color var(--duration-m) var(--ease-out);
}

.sidebar-slot-link.is-active .sidebar-slot-excerpt {
  color: color-mix(in srgb, var(--text-primary), var(--alpha-50));
}

.sidebar-slot-thumb {
  flex-shrink: 0;
  height: 66px;
  aspect-ratio: 1/1;
  object-fit: cover;
  border-radius: var(--radius-xs);
}

.sidebar-slot-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  min-width: 0;
}

.sidebar-slot-title {
  font-size: var(--text-size-m);
  line-height: var(--line-height-m);
  font-weight: 420;
}

.sidebar-slot-excerpt {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--text-size-s);
  line-height: var(--line-height-m);
  color: color-mix(in srgb, var(--text-primary), var(--alpha-50));
}

/* -- External (experience) links — open in a new tab. The ↗ mark mirrors the
   feed's .post-external so the new-tab cue is consistent site-wide. The link's
   ::after is already used for the divider line, so neutralise the global
   a[target="_blank"]::after glyph (design-system.css) here to keep the divider
   intact; the ↗ is rendered as a real element instead. -- */
.sidebar-slot-link[target="_blank"]::after {
  -webkit-mask-image: none;
  mask-image: none;
  width: auto;
  height: var(--border-s);
  margin-left: 0;
}

.sidebar-slot-external {
  position: absolute;
  top: var(--studio-gap);
  right: var(--studio-gap);
  display: flex;
  color: var(--text-faded);
  pointer-events: none;
}

.sidebar-slot-external .svg-icn {
  width: 1rem;
  height: 1rem;
}

/* -- Variant: slot-minimal — divider line, no card chrome -- */

.sidebar-slot.slot-minimal .sidebar-slot-link {
  padding: var(--studio-gap);
}

.sidebar-slot.slot-minimal .sidebar-slot-link:hover,
.sidebar-slot.slot-minimal .sidebar-slot-link.is-active {
  background-color: var(--background-faded);
  border-radius: var(--radius-s);
}

.sidebar-slot.slot-minimal .sidebar-slot-link.is-active:hover {
  background-color: var(--background-darker);
}

.sidebar-slot.slot-minimal .sidebar-slot-link::after {
  background-color: var(--border-faded);
}

/* :has(+ ...) reaches the previous sibling — CSS has no prev-sibling combinator */
.sidebar-slot.slot-minimal .sidebar-slot-link:hover::after,
.sidebar-slot.slot-minimal .sidebar-slot-link:has(+ .sidebar-slot-link:hover)::after,
.sidebar-slot.slot-minimal .sidebar-slot-link.is-active::after,
.sidebar-slot.slot-minimal .sidebar-slot-link:has(+ .sidebar-slot-link.is-active)::after,
.sidebar-slot.slot-minimal .sidebar-slot-link:last-child::after {
  background-color: transparent;
}

/* -- Variant: slot-card — background cards, gap separator -- */

.sidebar-slot.slot-card {
  gap: var(--space-s);
}

.sidebar-slot.slot-card .sidebar-slot-link {
  padding: var(--studio-gap);
  background-color: var(--background-faded);
  border-radius: var(--radius-s);
}

.sidebar-slot.slot-card .sidebar-slot-link:hover,
.sidebar-slot.slot-card .sidebar-slot-link.is-active,
.sidebar-slot.slot-card .sidebar-slot-link.is-active:hover {
  background-color: var(--background-darker);
}

.sidebar-slot.slot-card .sidebar-slot-link::after {
  background-color: transparent;
}

/* First-load reveal — initial hidden state, cleared by initSidebarReveal()
   in studio-nav.js once the bd-intro curtain dismisses (or fonts.ready on
   repeat visits). visibility: hidden keeps invisible cards out of the tab
   order during the staggered delay window. Reduced-motion users see it
   instantly. */
.intro-block,
.sidebar-slot .sidebar-label,
.sidebar-slot-link {
  opacity: 0;
  visibility: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .intro-block,
  .sidebar-slot .sidebar-label,
  .sidebar-slot-link {
    opacity: 1;
    visibility: visible;
  }
}


/* ------ SIDEBAR — COLLAPSED (DESKTOP) ------ */

/* Mini mark — hidden by default (expanded desktop + mobile drawer both show
   the full wordmark in .intro-block). Revealed only inside the collapsed rail. */
.sidebar-logo-mini {
  display: none;
  align-items: center;
  justify-content: center;
  color: var(--text-primary);
  text-decoration: none;
  padding: var(--space-s) 0;
}

.svg-logo:has([data-logo="by-default-mini"]) {
  width: 32px;
  aspect-ratio: 1 / 1;
}

body.is-sidebar-collapsed .sidebar {
  width: var(--sidebar-collapsed-width);
}

body.is-sidebar-collapsed .sidebar-logo-mini {
  display: flex;
}

body.is-sidebar-collapsed .sidebar-inner {
  align-items: center;
}

body.is-sidebar-collapsed .sidebar-intro,
body.is-sidebar-collapsed .sidebar-footer p {
  opacity: 0;
  visibility: hidden;
}

body.is-sidebar-collapsed .sidebar-header,
body.is-sidebar-collapsed .intro-block-wrap,
body.is-sidebar-collapsed .intro-block,
body.is-sidebar-collapsed .sidebar-about,
body.is-sidebar-collapsed .sidebar-slot {
  display: none;
}

body.is-sidebar-collapsed .sidebar-footer {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);

}


/* ------ MOBILE BAR (mobile only — hamburger trigger for sidebar drawer) ------ */
/* Hidden on desktop; the sidebar grid handles desktop layout. The narrow-viewport
   media query at the bottom of this file flips display + the grid template. */

.mobile-bar {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  height: var(--mobile-bar-height);
  padding: 0 var(--space-m);
  background: var(--background-sidebar);
  z-index: var(--z-mobile-bar);
  border-bottom: var(--border-s) solid var(--border-faded);
}

/* Mobile bar logo — wordmark on the left, tap target sized to the bar. */
.mobile-bar-logo {
  display: flex;
  align-items: center;
  height: 100%;
  padding: var(--space-xs) 0;
  color: var(--text-primary);
  text-decoration: none;
}

.mobile-bar-logo .svg-logo:has([data-logo="by-default-centered"]) {
  width: auto;
  height: 100%;
  aspect-ratio: 1050 / 505;
}

/* Hamburger is a .button.nav-btn[data-icon-only] (same as the footer icon
   buttons) — the button component drives bg/border/sizing. This rule only
   guarantees a comfortable 40px tap target on the mobile bar. */
.hamburger {
  width: 40px;
  height: 40px;
}

/* Hamburger icon morph: menu (≡) by default, close (✕) while the drawer is
   open. The mobile bar sits above the drawer so this stays tappable. */
.hamburger-icon-close {
  display: none;
}
body.is-drawer-open .hamburger-icon-open {
  display: none;
}
body.is-drawer-open .hamburger-icon-close {
  display: block;
}


/* ------ MAIN AREA + BARBA CONTAINERS ------ */

.main {
  grid-area: main;
  position: relative;
  min-height: calc(100vh - var(--mobile-bar-height));
  background-color: var(--background-primary);
  min-width: 0;
}

[data-barba="wrapper"] {
  position: relative;
  min-height: calc(100vh - var(--mobile-bar-height));
}

[data-barba="container"] {
  position: relative;
}

/* During a transition, both containers overlay each other so they can animate
   independently without affecting layout flow. */
body.is-animating [data-barba="wrapper"] {
  pointer-events: none;
}

/* ONLY the leaving container is taken out of flow during a transition. The
   entering container stays position:relative in normal flow at scroll 0 the
   whole time, so it never undergoes a position:fixed→static flip when
   is-animating is removed — that flip was a one-frame reflow of the entering
   page (the "advance" end-jump). Scoping to [data-studio-role="leave"]
   structurally deletes that failure class for every scenario.

   position:fixed (not absolute) keeps the leaving container from being a
   containing block for its own sticky/fixed descendants — combined with the
   transform living only on [data-barba-stage], the leaving page + its sticky
   chrome move as one rigid unit. Its inline `top:-scrollY` (set in the
   before-hook atomic block, no !important here) overrides top:0 so it stays
   where the user was scrolled. fixed is viewport-relative, so inset past the
   sidebar by hand — left/right, not width:100% — mirroring the .page-overlay
   rule below. No bottom/height: it sizes to content so the stage can
   translate it. data-studio-role="leave" is set on the leaving container in
   the before-hook atomic block so this rule (the pin) applies in the same
   paint-free task as is-animating + scrollTo (Bug B). */
body.is-animating [data-studio-role="leave"] {
  position: fixed;
  top: 0;
  left: var(--sidebar-width);
  right: 0;
  /* No background here: the container is never transformed, so an opaque fill
     would sit static over home for the whole `exit` drop (and over the overlay
     on `enter`). The page background rides the moving stage via .page-wrapper
     below instead. */
}

/* Track sidebar collapse — mirror of the .page-overlay rule so the leaving
   container's left edge always aligns with the sidebar's current width. */
body.is-sidebar-collapsed.is-animating [data-studio-role="leave"] {
  left: var(--sidebar-collapsed-width);
}

/* Mobile (≤768px): the sidebar is hidden behind a mobile-bar + drawer, so the
   leaving page pin sits flush left and starts under the mobile bar. (Tablet
   769–1079px offsets by the 64px rail instead — see the tablet block.) */
@media (max-width: 768px) {
  body.is-animating [data-studio-role="leave"] {
    top: var(--mobile-bar-height);
    left: 0;
  }
}

/* The single per-page transform layer. Every page transition animates THIS
   element (never the container), so the container never becomes a containing
   block for its position:sticky/fixed descendants and the whole page + its
   sticky chrome moves as one rigid unit. Must stay exactly position:relative
   + display:block + width:100% with zero box-spacing — its box must coincide
   with the container content box or the scale pivot and the advance
   title-shift geometry shift. Do not add padding/margin/border/size here.

   container-type: inline-size hosts the @container main-content queries used
   throughout this file for content layouts (data-grid, content-feed, named
   layouts, component variants). The host MUST be a DESCENDANT of the pinned
   [data-barba="container"] — putting it on .main or [data-barba="wrapper"]
   would make the pin's position:fixed re-anchor to that element instead of
   the viewport, breaking the Bug-B atomic-pin. [data-barba-stage] already
   owns the transform layer for the same containing-block reason, so adding
   container-context here is architecturally consistent. */
[data-barba-stage] {
  position: relative;
  display: block;
  width: 100%;
  container-type: inline-size;
  container-name: main-content;
}


/*
 * Z-index per scenario. Barba 2.x does NOT add .barba-leave/.barba-enter
 * classes — we set data-studio-role="leave|enter" ourselves in the
 * transition's leave() function. Without these explicit z-indexes, two
 * absolute siblings with equal z fall back to "later in DOM wins", which is
 * the wrong order for close (home gets appended after the leaving page
 * and would cover it).
 */

/* The scenario attribute on each container is the finalised SCENARIO name
   (enter / exit / swap / advance / fade). enter/swap rise and need the
   entering container above the .page-overlay (z-index 200); exit/advance
   keep their own stacking; fade crossfades (entering above so it can fade
   in over the leaving one). */

/* enter (home → page) — rise: home sits still beneath the overlay,
   the new page rises above it. */
body.is-animating [data-studio-role="leave"][data-studio-scenario="enter"]  { z-index: 1; }
body.is-animating [data-studio-role="enter"][data-studio-scenario="enter"]  { z-index: 300; }

/* exit (page → home): the leaving page falls AWAY in front of home */
body.is-animating [data-studio-role="enter"][data-studio-scenario="exit"] { z-index: 1; }
body.is-animating [data-studio-role="leave"][data-studio-scenario="exit"] { z-index: 2; }

/* swap (non-home ↔ non-home) — rise: same shape as enter. */
body.is-animating [data-studio-role="leave"][data-studio-scenario="swap"] { z-index: 1; }
body.is-animating [data-studio-role="enter"][data-studio-scenario="swap"] { z-index: 300; }

/* advance (next-read): leaving article on top sliding up, next revealed behind */
body.is-animating [data-studio-role="leave"][data-studio-scenario="advance"] { z-index: 2; }
body.is-animating [data-studio-role="enter"][data-studio-scenario="advance"] { z-index: 1; }

/* fade (defensive fallback) — crossfade: entering above so it fades in. */
body.is-animating [data-studio-role="leave"][data-studio-scenario="fade"] { z-index: 1; }
body.is-animating [data-studio-role="enter"][data-studio-scenario="fade"] { z-index: 300; }


/* ------ PAGE OVERLAY (rise transition) ------ */

/* A persistent dim layer used by the "rise" page transition. Covers the
   main content area + page-header, but leaves the sidebar (desktop) and
   mobile-bar at full brightness. Opacity is driven by WAAPI in
   studio-barba.js — default state is invisible. */
.page-overlay {
  position: fixed;
  top: 0;
  left: var(--sidebar-width);
  right: 0;
  bottom: 0;
  background-color: var(--studio-page-overlay-color);
  opacity: 0;
  pointer-events: none;
  z-index: 200;
}

/* Track sidebar collapse — mirror of the .page-header rule so the overlay's
   left edge always aligns with the sidebar's current width. */
body.is-sidebar-collapsed .page-overlay {
  left: var(--sidebar-collapsed-width);
}

/* Mobile (≤768px): the mobile bar appears, so the page-overlay starts under
   it and runs full-width. (Tablet offsets by the 64px rail — tablet block.) */
@media (max-width: 768px) {
  .page-overlay {
    top: var(--mobile-bar-height);
    left: 0;
  }
}

/* (The old parked-header rule lived here. Deleted in Phase 3: the page-header
   is now choreographed entirely by GSAP inside buildTransition's timeline —
   it sets its own offscreen start state inline at timeline build, so there is
   no CSS-parked default and no Bug-A race net to maintain. The header's
   permanent z-index:400 — so it always sits above the entering stage (peaks
   at 300) — moved onto the base .page-header rule below.) */


/* ------ SECTION HEADER (sticky pattern) ------ */

.section-header {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  min-height: var(--studio-bar-height);
  background-color: var(--background-primary);
  border-bottom: var(--border-s) solid var(--border-faded);
  transition: opacity var(--duration-xs) var(--ease-out);
}

/* (The scenario-split opacity mask + its baseline fade-back-in helper lived
   here. Deleted in Phase 3. The mask faded the sticky chrome on close/push
   because the OLD model transformed the container (a containing-block trap).
   Since Phase 2 the transform is on the inner stage and the container is
   never transformed, so the sticky chrome rides the stage rigidly as one
   unit on every scenario — no mask needed (amendment J: on advance the
   toc/share/sticky-media now travel up WITH the article instead of fading).
   .section-header keeps its own opacity transition above for hover/state —
   that is unrelated to the deleted mask.) */

.section-header[data-sticky="false"] {
  position: static;
}

.section-header-start {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  min-width: 0;
  align-self: stretch;
}

.section-header-end {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  flex-shrink: 0;
  align-self: stretch;
}

.section-header-end > .button {
  align-self: stretch;
}


/* ------ PAGE HEADER (top-of-page bar with close button) ------ */

/* Lives outside the Barba wrapper (sibling of <main>'s data-barba="wrapper").
   Position: fixed (not sticky) so it doesn't take flow space — toggling
   [hidden] doesn't reflow the document. The page-wrapper's padding-top
   (rule below) reserves the visual space for L1+ pages. The data-sticky
   attribute in markup is now a harmless no-op. */
.page-header {
  position: fixed;
  top: 0;
  left: var(--sidebar-width);
  right: 0;
  /* Always above the transition layers: the entering stage peaks at z-index
     300 during enter/swap. This was a scenario-scoped boost in the now-
     deleted parked-header rule; made unconditional since the header is
     persistent chrome and never needs to sit behind a transitioning page.
     (.page-overlay at 200 only has opacity mid-transition, so at rest the
     header being above it is invisible — safe.) */
  z-index: 400;
  background-color: var(--background-primary);
  padding: 0 var(--studio-gap);
  transition: left var(--duration-s) var(--ease-out);
}

body.is-sidebar-collapsed .page-header {
  left: var(--sidebar-collapsed-width);
}

/* Reserve space for the fixed header on L1+ pages. Padding lives on the
   container's own page-wrapper so the entering page is correctly padded
   BEFORE animating in (driven by the container's own data-level, not by
   body[data-current-level] which updates late in afterEnter). */
/* The [data-barba-stage] wrapper sits between the container and .page-wrapper,
   so the reservation must traverse it (`> [data-barba-stage] > .page-wrapper`).
   The plain `> .page-wrapper` pair is kept as the stageOf()-degrade fallback
   (a container without a stage still gets padded). Without this the L1/L2
   page jams under the fixed .page-header and the next-read title snaps up. */
[data-barba="container"][data-level="1"] > [data-barba-stage] > .page-wrapper,
[data-barba="container"][data-level="2"] > [data-barba-stage] > .page-wrapper,
[data-barba="container"][data-level="1"] > .page-wrapper,
[data-barba="container"][data-level="2"] > .page-wrapper {
  padding-top: var(--studio-bar-height);
}


/* Page background. It MUST live on .page-wrapper, not [data-barba="container"]:
   the container is never transformed (only the inner [data-barba-stage] moves),
   so a background on the container would occlude the .page-overlay on `enter`
   and the home page on `exit`. .page-wrapper is inside the stage, so its fill
   travels with the transform — the page reads as one opaque unit while still
   revealing the overlay/home beneath during transitions. */
.page-wrapper {
  background-color: var(--background-primary);
  min-height: 100vh;
}

/* Defensive — beats `.page-header { display: ... }` specificity when [hidden]
   is toggled on the persistent instance (e.g. on L0 home). */
.page-header[hidden] {
  display: none;
}

.page-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  min-height: var(--studio-bar-height);
  border-bottom: var(--border-s) solid var(--border-faded);
}

.page-header-start {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  min-width: 0;
  align-self: stretch;
}

.page-header-end {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  flex-shrink: 0;
  align-self: stretch;
}

.page-header-end > .button {
  align-self: stretch;
}




.eyebrow-header {
  margin: 0;
  font-size: var(--text-size-l);
}

/* Mobile (≤768px) chrome positioning — the mobile bar is shown, so the
   page-header sits full-width below it and sticky section-headers clear it.
   (Tablet offsets the page-header by the 64px rail — see the tablet block.) */
@media (max-width: 768px) {
  .section-header {
    top: var(--mobile-bar-height);
  }
  /* Mobile bar + page-header: the feed filter bar must pin below both. */
  .case-studies-section .section-header,
  .playground-section .section-header {
    top: calc(var(--mobile-bar-height) + var(--studio-bar-height));
  }
  .page-header {
    left: 0;
    top: var(--mobile-bar-height);
  }
  body.is-sidebar-collapsed .page-header {
    left: 0;
  }
}

/* Filter-click target. scrollIntoView on the grid lands its top below the
   sticky filter bar with a small clearance. The sticky bar stays stuck at
   viewport top; the .feed-masterhead intro scrolls off-screen.
   Anchoring on .section-header directly would be wrong — it's position:
   sticky and its bounding rect collapses to 0 when stuck. */
.content-feed {
  scroll-margin-top: var(--studio-bar-height);
}

/* Case studies: the filter bar sits below the masthead (not at the top of the
   section), so when it pins it must clear the opaque fixed .page-header
   (z-index 400) — top:0 would hide it behind the page-header. The masthead
   scrolls away above it. The filter-click scroll target must then clear both
   the page-header AND the pinned filter bar (each ≈ --studio-bar-height). */
.case-studies-section .section-header,
.playground-section .section-header {
  top: var(--studio-bar-height);
}
.case-studies-section .content-feed,
.playground-section .content-feed {
  scroll-margin-top: calc(var(--studio-bar-height) * 2);
}


/* ------ PAGE INTRO (shared) ------ */

.page-headline {
  font-size: var(--headline-size);
  font-weight: var(--headline-weight);
  color: var(--text-primary);
  margin: 0;
}

.page-title {
  font-size: var(--title-size);
  font-weight: var(--title-weight);
  color: var(--text-primary);
  font-stretch: var(--title-width);
}

.headline-display {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: uppercase;
  line-height: 0.85;;
}





.home-headline {
  margin: 0;
}

/* Cycling word — last word of the home headline rotates through a list of
   alternates. Items stack absolutely; one is active in flow at a time. JS
   measures the longest item at init and locks min-width on the wrapper so
   swaps don't reflow the line. The animation style is selected by the
   data-cycle-style attribute and registered in studio-home.js. */
.cycle-word {
  display: inline-block;
  position: relative;
  vertical-align: baseline;
  overflow: hidden;
  /* Buffer below the baseline so overflow:hidden doesn't clip descenders
     (g, p, y, etc.). Negative margin-bottom keeps external layout in place. */
  padding-bottom: 0.2em;
  margin-bottom: -0.2em;
  /* min-width is set inline by JS after measurement */
}

/* The cycle-word descender buffer shifts the inline word upward on a
   single-line heading where text precedes the cycle. The H1 puts the
   cycle-word on its own line (via <br>) so the buffer is invisible there;
   here it's inline after "Make your content" and visible as a baseline jog. */
#product-spotlight-heading .cycle-word {
  padding-bottom: 0;
  overflow: inherit;
}

.cycle-word-item {
  display: inline-block;
  position: absolute;
  inset: 0;
  visibility: hidden;
  white-space: nowrap;
}

.cycle-word-item.is-active {
  position: relative;
  visibility: visible;
}

/* Visually-hidden sibling that exposes the canonical word to screen readers.
   The animated .cycle-word wrapper is aria-hidden, so without this the
   heading would have no last-word at all in the accessibility tree. Standard
   "visually hidden" pattern; kept local until/unless a foundation utility
   lands in design-system.css. */
.cycle-word-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Visually-hidden polite live region announced on every Barba navigation
   (route-change announcement — SR users otherwise get no page-change cue
   because the title swap is silent and <main> has no accessible name).
   Persistent chrome (sibling of .page-overlay, outside the Barba wrapper)
   so it survives container swaps. Same standard "visually hidden" technique
   as .cycle-word-sr above. */
.route-status {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.page-subline {
  font-size: var(--subline-size);
  font-weight: var(--subline-weight);
  line-height: var(--line-height-l);
}

/* Inline image inside a headline — scales with the surrounding font-size,
   sits on the baseline, breathes a touch on each side. Multiple images per
   headline use the same class with no extra rules. */
.img-headline {
  display: inline-block;
  height: 0.7em;
  width: auto;
  vertical-align: baseline;
  margin: 0 0.15em;
  object-fit: cover;
  border-radius: var(--radius-s);
  display: none;
}

/* ------ HOME HERO (wraps a .bd-video player; studio-specific padding + chrome) ------ */

.home-hero {
  --bd-video-inset: var(--studio-gap);
}

.home-hero .bd-video-player {
  overflow: hidden;
  /* border-radius: var(--radius-m); */
  border: var(--border-s) solid var(--bg-faded-10);
  /* border-radius: var(--radius-s); */
  max-height: calc(100vh - var(--studio-gap) * 2); /* cap hero to viewport; object-fit:cover crops past 16:9 */
}

/* ------ HOME STATS (three-column data points beneath the hero) ------ */

.home-stats-headline {
  color: var(--text-primary);
}

.home-stats-headline-faded {
  color: var(--text-faded);
}

.home-stats-item {
  border-left: var(--border-s) solid var(--border-faded);
  padding: 0 var(--space-2xl);
}

.home-stats-figure {
  font-size: var(--font-7xl);
  font-family: var(--font-tertiary);
  font-weight: var(--font-weight-semi-bold);
  line-height: 1;
  letter-spacing: var(--letter-spacing-xs);
  margin: 0;
}

.home-stats-label {
  font-size: var(--text-size-l);
  font-weight: var(--font-weight-medium);
  color: var(--text-primary);
  margin: 0;
}

.home-stats-copy {
  color: var(--text-faded);
  margin: 0;
}

/* Stacked: rotate the divider from a left rule to a top rule when the items
   stack. .home-stats-item is shared by two grids that collapse at DIFFERENT
   content widths, so the rotation is scoped per grid to match each stack point
   exactly — a single global breakpoint left one grid stacked with the wrong
   divider in the band between the two thresholds.
     - home  (.home-stats → [data-grid][data-layout="thirds"]) stacks at 959.98px
     - about (.process-steps) stacks at 768px */
@container main-content (max-width: 959.98px) {
  .home-stats .home-stats-item {
    border-left: 0;
    border-top: var(--border-s) solid var(--border-faded);
    padding-left: 0;
    padding-top: var(--space-l);
  }
}

@container main-content (max-width: 768px) {
  .process-steps .home-stats-item {
    border-left: 0;
    border-top: var(--border-s) solid var(--border-faded);
    padding-left: 0;
    padding-top: var(--space-l);
  }
}

/* Decorative autoplay videos (article bodies, section backgrounds). No JS —
   pure HTML attributes (autoplay, muted, loop, playsinline). Distinct from
   the full .bd-video player. Emitted by the {{bg-video}} markdown shortcode
   in studio/cms/generator/lib/render-markdown.js. */
.bg-video {
  display: block;
  width: 100%;
  height: auto;
}


/* ------ HOME SERVICES (lettered specialties list) ------ */
/* Letters A/B/C/D are rendered via CSS counter on ::before, so adding or
   reordering items keeps the markers in sync without manual edits. */

.services-list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: services-counter;
}

.services-list-item {
  display: grid;
  grid-template-columns: 2rem 1fr;
  align-items: baseline;
  column-gap: var(--space-2xl);
  padding-block: var(--space-l);
  counter-increment: services-counter;
  font-family: var(--font-primary);
  font-size: var(--headline-size);
  font-weight: var(--font-weight-light);
  line-height: 1;
  letter-spacing: -0.01em;
}

.services-list-item::before {
  content: counter(services-counter, decimal-leading-zero);
  align-self: start;
  padding-top: 0.6em;
  font-family: var(--font-tertiary);
  font-weight: var(--font-weight-regular);
  letter-spacing: 0.05em;
  color: var(--text-faded);
}

@container main-content (max-width: 768px) {
  .services-list-item {
    grid-template-columns: 1.5rem 1fr;
    column-gap: var(--space-m);
    padding-block: var(--space-m);
  }
}


/* ------ CONTENT FEED (masonry grid) ------ */
/*
 * CSS column-based masonry. Cards flow top-to-bottom, left-to-right, filling
 * columns based on their natural height. Filtering hides cards with display:none
 * and the columns reflow automatically — no JS redistribution needed.
 */

.feed-masterhead {
  padding: var(--space-8xl) var(--space-m);
  display: flex;
  flex-direction: column;
  text-align: center;
  gap: var(--space-l);

}

.feed-masterhead > * {
  margin: 0;
}

.feed-headline {
  font-family: var(--font-display);
  font-size: clamp(3rem, 15vw, 15rem);
  letter-spacing: 0;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
}

.feed-subline {
  font-size: clamp(1rem, 2vw, 2rem);
  color: var(--text-faded);
  font-style: italic;
}

.content-feed {
  padding-top: var(--feed-gap);
  column-count: 3;
  column-gap: var(--feed-gap);
  width: 100%;
}


/* -- Post item (feed wrapper — masonry, filtering, spacing) -- */

.post-item {
  break-inside: avoid;
  margin-bottom: var(--feed-gap);
}

/* -- Feed transition states -- */
/* Hide: quick exit. Show: slightly slower entrance. */
/* Transition style set via data-feed-transition on .content-feed */

/* fade (default) */
.post-item {
  opacity: 1;
  transform: scale(1);
  transition: opacity var(--duration-2xl) var(--ease-out),
              transform var(--duration-2xl) var(--ease-out);
}

.post-item.is-hiding {
  opacity: 0;
  transition-duration: var(--duration-2xs);
}

.post-item.is-showing {
  opacity: 0;
}

/* scale — shrink to 0, grow back to 1 */
[data-feed-transition="scale"] .post-item.is-hiding,
[data-feed-transition="scale-stagger"] .post-item.is-hiding {
  opacity: 0;
  transform: scale(0);
  transition-duration: var(--duration-2xs);
}

[data-feed-transition="scale"] .post-item.is-showing,
[data-feed-transition="scale-stagger"] .post-item.is-showing {
  opacity: 0;
  transform: scale(0);
}

@container main-content (max-width: 960px) {
  .content-feed { column-count: 2; }
}

@container main-content (max-width: 768px) {
  .content-feed { column-count: 1; }
}


/* ------ STICKY STACK (reusable layout primitive) ------ */

/* Sticky .sticky-media beside a .scroll-stack column; combo with .section-content + data-grid. */
[data-grid].sticky-stack {
  align-items: start;        /* don't stretch columns — sticky needs travel room */
  grid-auto-flow: dense;     /* DOM-first .sticky-media claims its desktop column without gapping */
}

.sticky-media {
  position: sticky;
  top: calc(var(--studio-bar-height) + var(--studio-gap));
  height: calc(100vh - var(--studio-bar-height) - var(--studio-gap) * 2);
  align-self: start;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 5;
}

.scroll-stack {
  display: flex;
  flex-direction: column;
}

/* Each direct child of .scroll-stack, any tag. */
.scroll-stack-item {
  display: flex;
  flex-direction: column;
  justify-content: center;     /* default — items vertically centred */
  gap: var(--space-m);
}

/* Margin reset for text at any depth; :where() keeps specificity at 0 so component rules still win. */
.scroll-stack-item :where(h1, h2, h3, h4, h5, h6, p, ul, ol) {
  margin: 0;
}

/* Vertical alignment variants — set data-align on the parent .scroll-stack. */
.scroll-stack[data-align="top"]    .scroll-stack-item { justify-content: flex-start;    }
.scroll-stack[data-align="bottom"] .scroll-stack-item { justify-content: flex-end;      }
.scroll-stack[data-align="space"]  .scroll-stack-item { justify-content: space-between; }

.about-beliefs .scroll-stack-item {
  border-bottom: var(--border-s) solid var(--border-faded);
  padding: var(--space-8xl) var(--space-l);
}


/* Single-column below 959.98px: release the sticky full-height media so it flows inline. */
@container main-content (max-width: 959.98px) {
  .sticky-media {
    position: static;
    height: auto;
    z-index: auto;
  }
}

@container main-content (max-width: 768px) {
  .scroll-stack {
    gap: var(--space-2xl);
  }
  .scroll-stack-item {
    min-height: auto;
    gap: var(--space-s);
  }
}

/* Per-founder sticky header (two-column only) — .founder-intro height sets how long the name dwells. */
.founder-erlen,
.founder-syeda, .team-paul {
  border-bottom: var(--border-s) solid var(--border-faded);
}

.founder-intro {
  min-height: 70vh;
}

.founder-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  position: sticky;
  top: calc(var(--studio-bar-height) + var(--studio-gap));
  padding-bottom: var(--space-3xl);
}

.founder-header h2 {
  font-family: var(--font-display);
  font-size: var(--font-10xl);
  font-weight: var(--font-weight-bold);
  letter-spacing: 0;
  line-height: 0.8;
  text-transform: uppercase;
}

.team-member h3 {
  font-family: var(--font-display);
  font-size: var(--font-8xl);
  font-weight: var(--font-weight-bold);
  letter-spacing: 0;
  text-transform: uppercase;
  margin: 0;
}

/* Single-column below 959.98px: release the founder header from sticky and drop the dwell. */
@container main-content (max-width: 959.98px) {
  .founder-intro {
    min-height: 0;
  }
  .founder-header {
    position: static;
    top: auto;
  }
}

.syeda-bio {
  padding-left: var(--studio-gap-2x);
}

/* ------ ABOUT PAGE ------ */

/* -- Media frame (feature/hero mask — image, video, or BD-Video player) -- */

.media-frame {
  width: 100%;
  overflow: hidden;
}

.media-frame > img,
.media-frame > video,
.media-frame > .bd-video,
.media-frame > .bg-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Parallax — oversize the image so bd-animations.js has vertical slack to translate;
   negative margin-top centers it. Tune per-instance with --bd-parallax-overflow. */
.media-frame[data-bd-parallax] > img {
  height: calc(100% + var(--bd-parallax-overflow, 30%));
  margin-top: calc(var(--bd-parallax-overflow, 30%) / -2);
}

/* Fill — drop the aspect-ratio and fill the parent's height (e.g. inside .sticky-media).
   Gated on container width so it reverts to data-ratio when the content area is narrow. */
@container main-content (min-width: 960px) {
  .media-frame.is-fill {
    height: 100%;
    aspect-ratio: auto;
  }
}

/* -- Origin / Founding story -- */

.origin-prose {
  columns: 2;
  column-gap: var(--space-2xl);
  color: var(--text-primary);
}

.origin-prose p { margin: 0; }
.origin-prose p:not(:last-child) { margin-bottom: var(--space-l); }

.origin-prose em {
  font-style: italic;
  color: var(--text-primary);
}

@container main-content (max-width: 768px) {
  .origin-prose { columns: 1; }
}

/* -- How we work / process -- */

.about-process-divider {
  margin: var(--space-5xl) 0;
}

/* ------ ARTICLE HEADER ------ */

[data-article] {
  position: relative;
}

.article-lead {
  padding: var(--section-l) 0;
  background-color: var(--background-primary);
}

.article-header > .block {
  align-items: center;
  text-align: center;
  gap: var(--space-xl);

}

/* -- Article meta (badge, read time, date) -- */

.article-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-l);
}

.article-meta-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-s);
  color: var(--text-faded);
}

.article-meta-item .svg-icn {
    width: 1rem;
    height: 1rem;
}

.article-headline {
  margin: 0;
  font-size: var(--headline-size);
  font-weight: var(--headline-weight);
  line-height: var(--headline-leading);
  letter-spacing: var(--headline-tracking);
  text-wrap: balance;
}



/* -- Article author (avatar + name link) -- */

.article-author {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  color: var(--text-primary);
  text-decoration: none;
}

.article-author-by {
  font-style: italic;
  color: var(--text-faded);
}

.article-author-avatar {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  object-fit: cover;
}



/* -- Article content wrapper (3-column layout) -- */

.article-content-wrapper {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: var(--space-2xl);
  width: 100%;
}

.article-sidebar {
  flex: 1 1 0%;
  align-self: stretch;
}

.toc-block,
.share-block {
  position: sticky;
  top: calc(var(--mobile-bar-height) + var(--space-8xl));
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  max-width: 220px;
  margin: 0 auto;
  opacity: 0;
  transition: opacity var(--duration-l) var(--ease-out);
}

.toc-block.is-visible,
.share-block.is-visible {
  opacity: 1;
}

.article-body {
  flex: 0 1 auto;
  width: 60%;
  max-width: 600px;
}

/* TOC-link / hash jumps land below the fixed .page-header instead of behind it.
   Mobile adds --mobile-bar-height because the page-header is pushed down by
   the mobile bar at <=768px. */
.article-body :is(h1, h2, h3, h4, h5, h6) {
  scroll-margin-top: calc(var(--studio-bar-height) + var(--studio-gap));
}

@container main-content (max-width: 768px) {
  .article-body :is(h1, h2, h3, h4, h5, h6) {
    scroll-margin-top: calc(var(--mobile-bar-height) + var(--studio-bar-height) + var(--space-m));
  }
}


/* -- Table of contents -- */

.toc-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.toc-link {
  display: block;
  color: var(--text-secondary);
}

.toc-link:hover {
  color: var(--text-primary);
}

.toc-link.is-active {
  color: var(--text-primary);
  font-weight: var(--font-weight-medium);
}

.toc-list li {
  margin: 0;
}

.article-sidebar .toc-link {
  text-decoration: none;
  color: var(--text-faded);
}

.article-sidebar .toc-link.is-active {
  color: var(--text-primary);
}

/* -- "In this article" (inline TOC, always visible) -- */

.in-this-article {
  padding-left: var(--space-xl);
  margin-bottom: var(--space-xl);
  border-left: var(--border-s) solid var(--border-faded);
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

/* -- Share block -- */

.share-links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-s);
}

.share-links .button {
  --button-padding-y: var(--space-s);
  --button-padding-x: var(--space-s);
  --button-text-size: var(--font-s);
  --icon-size: 1em;
}

/* -- Responsive: collapse sidebars on tablet -- */

@container main-content (max-width: 960px) {
  .article-sidebar {
    display: none;
  }

  .article-body {
    width: 100%;
    max-width: none;
  }
}


/* ------ NEXT READ ------ */

/* Next-read block — sits between the current article and the next-read
   card as a standalone sibling. Only created by JS. */
.next-read {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-m);
  padding: var(--space-6xl) 0;
  background-color: var(--background-primary);
}

.next-read::before,
.next-read::after {
  content: "";
  flex: 1;
  height: var(--border-s);
  background-color: var(--divider-color);
}

.next-read-label {
  color: var(--text-faded);
}

/* Sibling gap between the current article and the next-read preview card */
.article + .article {
  margin-top: var(--studio-gap);
}

/* Next-read wrapper — shares .article base (bg + radius) with the current
   article card. Relative positioning + cursor live on the wrapper so the
   full-coverage link overlay works across the whole card. */
.article.is-next-read {
  position: relative;
  cursor: pointer;
}

/* Full-coverage clickable overlay */
.article.is-next-read .next-read-link {
  position: absolute;
  inset: 0;
  z-index: 1;
}



/* ------ POSTS ------ */


/* -- Base post (shared across all types) -- */

.post {
  display: flex;
  flex-direction: column;
  gap: var(--post-spacing);
  padding: var(--post-spacing);
  background-color: var(--bg-faded-3);
  text-decoration: none;
  color: var(--text-primary);
  overflow: hidden;
  border-radius: var(--radius-s);
  transition: background-color var(--duration-l) var(--ease-out);
}

.post[data-feed-layout="cover"] {
  padding: 0;
}


.post:hover {
  background-color: var(--bg-faded-7);
}

/* Thumbnail container — acts as a mask. The ratio lives on the container,
   the image inside fills it via object-fit: cover. This means the image
   can be any aspect ratio and the container crops it. */
.post-thumbnail {
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  /* border-radius: var(--radius-s); */
}

.img-thumb,
.vdo-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--duration-2xl) var(--ease-out);
}

.post:hover .img-thumb,
.post:hover .vdo-thumb {
  transform: scale(1.05);
}

/* Video thumbnail — hover-to-play, bound by thumb-hover.js. Playback + zoom
   both fire on hover. Touch + narrow viewports see the poster only. */
.vdo-thumb {
  background: var(--background-faded);
}

.post-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  z-index: 10;
}

.post-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

/* Post labels */

.post-label,
.post-client-label {
  color: var(--text-faded);
}


.post[data-feed-layout="cover"] .post-label {
  color: var(--white-alpha-70);
}

.post[data-feed-layout="cover"] .post-client-label {
  color: var(--white);
}


.post-title {
  margin: 0;
  font-weight: var(--title-weight);
  color: var(--text-primary);
  font-size: var(--text-size-l);
  text-wrap: balance;
}

.splide .post-title {
  font-size: var(--text-size-l);
}

.post-excerpt {
  margin: 0;
  color: var(--text-faded);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  display: none;
}

.post:hover .post-excerpt {
  color: var(--text-primary);
}

.post-meta {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  margin-top: var(--space-xs);
}

.post-meta-item {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--text-faded);
}

.bottom-meta {
  display: none;
}

.post-meta > *:not(:last-child)::after {
  content: "\00b7";
  margin-left: var(--space-s);
}
.post-read-status {
  display: none;
  color: var(--text-faded);
  flex-shrink: 0;
  background: none;
  padding: 0;
  gap: var(--space-xs);
}

.post-item.is-read .post-read-status {
  display: flex;
}

.post-read-status .svg-icn {
  width: 1.1rem;
  height: 1.1rem;
}

/* Experience external-link affordance — sits in the header end-slot where the
   read badge would be on internal cards, signalling the card opens out in a new
   tab. Icon colour stays consistent with .post-label across layouts. */
.post-external {
  display: flex;
  flex-shrink: 0;
  color: var(--text-faded);
}

.post-external .svg-icn {
  width: 1.1rem;
  height: 1.1rem;
}

.post[data-feed-layout="cover"] .post-external {
  color: var(--white-alpha-70);
}

/* Experience posts open in a new tab and so inherit the global
   a[target="_blank"]::after external-link glyph (design-system.css). The card
   already signals "opens externally" via .post-external (↗) in its header, so
   suppress the duplicate inline glyph on the card link itself. */
.post[target="_blank"]::after {
  content: none;
}

.post-hero {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  margin-bottom: var(--space-l);
}


/* -- Cover layout (full-bleed image with text overlay) -- */
/* Card height is driven by aspect-ratio on the post itself (default 4:5).
   Override with data-ratio="W:H" on the .post element. The :not([data-ratio])
   rule scopes the default so the global [data-ratio] block can win. */

.post[data-feed-layout="cover"] {
  position: relative;
  padding: 0;
}

.post[data-feed-layout="cover"]:not([data-ratio]) {
  aspect-ratio: 4 / 5;
}

.post[data-feed-layout="cover"] .post-header {
  padding: var(--studio-gap) var(--studio-gap) var(--space-5xl) var(--studio-gap);
    background: linear-gradient(to bottom, var(--black-alpha-30) 0%, transparent 100%);

}
.post[data-feed-layout="cover"] .post-thumbnail {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  z-index: 0;
}

.post[data-feed-layout="cover"] .post-body {
  position: relative;
  z-index: 1;
  justify-content: flex-end;
  height: 100%;
  padding: 0 var(--post-spacing) var(--space-2xl) var(--post-spacing);
  background: linear-gradient(to top, var(--black-alpha-70) 0%, transparent 70%);
}

.post[data-feed-layout="cover"] .post-title {
  color: var(--white);
  /* font-size: var(--font-xl); */
}

.post[data-feed-layout="cover"] .post-excerpt {
  color: var(--white-alpha-80);
}

.post[data-feed-layout="cover"] .post-meta {
  color: var(--white-alpha-60);
}

.post[data-feed-layout="cover"] .post-read-status {
  color: var(--white);
}




/* -- Content type accent colours -- */



/* ------ CASE STUDY ------ */

/* -- Header -- */

.case-study-header-content {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.case-study-header-actions {
  justify-self: end;
  align-self: end;
}

.case-study-synopsis {
  color: var(--text-secondary);
}

.case-study-services {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

.case-study-services .tag:nth-child(n + 6) {
  display: none;
}

/* -- Toggle button -- */

.button.case-study-toggle {
  gap: var(--space-xs);
  white-space: nowrap;
  --button-border: var(--button-text-color);
}

.case-study-toggle-icon-close {
  display: none;
}

.case-study-wrapper.is-info-open .case-study-toggle-icon-add,
body.is-case-study-open .case-study-toggle-wrap .case-study-toggle-icon-add {
  display: none;
}

.case-study-wrapper.is-info-open .case-study-toggle-icon-close,
body.is-case-study-open .case-study-toggle-wrap .case-study-toggle-icon-close {
  display: block;
}

/* -- Fixed toggle wrap (persistent, outside Barba container) -- */

.case-study-toggle-wrap {
  display: none;
  position: fixed;
  bottom: var(--studio-gap-2x);
  right: var(--studio-gap-2x);
  z-index: 50;
  transition: opacity var(--duration-xs) var(--ease-out),
              transform var(--duration-xs) var(--ease-out);
}

.case-study-toggle-wrap.is-visible {
  display: flex;
}

.case-study-toggle-wrap.is-hidden {
  opacity: 0;
  pointer-events: none;
  transform: translateY(var(--space-s));
}

/* -- Two-panel body -- */

.case-study-body {
  display: flex;
  align-items: stretch;
  scroll-margin-top: var(--studio-bar-height);
}

.case-study-visuals {
  flex: 1 1 0%;
  display: flex;
  flex-direction: column;
  gap: var(--studio-gap);
  min-width: 0;
  padding: var(--studio-gap);
  transition-property: width;
  transition-duration: 800ms;
  transition-timing-function: cubic-bezier(0.86, 0, 0.07, 1);
}

.case-study-visuals > p {
  margin: 0;
}

.case-study-visuals img,
.case-study-visuals video,
.case-study-visuals .bd-video {
  width: 100%;
  display: block;
}

/* -- Visual grid (side-by-side media) -- */

.case-study-grid {
  display: grid;
  gap: var(--studio-gap);
}

.case-study-grid[data-cols="2"] { grid-template-columns: repeat(2, 1fr); }
.case-study-grid[data-cols="3"] { grid-template-columns: repeat(3, 1fr); }

.case-study-grid img,
.case-study-grid video,
.case-study-grid .bd-video,
.case-study-grid .bg-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* -- Media wrapper (placeholder + scroll-reveal container) -- */

.cs-media {
  position: relative;
  overflow: hidden;
  background-color: var(--background-faded);
  border-radius: var(--radius-s);
}

.cs-media::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px;
  border: 2px solid var(--border-primary);
  border-top-color: transparent;
  border-radius: 50%;
  animation: cs-spin 0.8s linear infinite;
  opacity: 0.4;
  pointer-events: none;
}

@keyframes cs-spin {
  to { transform: rotate(360deg); }
}

.cs-media img,
.cs-media video,
.cs-media .bd-video {
  position: relative;
  z-index: 1;
  width: 100%;
  display: block;
}

.case-study-grid .cs-media {
  height: 100%;
}

.case-study-grid .cs-media img,
.case-study-grid .cs-media video,
.case-study-grid .cs-media .bg-video {
  height: 100%;
  object-fit: cover;
}

@media (prefers-reduced-motion: reduce) {
  .cs-media::after { animation: none; }
}

.case-study-content {
  width: 0;
  height: 0;
  max-width: 50%;
  opacity: 0;
  overflow: clip;
  display: flex;
  flex-direction: column;
  transition-property: width, opacity;
  transition-duration: 800ms, 200ms;
  transition-timing-function: cubic-bezier(0.86, 0, 0.07, 1), ease-out;
  transition-delay: 0ms, 0ms;
}

.case-study-wrapper.is-info-open .case-study-content {
  width: 50%;
  height: auto;
  opacity: 1;
  transition-delay: 0ms, 200ms;
}

.case-study-content-inner {
  position: sticky;
  top: 0;
  padding: var(--studio-gap) var(--studio-gap) var(--space-8xl) var(--studio-gap);
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  max-width: 36rem;
  margin: 0 auto;
}

/* -- Info panel typography -- */

.case-study-content-inner h2 {
  margin: 0;
}

.case-study-content-inner h3 {
  margin: 0;
}

.case-study-content-inner h4 {
  margin: 0;
}

.case-study-content-inner p {
  color: var(--text-secondary);
  line-height: var(--line-height-l);
}

.case-study-content-inner ul {
  padding-left: var(--space-l);
  color: var(--text-secondary);
  line-height: var(--line-height-l);
}

/* -- Case study mobile -- */

@container main-content (max-width: 768px) {
  .case-study-header [data-grid] > .block {
    grid-column: 1 / -1;
  }

  .case-study-header-actions {
    justify-self: stretch;
  }

  .case-study-header-actions .case-study-toggle {
    width: 100%;
  }

  .case-study-body {
    flex-direction: column;
    scroll-margin-top: calc(var(--mobile-bar-height) + var(--studio-bar-height));
  }

  .case-study-content {
    order: -1;
    width: 100%;
    height: auto;
    max-width: 100%;
    max-height: 0;
    transition-property: max-height, opacity;
    transition-duration: 800ms, 200ms;
    transition-timing-function: cubic-bezier(0.86, 0, 0.07, 1), ease-out;
  }

  .case-study-wrapper.is-info-open .case-study-content {
    width: 100%;
    max-height: 200vh;
    opacity: 1;
  }

  .case-study-content-inner {
    position: static;
    max-height: none;
  }

  .case-study-grid[data-cols="2"],
  .case-study-grid[data-cols="3"] {
    grid-template-columns: 1fr;
  }
}


/* -- Related work slider -- */



.case-study-slider:empty { display: none; }

.case-study-slider {
  overflow: hidden;
  width: 100%;
  padding: var(--space-2xl) 0;
 }

.case-study-slider-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2xl) var(--space-xl);
    border-top: var(--border-s) solid var(--border-faded);

}

.case-study-slider-title {
  font-size: var(--title-size);
  font-weight: var(--title-weight);
  line-height: var(--title-leading);
  letter-spacing: var(--title-tracking);
  margin: 0;
}

.case-study-splide {
  width: 100%;
}
.case-study-track {
  width: 100%;
}

.case-study-slide .post {
  height: 100%;
}

.case-study-arrow.splide__arrow--prev svg {
    transform: none !important;
}


/* ------ BACKDROP (mobile drawer scrim) ------ */

.sidebar-backdrop {
  position: fixed;
  inset: 0;
  background: var(--background-modal, var(--black-alpha-50));
  z-index: var(--z-backdrop);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-s) var(--ease-out);
}

body.is-drawer-open .sidebar-backdrop,
body.is-overlay-open .sidebar-backdrop {
  opacity: 1;
  pointer-events: auto;
}


/* ============================================================
   TABLET (769–1079px) — 64px rail + 400px overlay
   ============================================================ */

/* Tablet keeps the sidebar inline as a 64px rail. The rail burger opens it as
   a 400px overlay (NOT full width) with a backdrop. The overlay reuses the
   base desktop flex column — nav pinned, inner scrolls, footer pinned — so the
   close button + footer stay fixed while the work list scrolls. */
@media (min-width: 769px) and (max-width: 1079px) {
  .layout,
  body.is-sidebar-collapsed .layout {
    grid-template-columns: var(--sidebar-collapsed-width) 1fr;
  }

  .sidebar {
    width: var(--sidebar-collapsed-width);
  }

  /* Rail shows: mini logo + burger + (empty inner spacer) + footer */
  .sidebar-logo-mini {
    display: flex;
  }
  .sidebar-burger {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-s) 0;
  }

  /* Hide full-width content in the rail (inner stays as the flex spacer that
     pushes the footer to the bottom) */
  .sidebar-header,
  .intro-block-wrap,
  .sidebar-slot {
    display: none;
  }

  .sidebar-footer {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
  }
  .footer-collapse-toggle {
    display: none;
  }

  /* Chrome aligns with the 64px rail (no mobile bar at this size). */
  .page-header,
  .page-overlay,
  body.is-animating [data-studio-role="leave"] {
    left: var(--sidebar-collapsed-width);
  }

  /* -- Overlay (burger tapped) -- */
  body.is-overlay-open .sidebar {
    width: var(--sidebar-width);
    position: fixed;
    inset: 0 auto 0 0;
    z-index: var(--z-drawer);
    /* inherits the base flex column: nav flex-shrink:0 (pinned top),
       .sidebar-inner flex:1 1 0 overflow-y:auto (scrolls), footer
       flex-shrink:0 (pinned bottom). */
  }
  body.is-overlay-open .sidebar-logo-mini,
  body.is-overlay-open .sidebar-burger {
    display: none;
  }
  body.is-overlay-open .sidebar-header {
    display: flex;
  }
  body.is-overlay-open .intro-block-wrap {
    display: block;
  }
  body.is-overlay-open .sidebar-slot {
    display: block;
  }
  body.is-overlay-open .sidebar-footer {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
  /* Vertical nav in the overlay — larger tap targets */
  body.is-overlay-open .nav {
    flex-direction: column;
    gap: 0;
  }
  body.is-overlay-open .nav-link {
    padding: var(--space-m) var(--studio-gap);
    border-bottom: var(--border-s) solid var(--border-faded);
  }
  /* Close button pinned top-right — position:absolute against the fixed
     overlay stays put while the inner scrolls under it. */
  body.is-overlay-open .sidebar-close-row {
    display: block;
    position: absolute;
    top: var(--space-s);
    right: var(--space-s);
    z-index: 2;
  }

  /* Footer collapse toggle never applies on tablet (no inline collapse). */
  body.is-overlay-open .footer-collapse-toggle {
    display: none;
  }
}


/* ============================================================
   MOBILE (≤768px) — hidden sidebar + mobile bar + drawer
   ============================================================ */

@media (max-width: 768px) {
  .layout,
  body.is-sidebar-collapsed .layout {
    grid-template-columns: 1fr;
    grid-template-rows: var(--mobile-bar-height) 1fr;
    grid-template-areas:
      "mobilebar"
      "main";
  }

  /* Mobile bar: sticky at the top, z-index ABOVE the drawer so the logo +
     close (X) stay visible and the drawer content scrolls underneath it. */
  .mobile-bar {
    display: flex;
    grid-area: mobilebar;
    position: sticky;
    top: 0;
  }

  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--mobile-drawer-width);
    height: 100dvh;
    z-index: var(--z-drawer);
    transform: translateX(-100%);
    transition: transform var(--duration-s) var(--ease-out);
    overflow-y: auto;
    overflow-x: hidden;
    /* Offset the scroll content below the fixed mobile bar; as the user
       scrolls, nav + intro + work slide UP under the opaque bar. */
    padding-top: var(--mobile-bar-height);
  }

  /* Whole column scrolls as one — only the footer pins. */
  .sidebar-inner {
    flex: 0 0 auto;
    overflow: visible;
  }

  /* Footer pinned to the bottom while the rest scrolls behind it. Its opaque
     bg occludes content scrolling underneath. */
  .sidebar-footer {
    position: sticky;
    bottom: 0;
  }

  .sidebar::after {
    display: none;
  }

  body.is-drawer-open .sidebar {
    transform: translateX(0);
  }

  /* Rail-only triggers never show on mobile (the hamburger morph closes). */
  .sidebar-logo-mini,
  .sidebar-burger,
  .sidebar-close-row,
  body.is-sidebar-collapsed .sidebar-logo-mini,
  body.is-sidebar-collapsed .sidebar-burger {
    display: none;
  }

  /* Drawer always shows full content even if .is-sidebar-collapsed lingers. */
  body.is-sidebar-collapsed .sidebar {
    width: var(--mobile-drawer-width);
  }
  body.is-sidebar-collapsed .sidebar-inner {
    align-items: stretch;
  }
  body.is-sidebar-collapsed .sidebar-intro,
  body.is-sidebar-collapsed .sidebar-footer p,
  body.is-sidebar-collapsed .sidebar-header,
  body.is-sidebar-collapsed .intro-block-wrap,
  body.is-sidebar-collapsed .intro-block,
  body.is-sidebar-collapsed .sidebar-about,
  body.is-sidebar-collapsed .sidebar-slot {
    display: revert;
    opacity: 1;
    visibility: visible;
  }

  /* Vertical nav for large touch targets. The cosmetic treatment (large
     rows, page numbers, Pages-above label, dropped logo, mobile Home link)
     is shared with the tablet overlay — see the ≤1079px block below. */
  .nav {
    flex-direction: column;
    gap: 0;
  }
  .nav-link {
    padding: var(--space-m) var(--studio-gap);
    border-bottom: var(--border-s) solid var(--border-faded);
  }

  .nav-link:first-child {
    border-top: var(--border-s) solid var(--border-faded);

  }  

  /* The footer collapse toggle has no role on mobile. */
  [data-sidebar-collapse] {
    display: none;
  }

  /* Lock body scroll while the drawer is open */
  body.is-drawer-open {
    overflow: hidden;
  }
}


/* ============================================================
   DRAWER + TABLET-OVERLAY NAV TREATMENT (≤1079px)
   Shared cosmetic layer for the vertical nav shown in BOTH the
   mobile drawer (≤768) and the tablet overlay (769–1079). Desktop
   (≥1080) keeps the compact horizontal nav. The vertical layout +
   row padding/dividers live in each context's own block above;
   this block adds the large type, page numbers, Pages-above label,
   spacing, dropped logo, and Home link.
   ============================================================ */
@media (max-width: 1079px) {
  /* Home + Playground appear in the vertical numbered list (both hidden on the
     compact desktop bar — Home because the logo links home, Playground by request). */
  .nav-link-home,
  .nav-link-playground {
    display: inline-flex;
  }

  /* Pages label sits ABOVE the links; breathing room below the nav before
     the Work list. Drop the header's own divider so the last link's border
     is the single closing line. */
  .sidebar-header {
    flex-direction: column;
    border-bottom: none;
    margin-bottom: var(--space-xl);
  }
  .nav-pages-label {
    display: block;
  }

  /* Large, mixed-case, left-aligned rows with a muted page number on the right */
  .nav {
    counter-reset: nav-counter;
  }
  .nav-link {
    justify-content: space-between;   /* label left, number right */
    text-transform: none;             /* mixed case (was uppercase) */
    font-size: var(--font-3xl);
    font-weight: var(--font-weight-regular);
    white-space: normal;              /* allow reflow at narrow widths / 200% zoom */
    counter-increment: nav-counter;
    align-items: end;
  }
  .nav-link-num {
    display: block;
    font-size: var(--label-size);
    font-weight: var(--font-weight-regular);
    color: var(--text-faded);
  }
  .nav-link-num::before {
    content: counter(nav-counter, decimal-leading-zero);
  }
}




/* ------ PAGE CLOSE BUTTON (X) ------ */

/* Studio close-btn — extends the .button.transparent variant with a high-contrast icon color */
.close-btn {
  --button-color: var(--text-primary);
  --icon-size: 1.3rem;
}

.close-btn-label {
  font-family: var(--font-tertiary);
  font-size: var(--text-size-s);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-l);
  color: var(--text-faded);
}

/* Disable case study layout transitions during page transitions.
   These transitions are for user interactions (info panel toggle),
   not for Barba page animations. Without this, the 800ms layout
   transition fires during the page transition and creates stutter. */
body.is-animating .case-study-visuals,
body.is-animating .case-study-content {
  transition: none;
}

@media (max-width: 768px) {
  .close-btn-label {
    display: none;
  }
  /* Label hides → restore square padding so the button matches other icon-only buttons */
  .close-btn {
    --button-padding-x: var(--button-padding-y);
  }
}


/* ------ CONTACT FORM ------ */

.contact-block {
  max-width: 790px;
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  padding: var(--space-3xl) 0;
}

.contact-headline {
  font-weight: var(--headline-weight);
  font-size: var(--headline-size);
  line-height: var(--headline-leading);
}

/* -- Form layout -- */

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xl);
  margin-top: var(--space-2xl);
  position: relative;
}

.contact-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.contact-label {
  font-family: var(--font-primary);
  font-size: var(--body-size);
  color: var(--text-primary);
  font-weight: var(--font-weight-regular);
  white-space: nowrap;
  margin-bottom: 0;
}

/* -- Inline label + input on one line (desktop) -- */

.contact-inline {
  display: flex;
  align-items: center;
  gap: var(--space-m);
}

.contact-inline input,
.contact-inline .contact-email-wrap {
  flex: 1;
  min-width: 0;
}

@container main-content (max-width: 768px) {
  .contact-inline {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-s);
  }
}

/* -- Bottom-border-only inputs (name + email) -- */

.contact-inline input,
.contact-email-wrap input {
  border-top: 0;
  border-left: 0;
  border-right: 0;
  border-radius: 0;
  background-color: transparent;
  border-color: var(--border-primary);
  border-bottom-width: var(--border-s);
}

/* Mouse/programmatic focus: thicken the underline + keep the subtle fill. */
.contact-inline input:focus,
.contact-email-wrap input:focus {
  background-color: var(--input-background);
  border-bottom-width: var(--border-m);
  border-bottom-color: var(--text-primary);
  outline: none;
}

/* Keyboard focus: the studio-standard visible ring. */
.contact-inline input:focus-visible,
.contact-email-wrap input:focus-visible {
  outline: var(--border-m) solid var(--text-primary);
  outline-offset: 2px;
}

/* Keep the design-system red error ring on a keyboard-focused errored field. */
.contact-inline input.is-error:focus-visible,
.contact-email-wrap input.is-error:focus-visible {
  outline-color: var(--status-danger);
}

/* -- Chip groups (button-based selectable chips) -- */

.contact-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
}

.contact-chips .button {
  flex: 1 1 auto;
  padding-left: 0;
  padding-right: 0;
}

.contact-chips .button.is-selected {
  --button-bg: var(--text-primary);
  --button-text-color: var(--background-primary);
  --button-border: var(--text-primary);
}

.contact-chips .button.is-selected:hover {
  background-color: var(--text-primary) !important;
  color: var(--background-primary) !important;
  border-color: var(--text-primary) !important;
}

.contact-chips .button .svg-icn {
  display: none;
}

.contact-chips .button.is-selected .svg-icn {
  display: inline-flex;
}

@container main-content (max-width: 768px) {
  /* Services: single column */
  .contact-chips[role="group"] {
    flex-direction: column;
  }

  /* Budget: two columns */
  .contact-chips[role="radiogroup"] .button {
    flex: 1 1 calc(50% - var(--space-m) / 2);
  }
}

/* -- Textarea -- */

.contact-form textarea {
  resize: vertical;
  min-height: var(--space-13xl);
}

/* -- Email validation indicator -- */

.contact-email-wrap {
  position: relative;
}

.contact-email-wrap input {
  padding-right: var(--space-2xl);
}

.contact-email-tick {
  position: absolute;
  right: var(--space-m);
  top: 50%;
  transform: translateY(-50%);
  color: var(--status-success);
  font-size: var(--text-size-l);
  pointer-events: none;
}

/* Error states handled by design system (.is-error, .is-error:focus) */

/* -- Submit area -- */

.contact-actions {
  display: flex;
}

.contact-actions .button {
  width: 100%;
}

.contact-error-callout {
  margin: 0;
}

/* -- Page wrapper -- */

.contact-wrapper {
  overflow: hidden;
}

/* -- Form state toggle -- */

.contact-form-state .contact-success {
  display: none;
}

.contact-form-state.is-submitted .contact-form {
  display: none;
}

.contact-form-state.is-submitted .contact-success {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  margin-top: var(--space-2xl);
  padding-top: var(--space-2xl);
}

.contact-success-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  padding: var(--space-2xl);
  border: var(--border-s) solid var(--border-faded);
}

.contact-success-title {
  margin: 0;
}

.contact-success-body {
  margin: 0;
  color: var(--text-secondary);
}

/* -- Post-submit recommendations: 2-column editorial grid -- */
/* Shared .post[data-feed-layout="editorial"] cards; eyebrow label spans both columns. */

.contact-recommendations {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--feed-gap, var(--space-l));
  margin-top: var(--space-l);
}

.contact-recommendations-label {
  grid-column: 1 / -1;
  margin: 0;
}

.contact-recommendations .post-item {
  margin-bottom: 0;
}

@container main-content (max-width: 768px) {
  .contact-recommendations {
    grid-template-columns: 1fr;
  }
}


/* ------ SKIP LINK ------ */

.skip-link {
  position: absolute;
  top: var(--space-s);
  left: var(--space-s);
  z-index: 100;
  padding: var(--space-s) var(--space-m);
  background: var(--text-primary);
  color: var(--background-primary);
  font-family: var(--font-tertiary);
  text-decoration: none;
  /* border-radius: var(--radius-s); */
  transform: translateY(-150%);
  transition: transform var(--duration-m) var(--ease-in-out);
}

.skip-link:focus-visible {
  transform: translateY(0);
  outline: none;
}


/* ------ FOOTER ------ */
/* Dark surface scoped to the footer via [data-theme="dark"]. The design system
   flips --background-primary, --text-primary, --text-faded, --border-color
   inside this element only, so it remains dark regardless of the global theme. */

.footer-wrapper {
  background-color: var(--neutral-950);
  color: var(--text-primary);
  padding: 0 var(--space-2xl);
  border-radius: var(--radius-s);
}

/* -- Top grid: links / brand / contact -- */

.footer-grid {
  padding-top: var(--space-3xl);
  padding-bottom: var(--space-2xl);
  align-items: end;
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.footer-col-end {
  text-align: right;
}

.footer-label {
  color: var(--text-faded);
}

.footer-nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.footer-link {
  color: var(--text-primary);
  text-decoration: none;
  transition: color var(--duration-xs) var(--ease-out);
}

.footer-link:hover,
.footer-link:focus-visible {
  color: var(--text-secondary);
}

/* -- Brand block (centered logo + tagline) -- */

.footer-brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-l);
  text-align: center;
  padding: var(--space-5xl) 0;
}

.footer-logo {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  color: var(--text-primary);
}

a.footer-logo:hover {
  color: var(--text-secondary);

}

.footer-logo .svg-logo {
  display: block;
  width: 100%;
  aspect-ratio: 1050 / 505;
  max-width: 300px;
}

.footer-tagline {
  margin: 0;
  font-family: var(--font-tertiary);
  font-size: 170%;
  color: var(--text-primary);
}

/* -- Bottom row: copyright + legal -- */

.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-m) var(--space-l);
  padding: var(--space-2xl) 0;
  border-top: var(--border-s) solid var(--border-faded);
  font-size: var(--text-size-s);
  color: var(--text-faded);
}

.footer-copyright {
  margin: 0;
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-l);
}

.footer-legal-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--duration-xs) var(--ease-out);
}

.footer-legal-link:hover,
.footer-legal-link:focus-visible {
  color: var(--text-primary);
}

/* -- Responsive: stack columns on narrow viewports -- */
/* The design system's mobile reset ([data-grid] > *) has lower specificity than
   the data-col-start rules, so we re-stack the footer blocks explicitly here. */

@container main-content (max-width: 768px) {
  .footer-grid > .block {
    grid-column: 1 / -1;
  }

  .footer-col-end {
    text-align: left;
  }

  .footer-bottom {
    justify-content: flex-start;
  }
}


/* ------ ERROR PAGE (404) ------ */

.error-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - var(--mobile-bar-height) - (var(--studio-gap) * 2));
  padding: var(--space-3xl) var(--studio-gap);
  background-color: var(--black-alpha-3);
  border-radius: var(--radius-m);
}

.error-page__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-l);
  max-width: 44rem;
  width: 100%;
}

.error-page__code {
  font-family: var(--font-tertiary);
  font-size: var(--font-10xl);
  font-weight: var(--font-weight-bold);
  line-height: 1;
  color: var(--text-faded);
  margin: 0;
  animation: error-code-fade var(--motion-page-fade-duration) var(--motion-page-fade-easing) both;
}

.error-page-heading {
  font-size: var(--headline-size);
  line-height: 1.05;
  color: var(--text-primary);
  margin: 0;
  max-width: 20ch;
}

.error-page__lede {
  font-size: var(--text-size-l);
  line-height: 1.4;
  color: var(--text-secondary);
  margin: 0;
  max-width: 60ch;
}

.error-page__actions {
  margin-top: var(--space-s);
}

.error-page__suggestions {
  width: 100%;
  margin-top: var(--space-xl);
  padding-top: var(--space-l);
  border-top: var(--border-s) solid var(--border-secondary);
}

.error-page-suggestions-label {
  color: var(--text-secondary);
  margin: 0 0 var(--space-m) 0;
}

.error-page__suggestions ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s) var(--space-l);
}

.error-page__suggestions a {
  font-size: var(--text-size-l);
  color: var(--text-primary);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  transition: color var(--duration-m) var(--ease-in-out);
}

.error-page__suggestions a:hover {
  color: var(--text-secondary);
}

@keyframes error-code-fade {
  from { opacity: 0; transform: translateY(0.25rem); }
  to   { opacity: 1; transform: translateY(0); }
}

@container main-content (max-width: 768px) {
  .error-page__code { font-size: var(--font-8xl); }
}


/* ------ SERVICES PAGE ------ */

/* -- Section 1: page header -- */

.services-divider {
  height: 1px;
  background: var(--border-faded);
  width: 100%;
}

/* -- Section 2: services content (inside accordion panels) -- */

.services-sub-wrap {
  padding: var(--space-5xl) 0;
}

:is(.service-description, .capability-description) p {
  margin: 0 0 var(--space-m);
}

:is(.service-description, .capability-description) p:last-child { margin-bottom: 0; }

.service-stat {
  padding: var(--space-l);
  background: var(--background-faded);
  border-radius: var(--radius-m);
  border: var(--border-s) solid var(--border-faded);
}

.service-stat-headline {
  font-size: var(--subline-size);
  line-height: var(--line-height-m);
  color: var(--text-primary);
  margin: 0 0 var(--space-s);
}

.service-stat-source {
  font-family: var(--font-quaternary, monospace);
  font-size: var(--label-size);
  letter-spacing: var(--letter-spacing-m);
  text-transform: uppercase;
  color: var(--text-faded);
  margin: 0;
}

/* -- Capabilities accordion (also styles legacy `.services-accordion`) -- */

:is(.services-accordion, .capabilities-accordion) [data-depth="0"] > .accordion-header {
  padding: var(--space-2xl) var(--studio-gap);
}


:is(.services-accordion, .capabilities-accordion) [data-depth="1"] > .accordion-header {
  padding: var(--space-l);
}

:is(.services-accordion, .capabilities-accordion) .accordion-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
}

/* Parent items */
:is(.services-accordion, .capabilities-accordion) [data-depth="0"] > .accordion-header .accordion-title {
  font-family: var(--title-family);
}

/* Child items */

:is(.services-accordion, .capabilities-accordion) [data-depth="1"] .accordion-header {
  font-size: var(--text-size-l);
}

/* -- Capability formats (inner accordion of formats per capability) -- */


:is(.formats-section, .capability-formats) .accordion-item:last-child {
  border-bottom: none;
}
:is(.formats-section, .capability-formats) .accordion-item:first-child {


  border-top: var(--border-s) solid var(--border-faded);
}

:is(.formats-section, .capability-formats) .accordion {
  border-top: none;
}

/* -- Mini case tile (inverted) -- */

.mini-case {
  display: block;
  padding: var(--space-l);
  background: var(--text-primary);
  color: var(--background-primary);
  border-radius: var(--radius-m);
  text-decoration: none;
  transition: transform var(--duration-s) var(--ease-out);
}

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

.mini-case-label {
  color: var(--background-primary);
  opacity: 0.7;
  margin: 0 0 var(--space-s);
}

.mini-case-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  border-bottom: var(--border-s) solid currentColor;
  padding-bottom: 2px;
}

/* -- Inline CTA inside each service panel -- */

.service-cta {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  padding: var(--space-l) 0 0;
  border-top: var(--border-s) solid var(--border-faded);
}

.service-cta p {
  font-size: var(--text-size-l);
  color: var(--text-primary);
  margin: 0;
}

/* -- Section 3: how we work (process steps) -- */

.process-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-xl);
}

@container main-content (max-width: 768px) {
  .process-steps {
    grid-template-columns: 1fr;
  }
}

.process-step-title {
  margin: 0 0 var(--space-s);
font-size: var(--text-size-xl);

}

.process-step-desc {
  line-height: var(--line-height-xl);
  color: var(--text-secondary);
  margin: 0;
}



/* 12-col grid — opt-in via presence of data-grid (works on any element).
   container-type establishes a containment context so --col-unit can
   resolve against the grid's own width (100cqi), letting children
   compose padding/margin equal to one grid column. */
[data-grid] {
  display: grid !important;
  container-type: inline-size;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--studio-gap);
  row-gap: var(--space-xl);
  --col-unit: calc((100cqi - 11 * var(--studio-gap)) / 12);
}

[data-grid] > * {
  grid-column: 1 / -1;
}

[data-grid] > [data-col-span="1"]  { grid-column-end: span 1; }
[data-grid] > [data-col-span="2"]  { grid-column-end: span 2; }
[data-grid] > [data-col-span="3"]  { grid-column-end: span 3; }
[data-grid] > [data-col-span="4"]  { grid-column-end: span 4; }
[data-grid] > [data-col-span="5"]  { grid-column-end: span 5; }
[data-grid] > [data-col-span="6"]  { grid-column-end: span 6; }
[data-grid] > [data-col-span="7"]  { grid-column-end: span 7; }
[data-grid] > [data-col-span="8"]  { grid-column-end: span 8; }
[data-grid] > [data-col-span="9"]  { grid-column-end: span 9; }
[data-grid] > [data-col-span="10"] { grid-column-end: span 10; }
[data-grid] > [data-col-span="11"] { grid-column-end: span 11; }
[data-grid] > [data-col-span="12"] { grid-column-end: span 12; }

[data-grid] > [data-col-start="1"]  { grid-column-start: 1; }
[data-grid] > [data-col-start="2"]  { grid-column-start: 2; }
[data-grid] > [data-col-start="3"]  { grid-column-start: 3; }
[data-grid] > [data-col-start="4"]  { grid-column-start: 4; }
[data-grid] > [data-col-start="5"]  { grid-column-start: 5; }
[data-grid] > [data-col-start="6"]  { grid-column-start: 6; }
[data-grid] > [data-col-start="7"]  { grid-column-start: 7; }
[data-grid] > [data-col-start="8"]  { grid-column-start: 8; }
[data-grid] > [data-col-start="9"]  { grid-column-start: 9; }
[data-grid] > [data-col-start="10"] { grid-column-start: 10; }
[data-grid] > [data-col-start="11"] { grid-column-start: 11; }
[data-grid] > [data-col-start="12"] { grid-column-start: 12; }

/* Named layout patterns — :nth-child column placement on a data-grid.
   Apply data-layout="split|feature|feature-alt|headline|thirds|masthead|spotlight"
   to the [data-grid] parent. Children stay content-agnostic; the parent
   owns column positions.

   Gated on @container main-content (min-width:960px) — the SAME measurement
   source as the collapse rule below — so the named placements never fight
   the mobile collapse. They have higher specificity than the base
   [data-grid] > * rule, so without this gate they'd hold position even at
   1-column grids. Measuring the content area (not the viewport) is what
   makes them flip correctly when the sidebar narrows the content. */
@container main-content (min-width: 960px) {
  /* split: 6 · 6 — two equal halves */
  [data-grid][data-layout="split"]       > :nth-child(1) { grid-column: 1 / span 6; }
  [data-grid][data-layout="split"]       > :nth-child(2) { grid-column: 7 / span 6; }

  /* feature: 4 · 8 — minor left, major right */
  [data-grid][data-layout="feature"]     > :nth-child(1) { grid-column: 1 / span 4; }
  [data-grid][data-layout="feature"]     > :nth-child(2) { grid-column: 5 / span 8; }

  /* feature-alt / headline: 8 · 4 — major left, minor right.
     headline is a semantic alias used on page/section headers with a
     compact action area. */
  [data-grid][data-layout="feature-alt"] > :nth-child(1),
  [data-grid][data-layout="headline"]    > :nth-child(1) { grid-column: 1 / span 8; }
  [data-grid][data-layout="feature-alt"] > :nth-child(2),
  [data-grid][data-layout="headline"]    > :nth-child(2) { grid-column: 9 / span 4; }

  /* thirds: 4 · 4 · 4 — three equal columns */
  [data-grid][data-layout="thirds"]      > :nth-child(1) { grid-column: 1 / span 4; }
  [data-grid][data-layout="thirds"]      > :nth-child(2) { grid-column: 5 / span 4; }
  [data-grid][data-layout="thirds"]      > :nth-child(3) { grid-column: 9 / span 4; }

  /* masthead / spotlight: 3 · 6 · 3 — center-dominant with symmetric
     flankers. spotlight is the alias for product-feature layouts. */
  [data-grid][data-layout="masthead"]    > :nth-child(1),
  [data-grid][data-layout="spotlight"]   > :nth-child(1) { grid-column: 1 / span 3; }
  [data-grid][data-layout="masthead"]    > :nth-child(2),
  [data-grid][data-layout="spotlight"]   > :nth-child(2) { grid-column: 4 / span 6; }
  [data-grid][data-layout="masthead"]    > :nth-child(3),
  [data-grid][data-layout="spotlight"]   > :nth-child(3) { grid-column: 10 / span 3; }
}

/* Mobile collapse: below 960 every [data-grid] becomes a single column.
   data-col-span / data-col-start / named layouts all stack as source
   order. --col-unit resets to 0 so any padding/margin derived from
   it goes away on mobile.

   max-width is 959.98 (not 960) so this never matches at the SAME content
   width as the named-layout min-width:960 rule above. At exactly 960px of
   content (e.g. a 1360px viewport with the 400px sidebar open) both rules
   would otherwise fire — collapsing the grid to 1fr while still positioning
   children at grid-column spans — and the layout breaks. The sub-pixel gap
   hands 960px cleanly to the named layouts.

   data-stack-order optionally promotes children to a position earlier
   than their source order — visual-only via CSS `order`. RULE: only
   apply to children that contain NO interactive elements (links,
   buttons, inputs, details, [tabindex], or a heading starting a new
   section). DOM and tab order are unchanged. See studio/README.md. */
@container main-content (max-width: 959.98px) {
  [data-grid] {
    grid-template-columns: 1fr;
    --col-unit: 0px;
  }
  [data-grid] > [data-stack-order="1"] { order: -3; }
  [data-grid] > [data-stack-order="2"] { order: -2; }
  [data-grid] > [data-stack-order="3"] { order: -1; }
}/* -- Section 4: closing CTA (tabbed, dark) -- */

:is(.services-cta, .about-cta) {
  background: var(--text-primary);
  color: var(--background-primary);
}

.cta-tabs {
  display: flex;
  gap: 0;
  border-top: var(--border-s) solid var(--border-faded);
  border-bottom: var(--border-s) solid var(--border-faded);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.cta-tabs::-webkit-scrollbar { display: none; }

.cta-tab {
  padding: var(--space-l) var(--space-m);
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1.5px;
  font-family: var(--font-quaternary, monospace);
  font-size: var(--label-size);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--letter-spacing-l);
  text-transform: uppercase;
  color: var(--background-primary);
  opacity: 0.5;
  white-space: nowrap;
  flex: 1;
  text-align: center;
  min-width: max-content;
  cursor: pointer;
  transition: opacity var(--duration-s) var(--ease-out),
              border-color var(--duration-s) var(--ease-out);
}

.cta-tab:hover { opacity: 0.85; }

.cta-tab.is-active {
  opacity: 1;
  border-bottom-color: var(--background-primary);
}

.cta-panel {
  padding: var(--space-3xl) 0 0;
  text-align: center;
}

.cta-panel[hidden] { display: none; }

.cta-panel-title {
  font-size: var(--font-5xl);
  line-height: var(--line-height-m);
  color: var(--background-primary);
  margin: 0 auto var(--space-l);
  max-width: 16ch;
  letter-spacing: -0.01em;
}

.cta-panel-desc {
  font-size: var(--text-size-l);
  line-height: var(--line-height-l);
  color: var(--background-primary);
  opacity: 0.85;
  margin: 0 auto var(--space-2xl);
  max-width: 40ch;
}

.button.is-light {
  --button-bg: var(--background-primary);
  --button-border: var(--background-primary);
  --button-text-color: var(--text-primary);
}


/* ------ REDUCED MOTION ------ */

@media (prefers-reduced-motion: reduce) {
  .layout,
  .sidebar,
  .sidebar-intro,
  .sidebar-footer p,
  .sidebar-backdrop,
  .nav-link,
  [data-sidebar-collapse],
  .post,
  .close-btn,
  .contact-chips .button,
  .skip-link,
  .error-page__code,
  .sidebar-slot-link,
  .sidebar-slot-link::before {
    transition: none;
    animation: none;
  }
}


/* ------ STYLEGUIDE ------ */

/* -- Styleguide table — combo class on .table .table-full -- */

.table-styleguide th,
.table-styleguide td {
  padding-top: var(--space-l);
  padding-bottom: var(--space-l);
  padding-left: 0;
}

.table-styleguide th {
  padding-top: var(--space-s);
  padding-bottom: var(--space-s);
}

.table-styleguide th:first-child,
.table-styleguide td:first-child {
  width: 180px;
  padding-right: var(--space-l);
  vertical-align: top;
}

.table-styleguide td:first-child code {
  font-size: var(--label-size);
  color: var(--text-secondary);
}

.table-styleguide td:last-child > *:first-child {
  margin-top: 0;
}

.table-styleguide td:last-child > *:last-child {
  margin-bottom: 0;
}

/* -- Token copy — inline copy button for code chips in styleguide tables -- */

.token-copy {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  position: relative;
}

.token-copy code {
  transition: color var(--duration-2xs) var(--ease-out), background var(--duration-2xs) var(--ease-out);
}

.token-copy:hover code {
  color: var(--text-primary);
  background: color-mix(in srgb, var(--text-primary), var(--alpha-15));
}

.token-copy.is-copied code {
  color: var(--status-success);
}

.token-copy::after {
  content: "";
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  flex-shrink: 0;
  background-color: currentColor;
  mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 14C8 15.1046 8.89543 16 10 16H18C19.1046 16 20 15.1046 20 14V6C20 4.89543 19.1046 4 18 4H10C8.89543 4 8 4.89543 8 6V14ZM6 18V2H22V18H6ZM2 22V6H4V20H18V22H2Z'/%3E%3C/svg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 14C8 15.1046 8.89543 16 10 16H18C19.1046 16 20 15.1046 20 14V6C20 4.89543 19.1046 4 18 4H10C8.89543 4 8 4.89543 8 6V14ZM6 18V2H22V18H6ZM2 22V6H4V20H18V22H2Z'/%3E%3C/svg%3E");
  mask-size: contain;
  -webkit-mask-size: contain;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  opacity: 0.4;
  transition: opacity var(--duration-2xs) var(--ease-out);
  pointer-events: none;
}

.token-copy:hover::after {
  opacity: 0.8;
}

.token-copy.is-copied::after {
  opacity: 1;
  color: var(--status-success);
  mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9.54998 18L3.84998 12.3L5.27498 10.875L8.13576 13.7358C8.91681 14.5168 10.1831 14.5168 10.9642 13.7358L18.725 5.97501L20.15 7.40001L9.54998 18Z'/%3E%3C/svg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9.54998 18L3.84998 12.3L5.27498 10.875L8.13576 13.7358C8.91681 14.5168 10.1831 14.5168 10.9642 13.7358L18.725 5.97501L20.15 7.40001L9.54998 18Z'/%3E%3C/svg%3E");
}

/* -- Color row — swatch with hex/CSS copy buttons -- */

.color-row {
  display: flex;
  align-items: center;
  padding: var(--space-xl);
  font-size: var(--text-size-l);
  font-weight: var(--font-weight-medium);
  cursor: default;
  position: relative;
  height: 80px;
}

.color-row-name {
  pointer-events: none;
}

.color-row.is-text-dark .color-row-name,
.color-row.is-text-dark .color-copy-btn {
  color: var(--black);
}

.color-row.is-text-light .color-row-name,
.color-row.is-text-light .color-copy-btn {
  color: var(--white);
}

.color-row-actions {
  display: none;
  gap: var(--space-s);
  margin-left: auto;
}

.color-row:hover .color-row-actions,
.color-row:focus-within .color-row-actions {
  display: flex;
}

.color-copy-btn {
  color: inherit;
  background: none;
  border: none;
  font-size: var(--text-size-s);
  font-weight: var(--font-weight-semi-bold);
  cursor: pointer;
  padding: var(--space-2xs) var(--space-s);
}

/* State swap: default visible, copied hidden — toggles on .is-copied */
.color-copy-btn .copy-btn-default { display: inline-flex; align-items: center; gap: var(--space-s); }
.color-copy-btn .copy-btn-copied  { display: none; }
.color-copy-btn.is-copied .copy-btn-default { display: none; }
.color-copy-btn.is-copied .copy-btn-copied  { display: inline-flex; align-items: center; gap: var(--space-s); }

.color-copy-btn:hover {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 2.5px;
}

.sg-eyebrow {
  display: block;
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-faded);
  margin-bottom: var(--space-xs);
}

.sg-section {
  margin-top: var(--space-3xl);
}

.sg-section:first-child {
  margin-top: 0;
}

.sg-note {
  color: var(--text-secondary);
  margin-top: 0;
  margin-bottom: var(--space-l);
}

.sg-toc {
  margin-bottom: var(--space-2xl);
  padding: var(--space-l);
  background: var(--bg-faded-3);
  border-radius: var(--radius-m);
}

.sg-toc ul {
  list-style: none;
  padding: 0;
  margin: var(--space-s) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-l);
}

.sg-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  align-items: center;
}

.sg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-l);
}

.sg-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.sg-swatch {
  width: 100%;
  height: 48px;
  border-radius: var(--radius-s);
  border: var(--border-s) solid var(--border-faded);
}

.sg-spacer {
  height: 24px;
  background: var(--text-faded);
}

.sg-token-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: var(--space-2xs);
  font-size: var(--text-size-s);
}

.sg-token-row code {
  color: var(--text-secondary);
}

.sg-tooltip-demo {
  border-bottom: var(--border-s) dashed var(--text-faded);
  cursor: help;
}

.sg-radius-demo {
  width: 80px;
  height: 80px;
  background: var(--background-faded);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-size-s);
}

.sg-thumb-placeholder {
  background: var(--background-faded);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faded);
  font-family: var(--font-tertiary);
}

/* Styleguide-only — the placeholder has no intrinsic height on its own, so
   give the cursor solo demo thumbs a hoverable box to test the solo cursor. */
.sg-cursor-thumb {
  height: 140px;
  border-radius: var(--radius-m);
}

/* Constrain demo-only components (e.g. post cards in styleguide) */
.sg-demo {
  max-width: 320px;
}

@container main-content (max-width: 768px) {
  .table-styleguide th:first-child,
  .table-styleguide td:first-child {
    width: 120px;
  }
}

/* ------ SPLIT GRID ------ */

.split-grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: var(--space-xl);
  align-items: start;
}

@container main-content (max-width: 768px) {
  .split-grid {
    grid-template-columns: 1fr;
    gap: var(--space-l);
  }
}

/* ------ LOGO TICKER ------ */

.logo-ticker-section {
  overflow: hidden;
  margin-top: var(--space-2xl);
}

.logo-ticker-slide {
  display: flex;
  align-items: center;
}

.logo-ticker-slide svg {
  display: block;
}

/* ------ TICKER (Products → Reporting section) ------ */
/* Auto-scrolling stats ticker. Slides hand-authored in products.html;
   Splide instance mounted by initReportTicker (products.js). */

/* Outer container — clips ticker overflow at the section edges. */

.reporting-headline {
  text-wrap: pretty;
}

.ticker-section {
  overflow: hidden;
  margin-top: var(--space-2xl);
}

/* Slide layout — left-aligned: icon at the top with a wide gap below it,
   then the value, then the label. */
.ticker-slide {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-s);
  background-color: var(--background-faded);
  border-radius: var(--radius-s);
  padding: var(--space-l) var(--space-xl);
}

.ticker-wrapper {
  margin: 0 calc(-1 * var(--studio-gap));
}

/* Big stat — the slide's headline. */
.ticker-value {
  font-size: var(--font-4xl);
  /* font-family: var(--font-tertiary); */
  font-weight: var(--font-weight-medium);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  white-space: nowrap;
  text-align: left;
  margin: 0;
}

/* Caption beneath the value. */
.ticker-label {
  font-size: var(--text-size-s);
  line-height: var(--line-height-m);
  color: var(--text-secondary);
  white-space: nowrap;
  text-align: left;
  margin: 0;
}

/* Larger feature icon, set off from the value by a wide bottom margin.
   .svg-icn base handles centering + aspect-ratio. */
.ticker-icon {
  --icon-size: 1.75rem;
  margin-bottom: var(--space-l);
  color: var(--text-faded);
}

/* Mobile scale-down — keeps slides legible at narrow widths. */
@container main-content (max-width: 768px) {
  .ticker-value {
    font-size: var(--font-2xl);
  }

  .ticker-icon {
    width: 1rem;
    height: 1rem;
  }
}

/* ------ HOME: CASE STUDIES ------ */

.case-study-cards {
  display: flex;
  flex-direction: column;
  gap: var(--space-12xl);
}

/* Card is a link; reset link styles so inner type rules win. */
.case-study-card {
  display: grid;
  text-decoration: none;
  color: var(--text-primary);
  overflow: hidden;
}

a.case-study-card:hover {
  color: var(--text-primary);
}

/* Info column: title at top, stat at bottom — stretches to match
   the right-side media-frame's height (set by 16:9 ratio). */
.case-study-card-info {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-l);
}

/* Heading group: eyebrow (client name) sits tight above the title.
   Wrapping these two in their own flex column means the parent
   .case-study-card-info can keep `justify-content: space-between` and
   still push the stat to the bottom of the column. */
.case-study-card-heading {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.case-study-card-client {
  margin: 0;
  color: var(--text-faded);
}

.case-study-card-title {
  margin: 0;
}

/* Stat: <p> wraps the whole thing — its rules style the caption text
   directly. The value <span> is a block-level inline-flex callout
   (icon + number) above the caption. */
.case-study-card-stat {
  margin: 0;
  font-size: var(--text-size-s);
  color: var(--text-secondary);
}

.case-study-card-stat-value {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  margin-bottom: var(--space-xs);
  font-family: var(--font-tertiary);
  font-weight: var(--font-weight-medium);
  font-size: var(--font-7xl);
  color: var(--text-primary);
}

.case-study-card-stat-value .svg-icn {
  width: 1em;
  height: 1em;
}

/* Media block is the positioning context for the logo overlay
   (and any future scroll-revealed overlay layered on top). */
.case-study-card-media {
  position: relative;
  overflow: hidden;
}

/* Brand logo overlay — fills .case-study-card-media. Decorative
   (aria-hidden in markup); revealed only while body.is-scrolling.
   Phase 1 ships text content; Phase 2 swaps for an <img>. */
.case-study-card-logo {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  color: var(--white);
  background-color: var(--black-alpha-40);
  transition: opacity var(--duration-m) var(--ease-out);

  /* Phase 1 text styling — sized to read as a stand-in logo.
     The scrim above guarantees contrast over any video poster. */
  font-size: var(--font-3xl);
  font-weight: var(--font-weight-medium);
  text-align: center;
}

/* Logo mark — wrapper sizing for the sprite SVG. The .case-study-card-logo
   parent is the full-size scrim; this child caps the artwork itself so the
   logo reads as a centred mark, not a stretched fill.
   `aspect-ratio` is set inline by studio-home-featured.js from the sprite
   viewBox, so the wrapper sizes proportionally without per-logo CSS.
   Per-brand overrides hook in via `[data-logo="<name>"]`. */
.case-study-card-logo-mark {
  width: 30%;
  max-width: 20%;
  max-height: 20%;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Legacy <img> path — kept for any future bitmap-logo case. */
.case-study-card-logo img {
  max-width: 30%;
  max-height: 40%;
  width: auto;
  height: auto;
}

body.is-scrolling .case-study-card-logo {
  opacity: 1;
}

/* Reduced motion: keep the overlay permanently hidden rather than flashing
   in/out on every scroll. It's purely decorative reinforcement, so hiding
   it entirely is preferable to an instant opacity flip for vestibular
   sensitivity. */
@media (prefers-reduced-motion: reduce) {
  .case-study-card-logo {
    transition: none;
  }
  body.is-scrolling .case-study-card-logo {
    opacity: 0;
  }
}

/* ------ TESTIMONIALS ------ */

.home-cta .button-group {
  justify-content: center;
}

.cta-headline {
  font-size: var(--headline-size);
  font-weight: var(--title-weight);
  line-height: var(--title-leading);
  letter-spacing: var(--title-tracking);
  text-wrap: balance;
}

.cta-paragraph {
  text-wrap: balance;
}



.splide__arrow--prev svg {
    transform: scaleX(1) !important;
}

.testimonial-pause {
  display: none !important;
}

.testimonial-wrapper {
  overflow: hidden;
}

.splide__arrows .button {
  border-radius: var(--radius-pill);
}

/* Splide's vendor CSS sets overflow: hidden on the track and list, which
   clips anything positioned above the card edge (e.g. a half-overlapping
   avatar). Override here so the mark rebuild is free to overflow. */
.testimonial-slider .splide__track,
.testimonial-slider .splide__list {
  overflow: visible;
}

.testimonial-slide {
  display: flex;
  align-items: flex-start;
  overflow: visible;
  gap: var(--space-xl);
}

.testimonial-card {
  margin-top: 25px;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  padding: var(--space-2xl);
  background-color: var(--background-faded);
  /* Top-left stays sharp (anchors to the avatar). Other three corners
     round to soften the card. */
  border-radius: 0 var(--radius-l) var(--radius-l) var(--radius-l);
}

.testimonial-quote {
  font-size: var(--text-size-l);
  line-height: 1.3;
  color: var(--text-primary);
  margin: 0;
}

.testimonial-mark {
    flex: 0 0 auto;
    color: var(--background-primary);
    background: var(--text-primary);
    border-radius: 50%;
    overflow: hidden;
    height: 60px;
    width: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px;
}

.testimonial-mark .svg-logo {
  max-width: 45px;
  max-height: 45px;
}

.js .testimonial-quote {
  opacity: 0;
}

.testimonial-attribution {
  color: var(--text-faded);
}

/* Centered cluster: progress + pause + arrows. Below the slider track. */
.testimonial-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-l);
  margin-top: var(--space-2xl);
}

.testimonial-progress {
  width: 8rem;
  height: 1px;
  background-color: var(--divider-color);
  overflow: hidden;
}

.testimonial-progress .splide__progress__bar {
  background-color: var(--text-primary);
  height: 100%;
  width: 0%;
}

.testimonial-controls .splide__arrows {
  display: flex;
  gap: var(--space-s);
}

/* Override Splide's default absolute arrow positioning — we render them
   inside the centered controls cluster, not at the track edges. */
.testimonial-controls .splide__arrow--prev,
.testimonial-controls .splide__arrow--next,
.testimonial-controls .testimonial-pause {
  position: static;
  transform: none;
  opacity: 1;
}

/* Pause/play icon swap — only one icon visible at a time, driven by
   the `.is-paused` class on the button. */
.testimonial-pause .testimonial-pause-icon-play {
  display: none;
}

.testimonial-pause.is-paused .testimonial-pause-icon-pause {
  display: none;
}

.testimonial-pause.is-paused .testimonial-pause-icon-play {
  display: flex;
}

@container main-content (max-width: 768px) {
  .testimonial-card {
    /* Slide width is now controlled by Splide's fixedWidth breakpoints;
       the card stays at its desktop percentage of slide width. */
    padding: var(--space-xl);
  }


  .testimonial-progress {
    width: 5rem;
  }
}

/* ------ GSAP FOUC PREVENTION ------ */
/* Hide animated elements until JS reveals them.
   Scoped to .js so content remains visible if JavaScript is disabled. */

.js [data-bd-animate],
.js [data-text-animate] {
  opacity: 0;
}

/* ------ PRINT SAFETY ------ */
/* Ensure GSAP-animated elements are visible when printing */

@media print {
  [data-bd-animate],
  [data-text-animate],
  [data-bd-leave] {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
}

/* ------ ASPECT RATIO — global utility attribute ------ */
/* Apply data-ratio="W:H" to any element to set its aspect ratio.
   Component defaults set their own aspect-ratio; data-ratio overrides it.
   Lives at the end of the file so source-order beats component defaults
   at the same (0,1,0) specificity. */

[data-ratio="1:1"]  { aspect-ratio: 1 / 1; }
[data-ratio="2:1"]  { aspect-ratio: 2 / 1; }
[data-ratio="3:1"]  { aspect-ratio: 3 / 1; }
[data-ratio="4:3"]  { aspect-ratio: 4 / 3; }
[data-ratio="3:2"]  { aspect-ratio: 3 / 2; }
[data-ratio="3:4"]  { aspect-ratio: 3 / 4; }
[data-ratio="16:9"] { aspect-ratio: 16 / 9; }
[data-ratio="21:9"] { aspect-ratio: 21 / 9; }
[data-ratio="4:5"]  { aspect-ratio: 4 / 5; }
[data-ratio="5:4"]  { aspect-ratio: 5 / 4; }
[data-ratio="9:16"] { aspect-ratio: 9 / 16; }


/* ------ LINE LENGTH — global utility attribute ------ */
/* Apply data-line-length="<value>" to any text element to constrain its
   measure (max-width) to a known-good readability target. Values are named
   typographically — headline (display titles) → wide (max comfortable prose).
   Bringhurst: 45–75ch is the satisfactory range for body text; 66ch ideal. */

[data-line-length="headline"] { max-width: var(--line-length-headline); }
[data-line-length="small"]    { max-width: var(--line-length-small); }
[data-line-length="xsmall"]    { max-width: var(--line-length-xsmall); }
[data-line-length="body"]     { max-width: var(--line-length-body); }
[data-line-length="medium"]   { max-width: var(--line-length-medium); }
[data-line-length="wide"]     { max-width: var(--line-length-wide); }


/* ============================================================
   HOME — PRODUCT SPOTLIGHT
   Static product list. Each <li> is a whole-row link laid out by the
   [data-grid] data-layout="spotlight" pattern (media · info · CTA),
   collapsing to a single column at ≤959.98px. Entrance reveal is the
   shared bd-animations scrub-group (data-bd-scrub-group on the <ol>,
   data-bd-animate="slide-up" on each <li>); videos autoplay + loop.
   ============================================================ */

.product-spotlight .product-spotlight-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Row metrics live on the <li>; the [data-grid] sits one level inward on
   .product-spotlight-link so the whole row is one tappable target. The
   min-height gives the rows a consistent vertical rhythm. */
.product-spotlight .product-spotlight-item {
  min-height: 20rem;
  border-bottom: var(--border-s) solid var(--border-faded);
  margin: 0;
}


.product-spotlight .product-spotlight-item:last-child {
  border: none;
}

/* Whole-row link wrapper. Anchor reset + grid host. Three children opt
   into the [data-grid] 12-col layout via data-col-span / data-col-start
   in the markup: media spans cols 1–3, info spans cols 5–9 (col 4 is
   an explicit gutter between media and info), CTA spans cols 10–12. */
.product-spotlight .product-spotlight-link {
  display: grid;
  align-items: center;
  color: inherit;
  text-decoration: none;
  padding: var(--space-3xl) 0;

}

.product-spotlight .product-spotlight-media {
  aspect-ratio: 5 / 3;
  width: 100%;
  /* Cursor parallax (desktop only) — initProductParallax in studio-home.js
     writes per-tile --cursor-x/y while the pointer is over the row; the lerp
     in JS is the smoothing, so no CSS transition here. Fallback 0px keeps the
     transform an identity no-op on touch / reduced-motion (JS never sets the
     vars there). */
  transform: translate(var(--cursor-x, 0px), var(--cursor-y, 0px));
}

.product-spotlight .product-spotlight-media img,
.product-spotlight .product-spotlight-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* border-radius: var(--radius-s); */
  display: block;
}

/* .product-spotlight-info is the middle grid cell (cols 4–9 via the
   data-layout="spotlight" named pattern). padding-inline-start inset
   by one --col-unit gives the content the visual cols-5–9 width while
   the cell itself remains 6 cols wide. on mobile (≤959) --col-unit
   resets to 0px so the inset disappears with the collapse. */
.product-spotlight .product-spotlight-info {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  padding-inline-start: var(--col-unit);
}

/* Text colors. */
.product-spotlight .product-spotlight-title,
.product-spotlight .product-spotlight-subline,
.product-spotlight .product-spotlight-cta {
  color: var(--text-primary);
}

.product-spotlight .product-spotlight-description {
  color: var(--text-faded);
}

/* Per-element typography (color set in the grouped rule above). */
.product-spotlight .product-spotlight-title {
  margin: 0;
  font-size: var(--title-size);
  line-height: 1;
  letter-spacing: -0.02em;
}

.product-spotlight .product-spotlight-subline {
  margin: 0;
}

.product-spotlight .product-spotlight-description {
  margin: 0;
  text-wrap: balance;
}

/* Subtle trending icon + label CTA, stacked icon-above-label and
   horizontally centered. column-reverse keeps the icon visually first
   without reordering the markup (label first reads naturally and the
   icon is aria-hidden). */
.product-spotlight .product-spotlight-cta {
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: var(--space-s);
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
}

.product-spotlight .product-spotlight-cta .svg-icn {
  width: 1.5rem;
  height: 1.5rem;
}

/* Stacked — at the grid-collapse breakpoint the CTA reads as a full-width
   faded button: icon + label on one line, subtle fill. Mirrors the tokens
   of .button[data-variant="faded"]; --text-alpha-10 is built on
   --text-primary, so the fill adapts to dark mode with no per-theme rule. */
@container main-content (max-width: 959.98px) {
  .product-spotlight .product-spotlight-cta {
    flex-direction: row;
    justify-content: center;
    gap: var(--space-s);
    padding: var(--space-l) var(--space-xl);
    background-color: var(--text-alpha-10);
    border-radius: var(--radius-s);
  }

  .product-spotlight .product-spotlight-cta .svg-icn {
    width: 1.25rem;
    height: 1.25rem;
  }
}

/* Mobile — [data-grid] auto-collapses to a single column at ≤959px, so
   media / info / CTA stack naturally as a vertical flow. */
@container main-content (max-width: 768px) {
  .product-spotlight .product-spotlight-item {
    row-gap: var(--space-m);
    min-height: auto;
  }

  .product-spotlight .product-spotlight-media {
    aspect-ratio: 16 / 9;
  }
}

/* ============================================================
   EXPERIMENTAL — product spotlight hover effects (desktop only)
   Self-contained. Delete this whole block to revert to a plain
   static list (media always visible, no sibling dim). Pointer/
   hover-gated so touch is unaffected. Both effects target
   .product-spotlight-link / -media, never the <li> (which carries
   data-bd-animate — bd-animations sets its opacity inline and would
   win over a class rule).
   ============================================================ */
@media (hover: hover) and (pointer: fine) {
  .product-spotlight .product-spotlight-link {
    transition: opacity var(--duration-l) var(--ease-out);
  }

  /* Hovering one row dims its siblings so the row under the cursor stands out. */
  .product-spotlight .product-spotlight-list:hover .product-spotlight-item:not(:hover) .product-spotlight-link {
    opacity: 0.4;
  }

  /* Media hidden until its row is hovered, then fades to full. */
  .product-spotlight .product-spotlight-media {
    opacity: 0.4;
    transition: opacity var(--duration-s) var(--ease-out);
  }

  .product-spotlight .product-spotlight-link:hover .product-spotlight-media {
    opacity: 1;
  }
}


/* ------ BOOK A CALL ------ */

/* Full-viewport Google Appointment Schedule iframe.
   .page-wrapper already adds padding-top: var(--studio-bar-height) on L1 pages,
   so the iframe height is the remaining viewport space below the fixed page header. */
.booking-iframe {
  display: block;
  width: 100%;
  height: calc(100dvh - var(--studio-bar-height));
  border: 0;
}

@container main-content (max-width: 768px) {
  .booking-iframe {
    height: calc(100dvh - var(--mobile-bar-height) - var(--studio-bar-height));
  }
}
