/* ==========================================================================
   Case Study Layout — cs-* components
   Used by project-4.html (and future case studies).

   Per-project accent color: set --cs-accent on <main>.
   e.g. <main style="--cs-accent: #0060AF;">

   All components respect body.theme--light via semantic tokens.
   ========================================================================== */

/* ================================================================
   CUSTOM PROPERTY DEFAULTS
   ================================================================ */
:root {
  --cs-accent:          #2563EB;         /* fallback — overridden per project */
  --cs-accent-dim:      rgba(37, 99, 235, 0.12);
  --cs-section-py:      var(--space-5xl);
  --cs-chapter-py:      var(--space-3xl);
  --cs-split-gap:       var(--space-5xl);
  --cs-split-col-text:  7fr;
  --cs-split-col-vis:   5fr;
}


/* ================================================================
   CS-INTRO — Overview + Meta 2-col block
   ================================================================ */
.cs-intro {
  padding: var(--cs-section-py) 0 var(--space-4xl);
  background-color: var(--color-bg);
  transition: background-color var(--duration-theme);
}

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

.cs-intro__overview-label {
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--cs-accent);
  margin-bottom: var(--space-sm);
}

.cs-intro__text {
  font-size: var(--text-body-lg);
  line-height: var(--leading-prose);
  color: var(--color-text-secondary);
  max-width: 600px;
}

.cs-intro__text + .cs-intro__text {
  margin-top: var(--space-md);
}

/* Right: stacked meta list — horizontal cards instead of divider lines */
.cs-intro__meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.cs-intro__meta-item {
  padding: 16px 16px;
  border-radius: 8px;
  /* --color-card directly, not the --card-bg alias — --card-bg doesn't
     correctly pick up body.theme--light's override when the class is
     toggled at runtime (confirmed: --color-card resolves correctly,
     --card-bg does not), so it's bypassed here. */
  background-color: var(--color-card);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
}

.cs-intro__meta-label {
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--color-text-tertiary);
  margin-bottom: 4px;
}

.cs-intro__meta-value {
  font-size: var(--text-label);
  line-height: 1.5;
  color: var(--color-text-primary);
  font-weight: var(--fw-emphasis);
}

@media (max-width: 1024px) {
  .cs-intro__inner {
    grid-template-columns: 1fr;
    gap: var(--space-3xl);
  }

  .cs-intro__meta {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-md);
  }

  .cs-intro__meta-item {
    flex: 1 1 calc(50% - var(--space-md));
  }
}

@media (max-width: 640px) {
  .cs-intro__meta-item {
    flex: 1 1 100%;
  }
}


/* ================================================================
   CS-STATEMENT — Large editorial pull statement
   ================================================================ */
.cs-statement {
  padding: var(--space-4xl) 0;
}

.cs-statement__text {
  font-family: 'Newsreader', Georgia, serif;
  font-style: italic;
  font-size: clamp(1.5rem, 2.5vw + 0.5rem, 2.5rem);
  line-height: 1.35;
  color: var(--color-text-primary);
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
  letter-spacing: -0.01em;
}

.cs-statement__text em {
  font-style: normal;
  color: var(--cs-accent);
}


/* ================================================================
   CS-FULL-BLEED — Image with caption
   ================================================================ */
.cs-full-bleed {
  margin: var(--space-4xl) 0;
}

.cs-full-bleed__frame {
  width: 100%;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-light);
}

.cs-full-bleed__frame img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 600px;
  object-fit: contain;
  object-position: center;
}

.cs-full-bleed__caption {
  margin-top: var(--space-sm);
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  text-align: center;
  letter-spacing: var(--tracking-wide);
}


/* ================================================================
   CS-QUOTE-FEATURE — Full-bleed blue quote block + overlapping image
   The quote box breaks out to full viewport width (100vw technique)
   regardless of its .container ancestor's max-width/padding — safe
   because html/body carry overflow-x:hidden site-wide.

   The image sits in normal flow directly after the quote box, at 50%
   width centered; it's pulled up via a negative top margin equal to
   40% of its OWN rendered height (not the container's) — percentage
   margins resolve against the containing block's width, and since
   the image has a fixed intrinsic aspect ratio, 40% of its height
   converts to a fixed percentage of that same width, so this stays
   correct at any viewport size without JS. Halving the image's width
   also halves its rendered height, so the margin is half of what a
   full-width image would need for the same 40% overlap.

   The quote box's own bottom padding gets that same percentage added
   on top of its normal 72px — without it, the box's height is purely
   content-driven (text + padding) and doesn't actually grow to
   contain the overlap, so a large overlap % just pushes the image up
   past the TOP of the box instead of showing more blue behind it.
   ================================================================ */
.cs-quote-feature {
  margin: var(--space-4xl) 0;
}

