/* ─────────────────────────────────────────────────────────────────────────────
   Case-study chrome — shared by every case study page (LIV, Thropic, …).
   The sticky rail, article rhythm, lede, media wells, stats and callout all come
   from the same Figma geometry, so they live here once instead of being copied
   per page and drifting. Page-specific pieces stay in the page's own <style>.
   Same rule as everywhere: calc(<figma-px> * var(--s)), literal = Figma value.
   ───────────────────────────────────────────────────────────────────────────── */
/* ─────────────────────────────────────────────────────────────────────────────
   LIV case study. Written from Figma page LIV → frame `Desktop` (40:19), 1440 wide:
   sticky rail 187 at x80, article 842 at x299, section gap 96.
   Same rule as everywhere else: calc(<figma-px> * var(--s)), literal = Figma value.
   ───────────────────────────────────────────────────────────────────────────── */
/* Primary nav on the case study, so you can reach another one without going home
   first. Figma has a loose `track` (176:1548) parked just above this frame, which is
   what this is. Delete .topbar and its markup if you'd rather the page stayed bare. */
.case{display:grid;grid-template-columns:calc(187px * var(--s)) minmax(0,calc(842px * var(--s)));
  gap:calc(32px * var(--s));justify-content:start;
  padding-top:calc(var(--nav-clear) - var(--pad) + 26px)}

/* ── reading progress ─────────────────────────────────────────────────────── */
/* A hairline of the accent red across the very top, filling left to right as you
   read. case.js builds and gates it — see the note there for why it is not in the
   markup. Scaled rather than resized: transform is the one property that can be
   changed every frame without asking for layout, and this changes every frame.
   z-index clears the nav's 50, so the bar is never tucked behind the pill. */
.progress{position:fixed;top:0;left:0;right:0;height:calc(3px * var(--s));
  z-index:60;background:var(--sail);
  transform:scaleX(0);transform-origin:0 50%;
  will-change:transform;pointer-events:none}
/* Scroll fires faster than the screen refreshes and the writes are already
   coalesced to one a frame, so this is only smoothing the last pixel of judder —
   short enough not to lag behind the thumb. */
@media (prefers-reduced-motion:no-preference){
  .progress{transition:transform .08s linear}
}

/* ── sticky rail ── 187 wide, gap 15, items 15/138% ───────────────────────── */
.rail{position:sticky;top:var(--nav-clear);align-self:start;
  display:flex;flex-direction:column;gap:calc(15px * var(--s))}
/* An "←" text glyph carries left side bearing, so it never lines up with the titles
   below it. An SVG has no bearing — it sits flush on the same left edge.
   It sits off the list by a bit more than the 15px rail rhythm so it reads as a
   separate control, without the cavernous 48px gap it started with. */
.rail .back{display:block;width:calc(20px * var(--s));color:var(--ink);
  margin-bottom:calc(13px * var(--s));
  transition:transform .3s var(--ease)}
.rail .back svg{width:100%;height:auto;display:block}
.rail .back:hover{transform:translateX(-4px)}
.rail nav{position:relative;display:flex;flex-direction:column;gap:calc(15px * var(--s))}
/* A marker that slides between items reads as continuous motion; swapping font-weight
   on the active item snapped (and Libre Baskerville has no Medium, so 400→700 badly
   overshot the weight Figma actually draws). Weight now stays put. */
.rail nav .marker{position:absolute;left:calc(-14px * var(--s));top:0;
  width:2px;height:calc(15px * var(--s) * 1.38);background:var(--deep);border-radius:2px;
  opacity:0;transform:translateY(0);
  transition:transform .42s cubic-bezier(.33,.9,.28,1),opacity .3s ease}
.rail nav .marker.on{opacity:1}
.rail nav a{font-size:calc(15px * var(--s));line-height:1.38;color:var(--ink);opacity:.45;
  width:max-content;transition:opacity .38s ease,color .38s ease}
.rail nav a:hover{opacity:.8}
.rail nav a[aria-current]{opacity:1;color:var(--deep)}
.rail hr{border:0;border-top:1px solid var(--ink);width:calc(40px * var(--s));
  margin:calc(4px * var(--s)) 0}

