/* ==========================================================================================
   ND CASE STUDIES PAGE — /case-studies/   (enqueued only on is_page('case-studies'))
   ------------------------------------------------------------------------------------------
   Approved direction (Nathan, 2026-08-11, "Mockup 1 · editorial index"): a landing like About /
   Services, then the five case studies as full editorial bands (alternating image / copy) that
   REVEAL on scroll — the picture wipes in slowly, the name resolves per character, the tagline and
   the "what we did" chips stage in. A WHITE closing ("proof in numbers") ends it so the home footer's
   rising-slat wipe reads white -> black. Each band carries id="<slug>" so the five home cards
   (/case-studies/#<slug>) land on the right study. The full per-client case study is NOT built yet.

   ⚠️ COMPONENTS RE-PROVIDED ON PURPOSE (same as nd-about-page.css / nd-services-page.css): the Line
   CTA and the per-character reveal base live in nd-home.css, which is FRONT-PAGE ONLY, so they are
   copied here. Their JS is sitewide (nd-motion.js).

   THE HEADER: the page opens DARK, so the fixed header keeps its site default (white). The ink twin
   is masked in ONLY over the white closing (nd-case-studies-page.js), the same flip Services uses.
   ========================================================================================== */

/* The footer wipe rises black over the white closing above it. initFooter reads --nd-ftr-floor. */
:root { --nd-ftr-floor: var(--nd-color-paper); }

.nd-cs-page { background: var(--nd-color-ink); }
/* color is set once on <html> (dark) and inherits its COMPUTED value, so a light section must
   re-declare it or it renders cream-on-white (same fix as About / Services). */
.nd-cs-page [data-nd-theme] { color: var(--nd-text); }

/* ══════════════════════════════════════════════════════════════════════ LINE CTA (reused)
   Reproduced from nd-home.css / nd-services-page.css — the COMPONENT only. Hover sweep restarted by
   nd-motion.js (sitewide) via .nd-cta-sweep. Depends on .nd-fill (nd-base.css, sitewide). */