.cs-quote-feature__quote {
  background-color: #0078CF;
  color: #ffffff;
  padding: 72px 72px calc(72px + 22.49%);
  text-align: center;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  border-radius: 0;
}

.cs-quote-feature__text {
  font-family: var(--font-heading);
  font-size: 54px;
  font-weight: 700;
  font-style: italic;
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-heading);
  color: inherit;
  max-width: 900px;
  margin: 0 auto;
}

.cs-quote-feature__text em {
  font-style: normal;
}

.cs-quote-feature__image-wrap {
  position: relative;
  width: 50%;
  /* -40% of the image's own rendered height (at its new 50% width),
     expressed as a percentage of the containing block's width — see
     block comment above. coned-slide-1.png is 1400x1574. */
  margin-top: -22.49%;
  margin-left: auto;
  margin-right: auto;
  border-radius: var(--radius-card);
  overflow: hidden;
}

.cs-quote-feature__image {
  display: block;
  width: 100%;
  height: auto;
}

@media (max-width: 768px) {
  .cs-quote-feature__quote {
    padding: var(--space-xl) var(--space-xl) calc(var(--space-xl) + 35.98%);
  }

  .cs-quote-feature__image-wrap {
    width: 80%;
    margin-top: -35.98%;
  }
}


/* ================================================================
   CS-CHAPTER — Section divider with number + label
   ================================================================ */
.cs-chapter {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--cs-chapter-py) 0 var(--space-xl);
  border-top: 1px solid var(--cs-accent);
}

.cs-chapter__number {
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  color: var(--cs-accent);
  font-variant-numeric: tabular-nums;
  min-width: 2rem;
}

.cs-chapter__label {
  font-size: var(--text-h4);
  font-weight: var(--fw-heading);
  color: var(--color-text-primary);
  letter-spacing: var(--tracking-heading);
  line-height: 1.2;
}


/* ================================================================
   CS-SPLIT — Two-column text + visual section
   ================================================================ */
.cs-split {
  padding: 0 0 var(--cs-section-py);
  background-color: var(--color-bg);
  transition: background-color var(--duration-theme);
}

/* Display grid is on the section; container has display:contents to
   let the children participate directly in this grid */
.cs-split {
  display: grid;
  grid-template-columns: var(--cs-split-col-text) var(--cs-split-col-vis);
  gap: 0 var(--space-4xl);
  align-items: start;
  padding-left: var(--grid-margin);
  padding-right: var(--grid-margin);
  max-width: var(--max-width);
  margin-left: auto;
  margin-right: auto;
}

.cs-split--flip {
  grid-template-columns: var(--cs-split-col-vis) var(--cs-split-col-text);
}

/* Text column */
.cs-split__text {
  padding-top: var(--space-lg);
}

.cs-split__eyebrow {
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--cs-accent);
  margin-bottom: var(--space-xs);
}

.cs-split__heading {
  font-size: var(--text-h3);
  font-weight: var(--fw-heading);
  color: var(--color-text-primary);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-heading);
  margin-bottom: var(--space-lg);
}

.cs-split__body {
  font-size: var(--text-body);
  line-height: var(--leading-prose);
  color: var(--color-text-secondary);
}

.cs-split__body p {
  margin-bottom: var(--space-md);
}

.cs-split__body p:last-child {
  margin-bottom: 0;
}

.cs-split__body ul {
  margin-top: var(--space-md);
  margin-bottom: 0;
  padding-left: 1.25em;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.cs-split__body li {
  line-height: 1.6;
}

.cs-split__body li::marker {
  color: var(--cs-accent);
}

/* Visual column */
.cs-split__visual {
  padding-top: var(--space-lg);
  position: sticky;
  top: calc(var(--nav-height) + var(--space-lg));
}

.cs-split__image {
  width: 100%;
  min-height: 280px;
  border-radius: var(--radius-card);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-light);
  overflow: hidden;
  margin-bottom: var(--space-sm);
}

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

.cs-split__image-caption {
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  line-height: 1.5;
  letter-spacing: var(--tracking-wide);
}

/* Flipped: visual moves to col 1 */
.cs-split--flip .cs-split__text {
  order: 2;
}

.cs-split--flip .cs-split__visual {
  order: 1;
}

@media (max-width: 1024px) {
  .cs-split,
  .cs-split--flip {
    display: flex;
    flex-direction: column;
    padding-left: var(--grid-margin);
    padding-right: var(--grid-margin);
    gap: var(--space-2xl);
  }

  .cs-split--flip .cs-split__text,
  .cs-split--flip .cs-split__visual {
    order: unset;
  }

  .cs-split__visual {
    position: static;
  }
}


/* ================================================================
   CS-PULL-QUOTE — Bold blockquote section
   ================================================================ */