/* ── article ── section gap 96 ─────────────────────────────────────────────── */
.article{display:flex;flex-direction:column;gap:calc(96px * var(--s))}
/* Figma sets 96 between the article (Frame 58) and the footer (Frame 77); the .foot
   sat flush against the last section before this. */
.case + .foot{margin-top:calc(96px * var(--s))}
.article section{scroll-margin-top:var(--nav-clear);
  display:flex;flex-direction:column;gap:calc(22px * var(--s))}
.article .eyebrow{font-size:calc(20px * var(--s));line-height:1.4;color:var(--deep)}
.article h2{font-size:calc(36px * var(--s));font-weight:700;line-height:1.4;color:var(--ink)}
.article p{font-size:calc(20px * var(--s));line-height:1.4;color:var(--ink)}
.article p strong{font-weight:700;color:var(--deep)}
.article p a{color:var(--deep);font-weight:700;text-decoration:underline;
  text-decoration-thickness:1px;text-underline-offset:.18em;
  transition:color .25s ease,text-decoration-color .25s ease}
.article p a:hover,.article p a:focus-visible{color:var(--ink)}
.article .quiet{color:var(--steel)}

/* ── lede ── Frame 4: gap 38, head gap 23, h1 48/132 ──────────────────────── */
.lede{display:flex;flex-direction:column;gap:calc(38px * var(--s))}
.lede-head{display:flex;flex-direction:column;gap:calc(23px * var(--s))}
.lede h1{font-size:calc(48px * var(--s));font-weight:700;line-height:1.32;color:var(--ink)}
.lede .meta{font-size:calc(20px * var(--s));font-weight:700;line-height:1.4;color:var(--steel)}
/* ── testimonial callout ── Frame 43: steel, pad 43/78/42/77, r16, inner 688 ── */
.callout{background:var(--steel);border-radius:calc(16px * var(--s));
  padding:calc(43px * var(--s)) calc(78px * var(--s)) calc(42px * var(--s)) calc(77px * var(--s));
  display:flex;flex-direction:column;gap:calc(32px * var(--s))}
.callout blockquote{font-size:calc(32px * var(--s));font-weight:700;line-height:1.32;
  color:var(--ground);max-width:calc(688px * var(--s))}
.callout .who{font-size:calc(20px * var(--s));font-weight:700;line-height:1.32;color:#fff;
  white-space:pre-line}
/* the quote variant SCC and SAE both use — Figma pads these 48/56, not LIV's 43/78 */
.callout.q{padding:calc(48px * var(--s)) calc(56px * var(--s));gap:calc(26px * var(--s))}
.callout.q blockquote{font-size:calc(28px * var(--s));line-height:1.4;
  max-width:calc(732px * var(--s))}
.callout.q .who{font-size:calc(18px * var(--s));line-height:1.4}
.callout.q .who small{display:block;font-size:calc(16px * var(--s));font-weight:400;
  margin-top:calc(4px * var(--s))}

/* ── campaign stats ── 4 × 200, value 40/110, label 15/145 ────────────────── */
/* 4 × 200 across 844 in Figma, itemSpacing 0 — the slack is the gap, so no
   explicit gap here or the fourth stat wraps */
.stats{display:flex;justify-content:space-between;gap:0;
  margin-top:calc(10px * var(--s));flex-wrap:wrap}
.stat{display:flex;flex-direction:column;gap:calc(10px * var(--s));
  flex:0 0 auto;width:calc(var(--stat-w,200px) * var(--s))}
/* SCC and SAE sit their stats inside a card; LIV's run bare on the page.
   A boxed row loses 2×24 to padding, so fixed 200px stats overflow by ~6px and the
   last one silently wraps to a second line. Inside a box they share the row
   instead — that holds for four stats or five, and at any padding. */
.stats.boxed{background:var(--card);border:1px solid var(--hair);
  border-radius:calc(16px * var(--s));
  padding:calc(36px * var(--s)) calc(24px * var(--s));
  gap:calc(20px * var(--s));flex-wrap:nowrap}
.stats.boxed .stat{flex:1 1 0;width:auto;min-width:0}
.stat b{font-size:calc(40px * var(--s));font-weight:700;line-height:1.1;color:var(--ink)}
.stat.lead b{color:var(--sail)}
.stat span{font-size:calc(15px * var(--s));line-height:1.45;color:var(--steel)}