.nd-hero__cta {
  --nd-cta-fs: clamp(11px, calc(6px + 0.4688vw), 24px);
  --nd-fill-inset: -0.85em -1.1em -0.15em;
  --nd-fill-radius: 0;
  --nd-cta-dur: 0.75s;
  --nd-cta-stagger: var(--nd-cta-stagger-base, 34ms);
  --nd-cta-travel: 4.5em;
  --nd-cta-rule-pad: 0.85em;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5em;
  inline-size: 18em;
  max-inline-size: 100%;
  padding-block-end: 0.85em;
  min-block-size: 24px;
  font-family: var(--nd-typography-eyebrow-font-family);
  font-weight: 400;
  font-size: var(--nd-cta-fs);
  letter-spacing: 0.22em;
  line-height: 1;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--nd-text);
  -webkit-tap-highlight-color: transparent;
}
.nd-hero__cta::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 1px;
  background: var(--nd-line-strong);
  transform-origin: left center;
  transition: background var(--nd-dur-fast) var(--nd-ease);
}
.nd-hero__cta:is(:hover, :focus-visible, .is-hover)::after { background: var(--nd-text); }
.nd-hero__cta.nd-cta-sweep::after { animation: nd-cta-underline var(--nd-dur-slower) var(--nd-ease); }
@keyframes nd-cta-underline {
  0%   { transform: scaleX(1); transform-origin: right center; }
  49%  { transform: scaleX(0); transform-origin: right center; }
  50%  { transform: scaleX(0); transform-origin: left center; }
  100% { transform: scaleX(1); transform-origin: left center; }
}
.nd-hero__cta-arrow {
  flex: none;
  inline-size: 1.2em;
  block-size: auto;
  overflow: visible;
  transition: transform var(--nd-cta-dur, 0.75s) var(--nd-ease), clip-path var(--nd-cta-dur, 0.75s) var(--nd-ease), opacity var(--nd-cta-dur, 0.75s) var(--nd-ease);
  transition-delay: 0.34s;
}
.nd-hero__cta:is(:hover, :focus-visible, .is-hover) .nd-hero__cta-arrow {
  transform: translateX(3.5em);
  clip-path: inset(0 0 0 100%);
  opacity: 0;
  transition-delay: 0s;
}
.nd-hero__cta .nd-word { display: inline-block; white-space: nowrap; }
.nd-cta-char { display: inline-block; }
.nd-hero__cta .nd-cta-char {
  transition: transform var(--nd-cta-dur, 0.75s) var(--nd-ease);
  transition-delay: calc(var(--i, 0) * var(--nd-cta-stagger, 34ms));
}
.nd-hero__cta:is(:hover, :focus-visible, .is-hover) .nd-cta-char {
  transform: translateX(var(--nd-cta-travel, 4.5em));
  transition-delay: calc((var(--n, 13) - 1 - var(--i, 0)) * var(--nd-cta-stagger, 34ms));
}
.nd-hero__cta::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0;
  inset-block-end: var(--nd-cta-rule-pad, 0.85em);
  margin-block: auto;
  inline-size: 1.2em;
  block-size: 0.8em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 16'%3E%3Cpath d='M0 8h21M15 1.5 21.5 8 15 14.5' fill='none' stroke='%23fff' stroke-width='1.6'/%3E%3C/svg%3E") left center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 16'%3E%3Cpath d='M0 8h21M15 1.5 21.5 8 15 14.5' fill='none' stroke='%23fff' stroke-width='1.6'/%3E%3C/svg%3E") left center / contain no-repeat;
  opacity: 0;
  transform: translateX(-2em);
  clip-path: inset(0 100% 0 0);
  transition: opacity var(--nd-cta-dur, 0.75s) var(--nd-ease), transform var(--nd-cta-dur, 0.75s) var(--nd-ease), clip-path var(--nd-cta-dur, 0.75s) var(--nd-ease);
  transition-delay: 0s;
  pointer-events: none;
}
.nd-hero__cta:is(:hover, :focus-visible, .is-hover)::before {
  opacity: 1;
  transform: translateX(0);
  clip-path: inset(0);
  transition-delay: 0.42s;
}
@media (prefers-reduced-motion: reduce) {
  .nd-cta-char, .nd-hero__cta-arrow, .nd-hero__cta::before { transition: none; }
  .nd-hero__cta:is(:hover, :focus-visible, .is-hover)::after { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════ CHAR REVEAL (reused)
   The per-character "cycle" — RE-PROVIDED here (its base lives in nd-home.css, front-page only). Two
   things need it: the sitewide FOOTER headline + labels, and this page's headings. Held copy is
   released by initFooter / this page's JS; unheld copy by nd-motion.js on scroll-in. */
.nd-word { display: inline-block; white-space: nowrap; }
.nd-char { display: inline-block; opacity: 0; filter: blur(var(--nd-char-blur)); }
.nd-chars-in.is-in:not(.is-settled) .nd-char { will-change: filter, opacity; }
.nd-chars-in.is-in .nd-char {
  animation: nd-char-in var(--nd-char-dur) var(--nd-ease-out) both;
  animation-delay: var(--nd-char-d, 0ms);
}
@keyframes nd-char-in {
  from { opacity: 0; filter: blur(var(--nd-char-blur)); }
  to   { opacity: 1; filter: blur(0); }
}
.nd-chars-in.is-settled .nd-char { opacity: 1; filter: none; animation: none; }
.no-js .nd-chars-in .nd-char { opacity: 1; filter: none; animation: none; }
@media (prefers-reduced-motion: reduce) { .nd-chars-in .nd-char { opacity: 1; filter: none; animation: none; } }

/* ══════════════════════════════════════════════════════════════════════ THE LANDING */
/* Restructured to the About landing pattern (Nathan, 2026-08-12): centred sentence + subtext over the
   prism video, with a wide-tracked "CASE STUDIES" label on the lower edge. */
/* The landing STAYS PUT and the index sweeps up over it (Nathan, 2026-08-12): sticky at the top with
   the lowest z-index, while .csp-index (z-index 2, opaque) rises over it as the reader scrolls. Native
   scroll throughout — the page is never held; the hero is just pinned behind the rising panel. */
.csp-lead { position: sticky; top: 0; z-index: 0; min-block-size: 100svh; block-size: 100svh; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; padding-inline: clamp(24px, 7vw, 140px); overflow: hidden; background: var(--nd-color-ink); }
.csp-lead__bg { position: absolute; inset: 0; z-index: 0; }
/* prism video treated EXACTLY like the home hero (Nathan, 2026-08-13: "look the same as the hero").
   The hero plays the raw nd-prism-1920.mp4 at full opacity with NO scrim, NO filter, NO veil
   (nd-home.css: .nd-scene__backdrop + the "NO SCRIM" note). So: no brightness() here either — the
   earlier filter/veil made the landings brighter than the hero. Same treatment on About / Services. */
.csp-lead__bg video { inline-size: 100%; block-size: 100%; object-fit: cover; }
.csp-lead__in { position: relative; z-index: 1; max-inline-size: var(--nd-container-wide); margin-inline: auto; inline-size: 100%; }
.csp-lead__h { font-family: var(--nd-typography-display-font-family); font-weight: var(--nd-typography-display-font-weight); letter-spacing: -0.045em; line-height: 0.92; font-size: clamp(2.9rem, calc(1rem + 8.5vw), 9rem); max-inline-size: 15ch; margin-inline: auto; }
.csp-lead__h .ab-accent .nd-char { color: var(--nd-accent); }
.csp-lead__sub { margin-block-start: clamp(24px, 3vw, 48px); max-inline-size: 44ch; margin-inline: auto; font-size: clamp(1.15rem, calc(0.9rem + 1vw), 1.55rem); line-height: 1.5; color: var(--nd-text-soft); }
/* the wide-tracked label centred on the landing's lower edge (mirrors About's .ab-rail--hero) */
.csp-lead__rail { position: absolute; z-index: 1; inset-block-end: clamp(20px, 2vh, 40px); inset-inline-start: 50%; transform: translateX(-50%); font-family: var(--nd-typography-eyebrow-font-family); font-weight: 400; font-size: clamp(13px, calc(8px + 0.6vw), 30px); letter-spacing: 0.42em; line-height: 1; text-transform: uppercase; white-space: nowrap; color: var(--nd-text-muted); }

/* ══════════════════════════════════════════════════════════════════════ THE INDEX */
.csp-index { position: relative; z-index: 2; background: var(--nd-color-ink); }
.csp-study {
  /* STICKY STACK (Nathan, 2026-08-16): each band PINS at the top and the next slides up OVER it, so
     the studies stack like cards instead of scrolling past one another — the first covers the landing,
     the second covers the first, and so on to the last. Full-height + opaque so each fully covers the
     one beneath; z-index 1 keeps them above the sticky landing (z:0) and below the closing (z:2);
     later bands paint over earlier ones by DOM order within the same z. The old between-band top
     border is dropped — with stacking it would draw a seam sliding up on every band. */
  position: sticky; top: 0; z-index: 1;
  background: var(--nd-color-ink);
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(30px, 4vw, 80px);
  align-items: center; padding: clamp(48px, 8vh, 120px) clamp(24px, 6vw, 120px); min-block-size: 100lvh;
  scroll-margin-block-start: calc(var(--nd-header-h, 80px) + 20px);   /* deep-link lands clear of the fixed header */
}
.csp-study:nth-child(even) .csp-study__media { order: 2; }

/* the picture — a wipe + a settle-from-scale. Sweep sped up (Nathan, 2026-08-12: the images must
   sweep in faster) from the earlier 2.2s / 2.6s. */
.csp-study__media { position: relative; overflow: hidden; background: #141216; aspect-ratio: 4 / 3; border-radius: 16px; clip-path: inset(0 0 100% 0 round 16px); transition: clip-path 1.1s var(--nd-ease-out); }
.csp-study__media.is-in { clip-path: inset(0 0 0 0 round 16px); }
.csp-study__media img { inline-size: 100%; block-size: 100%; object-fit: cover; transform: scale(1.08); transition: transform 1.35s var(--nd-ease-out); }
.csp-study__media.is-in img { transform: scale(1); }

/* ⚠️ THE BODY USES THE FULL COLUMN (Nathan, 2026-08-16). An earlier 62ch cap here was an INVENTED
   boundary: the namerow was squeezed into ~624px, which forced the "Explore project" CTA to wrap (or
   be shrunk) even though the column has plenty of real width. The reading-width cap lives on the
   tagline + the "what we did" list instead, so those still hold a comfortable measure. */
.csp-study__body { max-inline-size: 100%; }
.csp-study__tag { max-inline-size: 46ch; }
.csp-study__did { max-inline-size: 46ch; }
.csp-study__num { font-family: var(--nd-typography-display-font-family); font-weight: 800; font-size: clamp(1.1rem, 1.5vw, 1.55rem); color: var(--nd-text-muted); letter-spacing: 0.1em; }
/* copy next to the image bumped up (Nathan, 2026-08-12: it reads small and hard to read) */
.csp-study__sector { font-family: var(--nd-typography-eyebrow-font-family); font-size: clamp(12px, 0.95vw, 14px); letter-spacing: 0.22em; text-transform: uppercase; color: var(--nd-text-muted); margin-block: 1.4em 0.5em; }
/* ⚠️ SIZED TO KEEP THE CTA BESIDE IT (Nathan, 2026-08-16). Was clamp(2.8rem, 6vw, 5.4rem) — at that
   size a long name (Northspan/Multiknit) + the "Explore project" link never fit on one line and the
   CTA wrapped below. 4vw scales the name with the column so the CTA fits on the same line at every
   width; the name is still large and bold, just no longer full-bleed. */
.csp-study__name { font-family: var(--nd-typography-display-font-family); font-weight: 800; letter-spacing: -0.03em; line-height: 0.95; font-size: clamp(2.2rem, 4vw, 4.2rem); }
/* tagline / rule / chips stage in when the body enters (data-nd-reveal -> .is-in) */
.csp-study__tag { margin-block-start: 0.45em; font-family: var(--nd-typography-display-font-family); font-weight: 600; font-size: clamp(1.3rem, 2.15vw, 1.95rem); line-height: 1.2; color: var(--nd-text); }
.csp-study__rule { block-size: 1px; background: rgba(242,242,242,0.16); margin-block: clamp(18px, 2.4vh, 30px); }
/* the "what we did" — an even 2-col grid so the four read as a placed set, not a squeezed wrap
   (Nathan, 2026-08-12). Each chip resolves per character (the site "cycle") when it scrolls in. */
.csp-study__did { list-style: none; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(0.7em, 1.4vh, 1.05em) 2em; margin: 0; padding: 0; }
.csp-study__did li { font-family: var(--nd-typography-eyebrow-font-family); font-size: clamp(13px, 1vw, 15px); letter-spacing: 0.04em; color: var(--nd-text-soft); position: relative; padding-inline-start: 1.15em; }
.csp-study__did li::before { content: ""; position: absolute; inset-inline-start: 0; inset-block-start: 0.62em; inline-size: 12px; block-size: 1px; background: rgba(242,242,242,0.4); }
/* the chips are their own char-cycle targets; stagger chip-to-chip by --i on top of each chip's own
   scatter (specificity beats the generic .nd-chars-in .nd-char rule so the base delay is added). */
.csp-study__did li.nd-chars-in.is-in .nd-char { animation-delay: calc(var(--i, 0) * 0.11s + var(--nd-char-d, 0ms)); }
/* CTA NEXT TO THE NAME, on the RIGHT, same level (Nathan, 2026-08-16) — a single row: the big client
   name on the left, the "Explore project" link pushed to the right and sitting on the name's
   baseline. No wrap (it stays beside the name, not under it); auto width, no top margin. */
/* CTA sits RIGHT AFTER the name (flex-start), on its baseline (Nathan, 2026-08-16). Not space-between:
   with the full-column row, pushing the CTA to the far edge would strand it a long way from the name
   on a wide screen. Right after the name keeps it "next to the name" at every width, at its natural
   size, with the empty space simply falling to the right. Wraps only if a row genuinely can't hold
   both (narrow laptops). */
.csp-study__namerow { display: flex; align-items: baseline; justify-content: flex-start; flex-wrap: wrap; gap: clamp(10px, 1.2vh, 18px) clamp(16px, 1.6vw, 36px); }
/* CTA at its NATURAL size — the earlier font cap that made it tiny is gone (Nathan, 2026-08-16: the
   CTAs looked too small and there is ample space). It keeps the shared --nd-cta-fs, so it scales with
   the viewport like every other Line CTA; the full-column row + right-after-the-name placement give
   it the room, so it no longer needs shrinking to avoid a wrap. */
.csp-study__cta { inline-size: auto; margin-block-start: 0; flex: none; }

/* reveal states (nd-motion.js adds .is-in to [data-nd-reveal]). The chips are NO LONGER here — they
   reveal per character via .nd-chars-in (the cycle), so they must stay visible for the chars to show. */
.csp-study__tag, .csp-study__rule { opacity: 0; transform: translateY(12px); }
.csp-study__tag { transition: opacity 0.7s var(--nd-ease-out) 0.1s, transform 0.7s var(--nd-ease-out) 0.1s; }
.csp-study__rule { transform: scaleX(0); transform-origin: left; transition: transform 0.9s var(--nd-ease-out) 0.22s; }
.csp-study__body.is-in .csp-study__tag { opacity: 1; transform: none; }
.csp-study__body.is-in .csp-study__rule { transform: scaleX(1); }

/* ══════════════════════════════════════════════════════════════════════ PER-CLIENT THEMED BANDS
   Each band wears its client's world — colour + display font — matching that client's case-study
   detail page (Nathan, 2026-08-12). All colour/font values arrive as CSS vars set inline per band in
   case-studies-index.php (--cs-bg / --cs-ink / --cs-soft / --cs-muted / --cs-line / --cs-accent /
   --cs-font / --cs-weight / --cs-track), so this block is written ONCE and adding a client is data only.
   Cormorant Garamond (Vanterra) is self-hosted; the other clients use Georgia (system) or the site
   display font. The fixed header's ink flip over light bands is handled in nd-case-studies-page.js. */
@font-face { font-family: 'Cormorant Garamond'; src: url('../fonts/cormorant-garamond-400.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Cormorant Garamond'; src: url('../fonts/cormorant-garamond-500.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; }

/* Every --cs-* is set inline per band (case-studies-index.php); the fallbacks are dark-page-safe
   defaults so a missing var degrades gracefully (and satisfies the token lint). */
.csp-study--themed { background: var(--cs-bg, #0d0d0d); color: var(--cs-ink, #f2f2f2); border-block-start-color: var(--cs-line, rgba(242,242,242,0.16)); }
.csp-study--themed .csp-study__num { color: var(--cs-accent, #f2f2f2); font-family: var(--cs-font, var(--nd-typography-display-font-family)); font-weight: var(--cs-weight, 800); }
.csp-study--themed .csp-study__sector { color: var(--cs-accent, #f2f2f2); }
.csp-study--themed .csp-study__name { color: var(--cs-ink, #f2f2f2); font-family: var(--cs-font, var(--nd-typography-display-font-family)); font-weight: var(--cs-weight, 800); letter-spacing: var(--cs-track, -0.03em); }
.csp-study--themed .csp-study__tag { color: var(--cs-ink, #f2f2f2); font-family: var(--cs-font, var(--nd-typography-display-font-family)); font-weight: var(--cs-weight, 800); }
.csp-study--themed .csp-study__rule { background: var(--cs-line, rgba(242,242,242,0.16)); }
.csp-study--themed .csp-study__did li { color: var(--cs-soft, var(--nd-text-soft)); }
.csp-study--themed .csp-study__did li::before { background: var(--cs-accent, #f2f2f2); }
.csp-study--themed .csp-study__media { background: color-mix(in srgb, var(--cs-ink, #f2f2f2) 12%, var(--cs-bg, #0d0d0d)); }
/* the Line CTA — recoloured to the band ink (its defaults are the dark-page globals) */
.csp-study--themed .nd-hero__cta { color: var(--cs-ink, #f2f2f2); }
.csp-study--themed .nd-hero__cta::after { background: var(--cs-line, rgba(242,242,242,0.16)); }
.csp-study--themed .nd-hero__cta:is(:hover, :focus-visible, .is-hover)::after { background: var(--cs-ink, #f2f2f2); }

/* ══════════════════════════════════════════════════════════════════════ CLOSING (WHITE) — proof in numbers */
.csp-close { position: relative; z-index: 2; min-block-size: 100lvh; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; padding: var(--nd-section-y) var(--nd-gutter); background: var(--nd-color-paper); }
.csp-close__eyebrow { font-family: var(--nd-typography-eyebrow-font-family); font-size: var(--nd-typography-eyebrow-font-size); letter-spacing: var(--nd-typography-eyebrow-letter-spacing); text-transform: uppercase; color: var(--nd-text-muted); margin-block-end: 1.6em; }
/* bigger + one word set in the brand orange (Nathan, 2026-08-12) */
.csp-close__h { font-family: var(--nd-typography-display-font-family); font-weight: 800; letter-spacing: -0.03em; line-height: 1.04; font-size: clamp(2.5rem, 5.8vw, 4.9rem); max-inline-size: 20ch; }
.csp-close__h .ab-accent .nd-char { color: var(--nd-accent); }
.csp-close__stats { display: flex; gap: clamp(30px, 6vw, 96px); flex-wrap: wrap; justify-content: center; margin-block-start: clamp(48px, 7vw, 96px); padding-block-start: clamp(30px, 3.4vw, 50px); border-block-start: 1px solid rgba(13,13,13,0.16); }
.csp-close__stat { text-align: center; opacity: 0; transform: translateY(14px); transition: opacity 0.6s var(--nd-ease-out), transform 0.6s var(--nd-ease-out); }
.csp-close__stats.is-in .csp-close__stat { opacity: 1; transform: none; transition-delay: calc(var(--i, 0) * 0.1s); }
.csp-close__stat b { font-family: var(--nd-typography-display-font-family); font-weight: 800; font-size: clamp(2.4rem, 4.4vw, 4rem); display: block; line-height: 1; }
.csp-close__stat span { font-family: var(--nd-typography-eyebrow-font-family); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--nd-text-muted); margin-block-start: 0.6em; display: block; }

/* ══════════════════════════════════════════════════════════════════════ RESTS-IN-FINISHED-STATE + REDUCED MOTION
   With no JS nothing adds .is-in, so un-hide every reveal target (the "rests in its finished state"
   rule). Reduced motion keeps everything shown and drops the transitions. */
.no-js .csp-study__media { clip-path: none; }
.no-js .csp-study__media img { transform: none; }
.no-js :is(.csp-study__tag, .csp-study__rule, .csp-study__did li, .csp-close__stat) { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .csp-study__media { clip-path: none !important; transition: none; }
  .csp-study__media img { transform: none !important; transition: none; }
  :is(.csp-study__tag, .csp-study__rule, .csp-study__did li, .csp-close__stat) { opacity: 1 !important; transform: none !important; transition: none; }
}

@media (max-width: 900px) {
  .csp-study { grid-template-columns: 1fr; gap: clamp(20px, 5vw, 34px); min-block-size: auto; padding-block: clamp(56px, 12vh, 96px); }
  .csp-study:nth-child(even) .csp-study__media { order: 0; }
  /* one column on a phone — the longer labels wrap badly across two narrow columns */
  .csp-study__did { grid-template-columns: 1fr; }
}