.cs-pull-quote {
  padding: var(--space-4xl) 0;
  background-color: var(--color-bg-alt);
  border-top: 1px solid var(--color-border-light);
  border-bottom: 1px solid var(--color-border-light);
  transition: background-color var(--duration-theme),
              border-color var(--duration-theme);
}

.cs-pull-quote__text {
  font-family: 'Newsreader', Georgia, serif;
  font-style: italic;
  font-size: clamp(1.25rem, 1.5vw + 0.5rem, 1.75rem);
  line-height: 1.45;
  color: var(--color-text-primary);
  max-width: 760px;
  margin: 0 auto;
  text-align: center;
  padding-left: var(--space-2xl);
  padding-right: var(--space-2xl);
  position: relative;
}

.cs-pull-quote__text::before {
  content: '"';
  display: block;
  font-family: 'Newsreader', Georgia, serif;
  font-style: italic;
  font-size: 4rem;
  line-height: 1;
  color: var(--cs-accent);
  opacity: 0.4;
  margin-bottom: -1rem;
}

.cs-pull-quote__text strong {
  font-style: normal;
  font-weight: var(--fw-heading);
  color: var(--color-text-primary);
}


/* ================================================================
   CS-STATS — Impact metrics grid
   ================================================================ */
.cs-stats {
  padding: var(--cs-section-py) 0;
  background-color: var(--color-bg);
  transition: background-color var(--duration-theme);
}

.cs-stats__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-lg);
}

.cs-stat {
  padding: var(--space-xl) var(--space-lg);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-card);
  text-align: center;
  transition: background-color var(--duration-theme),
              border-color var(--duration-theme);
}

.cs-stat__number {
  font-size: clamp(2.5rem, 4vw + 0.5rem, 4rem);
  font-weight: var(--fw-black);
  line-height: 1;
  color: var(--cs-accent);
  letter-spacing: var(--tracking-heading);
  margin-bottom: var(--space-xs);
  font-variant-numeric: tabular-nums;
}

.cs-stat__label {
  font-size: var(--text-caption);
  line-height: 1.5;
  color: var(--color-text-secondary);
  max-width: 200px;
  margin: 0 auto;
}

@media (max-width: 1024px) {
  .cs-stats__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 640px) {
  .cs-stats__grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-sm);
  }

  .cs-stat {
    padding: var(--space-lg) var(--space-md);
  }
}


/* ================================================================
   THEME — Light mode overrides
   All semantic-token-based components update automatically.
   These are for cs-specific elements that need explicit overrides.
   ================================================================ */
body.theme--light .cs-stat {
  background-color: var(--p-neutral-50);
  border-color: var(--p-neutral-150);
}

body.theme--light .cs-full-bleed__frame {
  background-color: var(--p-neutral-100);
  border-color: var(--p-neutral-200);
}

body.theme--light .cs-split__image {
  background-color: var(--p-neutral-100);
  border-color: var(--p-neutral-200);
}

/* ================================================================
   CS-PROGRESS — Thin reading progress bar (fixed top of viewport)
   ================================================================ */
.cs-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0%;
  background-color: var(--cs-accent);
  z-index: 200;
  transition: width 80ms linear;
  pointer-events: none;
}


/* ================================================================
   HERO BREADCRUMB + TAGS
   ================================================================ */
.hero__breadcrumb {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin-top: var(--space-xl);
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--p-neutral-400);
}

.hero__breadcrumb a {
  color: inherit;
  transition: color var(--duration-fast) var(--ease-default);
}

.hero__breadcrumb a:hover {
  color: var(--p-neutral-100);
}

.hero__breadcrumb-sep {
  color: var(--p-neutral-600);
  font-weight: var(--p-fw-regular);
}

.hero__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}

.hero__tag {
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--cs-accent);
  opacity: 0.85;
}

/* Lock hero breadcrumb/tags to dark palette even when body.theme--light */
body.theme--light .hero--project .hero__breadcrumb { color: var(--p-neutral-400); }
body.theme--light .hero--project .hero__breadcrumb a:hover { color: var(--p-neutral-100); }
body.theme--light .hero--project .hero__tag { color: var(--cs-accent); }


/* ================================================================
   CS-STATS EARLY — Compact inline stat strip (used in cs-intro zone)
   Displays headline numbers before the narrative for FAANG outcome-first
   scanning. Separate from the full cs-stats grid at the end.
   ================================================================ */
.cs-stats-early {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-lg) var(--space-3xl);
  padding: var(--space-2xl) 0 var(--space-xl);
  margin-bottom: var(--space-3xl);
}

.cs-stats-early__item {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.cs-stats-early__number {
  font-size: var(--text-h3);
  font-weight: var(--fw-display);
  line-height: 1;
  letter-spacing: var(--tracking-heading);
  color: var(--cs-accent);
  font-variant-numeric: tabular-nums;
}

.cs-stats-early__label {
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--color-text-tertiary);
  max-width: 200px;
  line-height: 1.4;
}