/* ── card grid ── Figma draws these identically on Thropic and SCC: 406×169,
   r16, 1px hairline, pad 22/24, gap 10. --cols switches 2-up vs 3-up. ────────── */
.cards{display:grid;grid-template-columns:repeat(var(--cols,2),1fr);
  gap:calc(32px * var(--s));margin-top:calc(10px * var(--s))}
.cards .card{background:var(--card);border:1px solid var(--hair);
  border-radius:calc(16px * var(--s));
  padding:calc(22px * var(--s)) calc(24px * var(--s));
  display:flex;flex-direction:column;gap:calc(10px * var(--s));
  transition:transform .38s var(--ease),box-shadow .38s ease,border-color .38s ease}
.cards .card:hover{transform:translateY(-4px);border-color:rgb(29 51 84 / .28);
  box-shadow:0 calc(14px * var(--s)) calc(26px * var(--s)) calc(-10px * var(--s)) rgb(29 51 84 / .18)}
.cards .n{font-size:calc(16px * var(--s));line-height:1.4;color:var(--deep)}
.cards h3{font-size:calc(24px * var(--s));font-weight:700;line-height:1.32;color:var(--ink)}
.cards p{font-size:calc(16px * var(--s));line-height:1.5;color:var(--steel)}
/* Figma sets the 3-up cards a size down from the 2-up ones */
.cards.sm .n{font-size:calc(15px * var(--s))}
.cards.sm h3{font-size:calc(22px * var(--s))}
.cards.sm p{font-size:calc(15px * var(--s));line-height:1.5}


/* ── video facade ── poster now, player on click ─────────────────────────────
   The poster is a real link to YouTube, which JS upgrades into an inline player.
   That way it degrades to "opens the video" rather than a dead image if the
   script is stale, blocked, or still loading — a button would just sit there.
   Colours use rgba() and explicit offsets rather than the newer rgb( / ) and
   inset shorthand, so nothing here depends on recent CSS parsing. */
.video{position:relative;display:block;width:100%;aspect-ratio:16/9;
  border-radius:calc(16px * var(--s));overflow:hidden;background:#0b1420;
  margin-top:calc(10px * var(--s));text-decoration:none;color:inherit}
.video img{width:100%;height:100%;object-fit:cover;display:block}
.video iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0}
.video .play{position:absolute;top:0;left:0;right:0;bottom:0;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(to bottom,rgba(11,20,32,.10),rgba(11,20,32,.34));
  transition:background .35s ease;pointer-events:none}
.video .play svg{width:calc(78px * var(--s));height:calc(78px * var(--s));
  filter:drop-shadow(0 calc(6px * var(--s)) calc(16px * var(--s)) rgba(11,20,32,.45));
  transition:transform .35s var(--ease)}