@media (max-width: 640px) {
  .cs-stats-early {
    gap: var(--space-lg) var(--space-2xl);
  }
  .cs-stats-early__number {
    font-size: var(--text-h4);
  }
}


/* ================================================================
   CS-VIDEO — Inline .mov / mp4 player
   Usage: <div class="cs-video" data-src="../assets/video/demo.mov"
               data-poster="../assets/images/poster.jpg"
               data-caption="Caption text here">
          </div>
          <p class="cs-video__caption"></p>
   JS (initVideoPlaceholders) injects the <video> element on load.
   ================================================================ */
.cs-video {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background-color: var(--color-surface);
  border-radius: var(--radius-card);
  overflow: hidden;
  border: 1px solid var(--color-border-light);
  margin: var(--space-3xl) 0 var(--space-sm);
}

.cs-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  background-color: var(--p-neutral-950);
}

/* Placeholder state — shown before JS injects the video */
.cs-video:not(:has(video))::after {
  content: attr(data-caption);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  letter-spacing: var(--tracking-wide);
}

.cs-video__caption {
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  letter-spacing: var(--tracking-wide);
  margin-bottom: var(--space-3xl);
  line-height: 1.5;
}

/* Light theme */
body.theme--light .cs-video {
  background-color: var(--p-neutral-100);
  border-color: var(--p-neutral-200);
}

body.theme--light .cs-video video {
  background-color: var(--p-neutral-950);
}


/* ================================================================
   LIGHT THEME — New component overrides
   ================================================================ */

body.theme--light .cs-stats-early__number {
  color: var(--cs-accent);
}

body.theme--light .cs-stats-early__label {
  color: var(--p-neutral-500);
}


/* ================================================================
   HERO — SPLIT LAYOUT (text panel + visual carousel)
   New project-hero pattern: text left, dot-controlled image carousel
   right. Replaces the old absolute-background .hero__carousel for
   pages migrated to this pattern. Stacks vertically <=1024px.
   Usage: <section class="hero hero--project hero--warm hero--split">
   ================================================================ */
.hero--split {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  align-items: stretch;
  min-height: var(--hero-min-h-project);
  max-width: var(--max-width);
  margin: 0 auto;
  padding-top: 0;
  padding-bottom: 0;
}

.hero--split .hero__panel-text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--nav-height) + var(--space-3xl)) var(--grid-margin) var(--space-3xl);
  min-width: 0;
}

.hero--split .hero__breadcrumb { margin-top: 0; }

.hero__panel-visual {
  position: relative;
  min-height: 480px;
  padding: var(--space-xl);
  padding-bottom: 0;
  background-color: transparent; /* inherits the .hero section's own bg (dark/warm/default) to match the text panel */
  overflow: hidden;
}

.hero__visual-carousel {
  position: absolute;
  inset: 0;
}

.hero__visual-slide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  opacity: 0;
  /* Matches the established .hero__carousel crossfade timing */
  transition: opacity 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

.hero__visual-slide.is-active {
  opacity: 1;
  z-index: 1;
}

.hero__visual-slide img {
  width: 85%;
  height: 85%;
  object-fit: contain;
  object-position: center center;
  display: block;
  margin: 0 auto;
  border-radius: 16px;
}

/* ================================================================
   PROJECT HERO CAROUSEL — directional slide-in variant
   Opt-in per project via a modifier class on .hero__visual-carousel
   (e.g. --slide-btt, --slide-rtl, --slide-ttb). Replaces the default
   crossfade with a transform-based push in a single fixed axis, while
   keeping the same dot-click-to-jump + auto-advance behavior. Base rule
   sets each direction's resting (off-screen) position; the combined
   .is-active selector below has one extra class, so it always wins
   regardless of source order.
   ================================================================ */
.hero__visual-carousel--slide-btt .hero__visual-slide,
.hero__visual-carousel--slide-rtl .hero__visual-slide,
.hero__visual-carousel--slide-ttb .hero__visual-slide {
  opacity: 1;
  /* align-items stays flex-end (inherited from the base rule) so the
     image sits flush to the bottom edge, matching the documented
     Project Hero spec (510x646 safe area, bottom + center aligned) —
     this was accidentally overridden to "center" before, which split
     the empty space evenly top/bottom instead. */
  transition: transform 0.84s cubic-bezier(0.65, 0, 0.35, 1);
}

.hero__visual-carousel--slide-btt .hero__visual-slide { transform: translateY(100%); }
.hero__visual-carousel--slide-rtl .hero__visual-slide { transform: translateX(100%); }
.hero__visual-carousel--slide-ttb .hero__visual-slide { transform: translateY(-100%); }

.hero__visual-carousel--slide-btt .hero__visual-slide.is-active,
.hero__visual-carousel--slide-rtl .hero__visual-slide.is-active,
.hero__visual-carousel--slide-ttb .hero__visual-slide.is-active {
  transform: translate(0, 0);
  z-index: 1;
}

.hero__visual-carousel--slide-btt .hero__visual-slide.is-exit-btt { transform: translateY(-100%); }
.hero__visual-carousel--slide-rtl .hero__visual-slide.is-exit-rtl { transform: translateX(-100%); }
.hero__visual-carousel--slide-ttb .hero__visual-slide.is-exit-ttb { transform: translateY(100%); }

.hero__visual-slide.no-transition {
  transition: none;
}

.hero__visual-dots {
  position: absolute;
  right: var(--space-lg);
  bottom: var(--space-lg);
  display: flex;
  gap: var(--space-xs);
  z-index: 2;
}

.hero__visual-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1.2px solid rgba(255, 255, 255, 0.8);
  background: transparent;
  padding: 0;
  cursor: pointer;
  transition: background-color var(--duration-normal) var(--ease-default),
              transform var(--duration-fast) var(--ease-default),
              border-color var(--duration-normal) var(--ease-default);
}

.hero__visual-dot:hover {
  border-color: #fff;
}

.hero__visual-dot.is-active {
  background-color: #fff;
  transform: scale(1.15);
}

/* Filmstrip — nav between other case studies */
.hero__filmstrip {
  display: flex;
  gap: var(--space-md);
  margin-top: var(--space-3xl);
  overflow-x: auto;
  padding-bottom: 2px; /* room for focus ring */
}

.hero__filmstrip-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  flex: 0 0 auto;
  width: 96px;
  opacity: 0.55;
  transition: opacity var(--duration-normal) var(--ease-default);
}

.hero__filmstrip-item:hover,
.hero__filmstrip-item.is-active {
  opacity: 1;
}

.hero__filmstrip-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-input);
  background-color: var(--color-surface);
  overflow: hidden;
}

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