.video:hover .play{background:linear-gradient(to bottom,rgba(11,20,32,.04),rgba(11,20,32,.24))}
.video:hover .play svg,.video:focus-visible .play svg{transform:scale(1.08)}
.video:focus-visible{outline:2px solid var(--steel);outline-offset:3px}
.video .disc{fill:#B8333A}
.video .tri{fill:#F8F8F3}
@media (prefers-reduced-motion:reduce){
  .video .play,.video .play svg{transition:none}
}

/* ── media wells ── #d9d9d9 r16 placeholders, exactly as they sit in Figma ── */
.well{background:#d9d9d9;border-radius:calc(16px * var(--s));overflow:hidden}
/* video tiles — muted loops that fill their well; the JS only fetches them once
   they scroll into view, so a page with four of them still loads like a page
   with none until you reach the section */
.well video{width:100%;height:100%;object-fit:cover;display:block}
.videos{display:grid;grid-template-columns:repeat(3,1fr);gap:calc(32px * var(--s));
  margin-top:calc(10px * var(--s))}
.videos .a{grid-column:1;grid-row:1 / span 2;aspect-ratio:260 / 523}
.videos .b{grid-column:2 / span 2;grid-row:1;aspect-ratio:552 / 246}
.videos .c{grid-column:2;grid-row:2;aspect-ratio:260 / 246}
.videos .d{grid-column:3;grid-row:2;aspect-ratio:260 / 246}
.ads{display:grid;grid-template-columns:repeat(4,1fr);gap:calc(32px * var(--s));
  margin-top:calc(10px * var(--s))}
.ad{display:flex;flex-direction:column;gap:calc(15px * var(--s))}
/* The well is the backdrop; the creative sits on top of it. If a file isn't there
   yet the img removes itself and you get the grey well back, never a broken icon. */
/* LIV's ads are square 1080s; Thropic's are 187×156. The page sets --ad-ratio. */
.ad .well{aspect-ratio:var(--ad-ratio,1);overflow:hidden;position:relative}
.ad .well img{width:100%;height:100%;object-fit:cover;display:block}
.ad span{font-size:calc(20px * var(--s));line-height:1.4;color:var(--ink)}

/* No takeaway paragraph in Figma carries a real line break (checked all four
   pages), so pre-line was only ever turning source wrapping into visible breaks.
   Don't reinstate it — express any deliberate break as separate <p> elements. */
.takeaways p{line-height:1.58}

/* ── next project ── each case study ends by handing you the next one, so the
   read doesn't dead-end. Sits inside .article so it lines up with the copy
   column rather than spanning under the rail. */
.next{display:flex;justify-content:space-between;align-items:baseline;
  gap:calc(24px * var(--s));
  border-top:1px solid var(--hair);
  padding-top:calc(28px * var(--s));margin-top:calc(20px * var(--s));
  color:var(--ink)}
.next .lbl{font-size:calc(16px * var(--s));line-height:1.4;color:var(--steel)}
.next .name{display:inline-flex;align-items:baseline;gap:calc(12px * var(--s));
  font-size:calc(26px * var(--s));font-weight:700;line-height:1.3;
  transition:color .3s ease}
.next .name svg{width:calc(22px * var(--s));height:auto;flex:none;
  transform:translateY(calc(-2px * var(--s)));
  transition:transform .34s var(--ease)}
.next:hover .name{color:var(--deep)}
.next:hover .name svg{transform:translate(calc(6px * var(--s)),calc(-2px * var(--s)))}
@media (max-width:1000px){
  .next{flex-direction:column;align-items:flex-start;gap:calc(6px * var(--s))}
  .next .name{font-size:calc(22px * var(--s))}
}

@media (prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}
@media (prefers-reduced-motion:reduce){
  .rail nav .marker{transition:none}
  .rail nav a{transition:none}
}
@media (max-width:1000px){
  .case{grid-template-columns:1fr;padding-top:calc(24px * var(--s))}
  .rail{position:static;flex-direction:row;flex-wrap:wrap;align-items:center;
    gap:calc(12px * var(--s));padding-bottom:calc(16px * var(--s));
    border-bottom:1px solid var(--hair)}
  .rail .sp,.rail hr{display:none}
  .rail nav{flex-direction:row;flex-wrap:wrap;gap:calc(12px * var(--s))}
  .split,.feat,.feat.flip{grid-template-columns:1fr}
  .feat.flip .feat-copy{order:0;text-align:left}
  .feat.flip img{order:1}
  .ads{grid-template-columns:repeat(2,1fr)}
  /* A nowrap stat row can't shrink past its widest number ("505,379"), and as a
     grid item that min-content width becomes the whole article column — which
     was pushing the SAE page 175px wider than the phone. Two-up grid instead. */
  /* Grid/flex items default to min-width:auto, so the widest unbreakable child
     sets the column and the whole page grows past the phone. Let the case column
     shrink, and collapse the card grids that still declare 3 columns inline. */
  .case > *{min-width:0}
  /* At 48px the longest word in a title ("Commencement,") is wider than a phone
     and pushes the page 39px sideways. Smaller headline, plus break-word as a
     backstop so a future long title can't do it again. */
  .lede h1{font-size:calc(38px * var(--s));overflow-wrap:break-word}
  .cards{grid-template-columns:1fr}
  .stats,.stats.boxed{display:grid;grid-template-columns:repeat(2,1fr);
    gap:calc(26px * var(--s)) calc(16px * var(--s))}
  .stats .stat{width:auto}
  .stats.boxed{padding:calc(28px * var(--s)) calc(20px * var(--s))}
}