.hero__filmstrip-label {
  font-size: var(--text-caption);
  color: var(--color-text-tertiary);
  letter-spacing: var(--tracking-wide);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- Tablet / Mobile — stack visual under text ---- */
@media (max-width: 1024px) {
  .hero--split {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .hero--split .hero__panel-text {
    padding: calc(var(--nav-height) + var(--space-2xl)) var(--grid-margin) var(--space-2xl);
  }

  .hero__panel-visual {
    min-height: 360px;
  }
}

@media (max-width: 640px) {
  .hero__panel-visual {
    min-height: 280px;
  }

  .hero__filmstrip-item {
    width: 76px;
  }

  .hero__visual-dots {
    right: var(--space-md);
    bottom: var(--space-md);
  }
}

/* ================================================================
   HERO — HOME SPLIT VARIANT
   Reuses the .hero--split grid/stack mechanics above, with a
   light, editorial treatment: viewfinder corner marks, a decorative
   accent ring behind the copy, and a plain auto-advancing (no dot
   controls) image/video carousel on the right, edge-to-edge.
   ================================================================ */
.hero--home.hero--split {
  background-color: var(--p-neutral-0);
  min-height: var(--hero-min-h-home);
  grid-template-columns: minmax(0, 47%) minmax(0, 53%);
}

.hero__panel-text--home {
  position: relative;
  background-color: var(--p-neutral-50);
  overflow: hidden;
}

.hero__eyebrow--home {
  position: absolute;
  top: calc(var(--nav-height) + var(--space-lg) + 16px);
  /* Corner mark's inward edge sits at space-lg + 21px (its own size);
     add 16px past that for a true visual gap, not just a flat shift. */
  right: calc(var(--space-lg) + 21px + 16px);
  margin-bottom: 0;
  font-size: var(--text-caption);
}

.hero__home-copy {
  position: relative;
  z-index: 1;
}

/* Viewfinder corner marks — decorative, framing the copy block */
.hero__frame-corner {
  position: absolute;
  width: 21px;
  height: 21px;
  border: 0 solid var(--p-neutral-900);
  pointer-events: none;
  z-index: 1;
}

.hero__frame-corner--tl {
  top: calc(var(--nav-height) + var(--space-lg));
  left: var(--space-lg);
  border-top-width: 2px;
  border-left-width: 2px;
  border-top-left-radius: 2px;
}

.hero__frame-corner--tr {
  top: calc(var(--nav-height) + var(--space-lg));
  right: var(--space-lg);
  border-top-width: 2px;
  border-right-width: 2px;
  border-top-right-radius: 2px;
}

.hero__frame-corner--bl {
  bottom: var(--space-lg);
  left: var(--space-lg);
  border-bottom-width: 2px;
  border-left-width: 2px;
  border-bottom-left-radius: 2px;
}

.hero__frame-corner--br {
  bottom: var(--space-lg);
  right: var(--space-lg);
  border-bottom-width: 2px;
  border-right-width: 2px;
  border-bottom-right-radius: 2px;
}

/* Decorative accent ring, centered behind the copy block */
.hero__accent-ring {
  position: absolute;
  left: 44%;
  top: 62%;
  width: min(420px, 55%);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 1.5px solid var(--p-neutral-200);
  pointer-events: none;
  z-index: 0;
}

/* Back / Next caption row — doubles as the home carousel's controls.
   Vertically centered on the corner bracket's top edge (space-lg +
   21px, its own footprint) via the bottom+translateY(50%) pairing,
   which stays centered regardless of the row's actual line-height. */
.hero__frame-nav {
  position: absolute;
  left: calc(var(--space-lg) + 21px + 16px);
  right: calc(var(--space-lg) + 21px + 16px);
  bottom: calc(var(--space-lg) + 21px);
  transform: translateY(50%);
  display: flex;
  justify-content: space-between;
  z-index: 1;
}

.hero__frame-nav-label {
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font-family: inherit;
  font-size: var(--text-caption);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  color: var(--color-text-tertiary);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-default);
}

.hero__frame-nav-label:hover,
.hero__frame-nav-label:focus-visible {
  color: var(--color-text-primary);
}

.hero__panel-visual--home {
  padding: 0;
  background-color: #e5e5e5;
  border-top-right-radius: 16px;
  border-bottom-right-radius: 16px;
}

/* ================================================================
   HOME HERO CAROUSEL — vertical slide transition, unique to the
   home hero (distinct from the dot-controlled project-page
   carousels, which crossfade instead). Auto-advances upward; the
   Back/Next buttons drive it manually in either direction.
   ================================================================ */
.home-hero-carousel {
  position: absolute;
  inset: 0;
}

.home-hero-carousel__slide {
  position: absolute;
  inset: 0;
  transform: translateY(100%);
  transition: transform 0.7s cubic-bezier(0.65, 0, 0.35, 1);
}

.home-hero-carousel__slide.is-active {
  transform: translateY(0%);
}

.home-hero-carousel__slide.is-exit-up {
  transform: translateY(-100%);
}

.home-hero-carousel__slide.is-exit-down {
  transform: translateY(100%);
}

.home-hero-carousel__slide.is-enter-top {
  transform: translateY(-100%);
}

.home-hero-carousel__slide.no-transition {
  transition: none;
}

.home-hero-carousel__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

@media (max-width: 1024px) {
  .hero__panel-visual--home {
    border-radius: var(--radius-panel);
  }

  .hero__accent-ring {
    width: min(320px, 60%);
  }

  /* Reserve room so the absolutely-positioned Back/Next row doesn't
     collide with the CTA button once the panel height is content-driven
     instead of viewport-driven (stacked layout). Sized for the row's
     bottom offset (space-lg + 21px + 16px) plus its own height. */
  .hero--split .hero__panel-text--home {
    padding-bottom: calc(var(--space-2xl) + 60px);
  }
}

@media (max-width: 640px) {
  .hero__frame-corner {
    display: none;
  }

  .hero__eyebrow--home {
    top: calc(var(--nav-height-mobile) + var(--space-md));
    right: var(--space-lg);
  }

  .hero__frame-nav {
    left: var(--space-lg);
    right: var(--space-lg);
  }

  /* The home hero copy is normally vertically centered (see the base
     .hero--split .hero__panel-text rule), but centering combined with
     the absolutely-positioned eyebrow can make the title collide with
     it on short mobile viewports. Pin to the top instead and reserve
     explicit clearance below the eyebrow so they never overlap. */
  .hero--split .hero__panel-text--home {
    justify-content: flex-start;
    padding-top: calc(var(--nav-height-mobile) + var(--space-md) + 20px + var(--space-lg));
  }

  /* Consistent rhythm: title-to-subtitle and subtitle-to-CTA both use
     the same gap as the reserved eyebrow clearance above. */
  .hero--home .hero__subtitle {
    font-size: 16px;
  }

  .hero--home .hero__cta {
    margin-top: var(--space-lg);
  }
}

/* Below 600px, left-align the eyebrow with the title/body copy instead
   of keeping it right-anchored — matches .hero--split .hero__panel-text's
   own left padding (--grid-margin) so it lines up with the text below it. */
@media (max-width: 600px) {
  .hero__eyebrow--home {
    right: auto;
    left: var(--grid-margin);
  }
}

/* ================================================================
   HERO — ABOUT SPLIT VARIANT
   Even 50/50 split. Left panel is an intentionally dark surface
   (--color-surface-inverted, fixed regardless of page theme) holding
   a smaller rounded portrait card. Right panel is an ambient,
   continuously auto-advancing image/video carousel with a dark
   gradient overlay and centered white copy on top.
   ================================================================ */
.hero--about.hero--split {
  position: relative;
  background-color: var(--color-bg);
  min-height: var(--hero-min-h-home);
  grid-template-columns: 1fr 1fr;
}

.hero__panel-visual--about-portrait {
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--color-surface-inverted);
}

.hero__portrait-card {
  width: min(259px, 44.55%);
  aspect-ratio: 280 / 380;
  border-radius: var(--p-radius-md);
  overflow: hidden;
  background-color: #111111;
}

.hero__portrait-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}

.hero__panel-visual--about-carousel {
  padding: 0;
  position: relative;
  overflow: hidden;
  background-color: var(--color-surface-inverted);
}

.about-hero-carousel {
  border-radius: 16px;
  overflow: hidden;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  /* Set directly on this absolutely-positioned element rather than
     as padding on the ancestor — the containing block for an
     absolute child is the ancestor's padding box, so ancestor
     padding doesn't reserve a visible gap; inset:0 would fill
     straight through it. */
  right: var(--space-lg);
}

.about-hero-carousel__slide {
  position: absolute;
  inset: 0;
  transition: transform 0.8s cubic-bezier(0.65, 0, 0.35, 1);
}

.about-hero-carousel__slide img,
.about-hero-carousel__slide video {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
}

/* Each slide's resting position is baked into its own direction — the
   side it enters from — so no dynamic pre-positioning is needed. */
.about-hero-carousel__slide[data-direction="rtl"] { transform: translateX(100%); }
.about-hero-carousel__slide[data-direction="ttb"] { transform: translateY(-100%); }
.about-hero-carousel__slide[data-direction="btt"] { transform: translateY(100%); }
.about-hero-carousel__slide[data-direction="ltr"] { transform: translateX(-100%); }

/* Must come AFTER the [data-direction] resting-position rules above —
   equal specificity (one class vs one attribute selector), so source
   order decides the winner. Without this order, is-active never
   actually wins and slides never reach center. */
.about-hero-carousel__slide.is-active {
  transform: translate(0, 0);
}

/* Exit transforms continue the incoming slide's direction (push effect) */
.about-hero-carousel__slide.is-exit-rtl { transform: translateX(-100%); }
.about-hero-carousel__slide.is-exit-ttb { transform: translateY(100%); }
.about-hero-carousel__slide.is-exit-btt { transform: translateY(-100%); }
.about-hero-carousel__slide.is-exit-ltr { transform: translateX(100%); }

.about-hero-carousel__slide.no-transition {
  transition: none;
}

.hero__gradient-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.6) 100%);
}

.hero__about-copy {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  text-align: center;
  padding: 0 var(--space-2xl) var(--space-4xl);
}

.hero__eyebrow--about,
.hero__title--about,
.hero__subtitle--about {
  color: var(--color-text-on-inverted);
}

.hero__subtitle--about {
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
}

@media (max-width: 1024px) {
  .hero__panel-visual--about-portrait,
  .hero__panel-visual--about-carousel {
    min-height: 420px;
  }

  /* Stacked layout: the overlay + copy still span the full section
     (both the portrait block and the carousel block below it), same
     as desktop — inset:0 from the base rules already covers this.
     Center instead of desktop's flex-end so the copy doesn't overflow
     upward past the top of a height-constrained stacked box. */
  .hero__about-copy {
    justify-content: center;
  }
}

@media (max-width: 640px) {
  .hero__portrait-card {
    width: min(227px, 52.65%);
  }
}


/* ================================================================
   CS-STORY-LEAD — Big opening statement (narrow label + large
   statement, side by side) with a full-width image beneath. Used to
   open a case-study narrative section, translated from a Figma
   wireframe (frog.co template) into this site's token system.
   ================================================================ */
.cs-story-lead {
  padding: var(--cs-section-py) 0 var(--space-2xl);
}

.cs-story-lead__row {
  display: flex;
  gap: var(--space-4xl);
  align-items: flex-start;
}

.cs-story-lead__label {
  flex: 0 0 auto;
  width: 160px;
  font-size: var(--text-body-lg);
  font-weight: var(--fw-heading);
  color: var(--color-text-primary);
}

.cs-story-lead__statement {
  flex: 1 1 auto;
  font-size: var(--text-h2);
  line-height: 1.4;
  letter-spacing: var(--tracking-heading);
  color: var(--color-text-secondary);
  max-width: 840px;
}

.cs-story-lead__statement strong {
  font-weight: var(--fw-heading);
  color: var(--color-text-primary);
}

.cs-story-lead__image {
  width: 100%;
  margin-top: var(--space-3xl);
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-light);
}

.cs-story-lead__image img {
  display: block;
  width: 100%;
  height: 560px;
  object-fit: cover;
  object-position: center top;
}

@media (max-width: 1024px) {
  .cs-story-lead__row {
    flex-direction: column;
    gap: var(--space-md);
  }
  .cs-story-lead__label { width: auto; }
  .cs-story-lead__image img { height: 380px; }
}

@media (max-width: 640px) {
  .cs-story-lead__image img { height: 280px; }
}


/* ================================================================
   CS-DUO-FIGURE — Two side-by-side images of differing width,
   following a text block (no split text/visual pairing needed).
   ================================================================ */
.cs-duo-figure {
  display: flex;
  gap: var(--space-2xl);
  margin: var(--space-3xl) 0;
  align-items: stretch;
}

.cs-duo-figure__item {
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-light);
}

.cs-duo-figure__item--lg { flex: 1.7 1 0; }
.cs-duo-figure__item--sm { flex: 1 1 0; }

.cs-duo-figure__item img {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 420px;
  object-fit: cover;
}

@media (max-width: 1024px) {
  .cs-duo-figure { flex-direction: column; }
  .cs-duo-figure__item img { min-height: 320px; }
}


/* ================================================================
   CS-MISSION — Challenge / Opportunity / Outcome style triptych.
   Stacked rows, each with a large index label, an accent overline
   heading, and body copy.
   ================================================================ */
.cs-mission {
  padding: var(--space-2xl) 0 var(--cs-section-py);
}

.cs-mission__heading {
  font-size: var(--text-h2);
  font-weight: var(--fw-heading);
  color: var(--color-text-primary);
  margin-bottom: 4px;
}

.cs-mission__subtitle {
  font-size: var(--text-body-lg);
  color: var(--color-text-secondary);
  margin-bottom: var(--space-3xl);
}

/* Two-column grid, content block anchored to the right column by
   default — the wireframe alternates which column each item's content
   sits in (Challenge: right, Opportunity: left, Outcome: right), so
   the whole group zigzags down the page rather than stacking in a
   fixed label/body row. Add .cs-mission__item--left to flip a row. */
.cs-mission__item {
  padding: var(--space-3xl) 0;
  border-top: 1px solid var(--color-border);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4xl);
}

.cs-mission__item:last-child {
  border-bottom: 1px solid var(--color-border);
}

.cs-mission__item-content {
  grid-column: 2;
  max-width: 480px;
}

.cs-mission__item--left .cs-mission__item-content {
  grid-column: 1;
  /* Wireframe insets the left-column item an extra 124px past the
     row's own left edge (on top of just occupying column 1) — closest
     token match is --space-6xl (128px). */
  padding-left: var(--space-6xl);
}

.cs-mission__item-title {
  font-size: var(--text-h3);
  font-weight: var(--fw-body);
  line-height: var(--leading-heading);
  color: var(--color-text-primary);
  margin-bottom: var(--space-sm);
}

.cs-mission__item-heading {
  font-size: var(--text-label);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--cs-accent);
  margin-bottom: var(--space-sm);
}

.cs-mission__item-body {
  font-size: var(--text-body);
  line-height: var(--leading-prose);
  color: var(--color-text-secondary);
}

@media (max-width: 768px) {
  .cs-mission__item {
    grid-template-columns: 1fr;
    gap: var(--space-sm);
  }

  .cs-mission__item-content,
  .cs-mission__item--left .cs-mission__item-content {
    grid-column: 1;
    max-width: none;
    padding-left: 0;
  }
}


/* ---- Light theme overrides for the new story components ---- */
body.theme--light .cs-story-lead__image,
body.theme--light .cs-duo-figure__item {
  background-color: var(--p-neutral-100);
  border-color: var(--p-neutral-200);
}


/* ================================================================
   CS-ACCENT-MUTED — opt-in modifier (set on <main>) for pages that
   want the cs-* component structure — chapter/mission dividers, split
   eyebrows, mission headings, list markers — without the per-project
   --cs-accent color splashed across them, and without the horizontal
   rules those dividers used regardless of color. Eyebrows/headings
   fall back to the same neutral grey (--color-text-tertiary) already
   used by .section__eyebrow elsewhere on the site.
   ================================================================ */
.cs-accent-muted .cs-chapter {
  border-top: none;
}

.cs-accent-muted .cs-mission__item {
  border-top: none;
}

.cs-accent-muted .cs-mission__item:last-child {
  border-bottom: none;
}

.cs-accent-muted .cs-chapter__number,
.cs-accent-muted .cs-split__eyebrow,
.cs-accent-muted .cs-mission__item-heading {
  color: var(--color-text-tertiary);
}

.cs-accent-muted .cs-split__body li::marker {
  color: var(--color-text-tertiary);
}

