/* =========================================================================
   CoreWeave — landing page
   Figma: CW / node 31:386 (1440 × 9587)

   Every value below comes off the Figma frame. Where the design gives one
   number at 1440, the CSS gives a clamp() whose upper bound is that number,
   so the page is identical at 1440 and degrades proportionally below it.
   ========================================================================= */

/* ---------------------------------------------------------------- tokens -- */
:root {
  /* palette */
  --ink:        #030616;
  --blue:       #1e3fdf;
  --pale:       #d8ffff;
  --navy:       #060d2d;
  --black:      #000000;
  --white:      #ffffff;

  --ink-40:     rgba(3, 6, 22, .4);
  --ink-30:     rgba(3, 6, 22, .3);
  --ink-50:     rgba(3, 6, 22, .5);
  --rule:       rgba(0, 0, 0, .4);
  --rule-light: rgba(255, 255, 255, .2);
  --rule-dot:   rgba(255, 255, 255, .4);

  /* The real design fonts. The first name catches a local desktop install
     (Adobe CC sync), the second is the same family served from the Adobe Fonts
     web kit — so everyone gets the actual typeface, not an approximation. */
  --sans: "Rig Sans", "rig-sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "Novel Mono Pro Cnd", "novel-mono-pro-condensed", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* fluid scale — upper bound == the Figma value at 1440 */
  --fs-hero:    clamp(44px, 8.334vw, 120px);   /* 120 */
  --fs-h1:      clamp(30px, 3.334vw, 48px);    /*  48 */
  --fs-h2:      clamp(27px, 2.917vw, 42px);    /*  42 */
  --fs-h3:      clamp(27px, 2.778vw, 40px);    /*  40 */
  --fs-quote:   clamp(28px, 3.611vw, 52px);    /*  52 */
  --fs-mono-xl: clamp(26px, 2.917vw, 42px);    /*  42 */
  --fs-nav-lg:  clamp(22px, 2.223vw, 32px);    /*  32 */
  --fs-ten:     clamp(120px, 21.53vw, 310px);  /* 310 */
  --fs-lede:    clamp(17px, 1.389vw, 20px);    /*  20 */
  --fs-body-m:  clamp(16px, 1.25vw, 18px);     /*  18 */
  /* Body copy in the why items and the blue tiles, the resting size of the
     circled arrows, and the why panel's padding. The frames set this copy at
     14; 16 is a deliberate step up from that, and the panel still lands on the
     frame's 760 with its own 80 of padding — measured, not assumed. */
  --fs-body-s:  16px;
  --arrow-ring: 1;            /* the ring's resting scale on a 32px box */
  --arrow-ring-hover: 1.28;
  --why-pad:    var(--pad-80);   /* lands the section on the frame's 760 */
  --fs-mono-m:  16px;
  --fs-label:   12px;
  --fs-nav:     14px;

  /* spacing — 40 is the page gutter at 1440 */
  --gutter:  clamp(20px, 2.778vw, 40px);       /*  40 */
  --pad-48:  clamp(24px, 3.334vw, 48px);       /*  48 */
  --pad-80:  clamp(28px, 5.556vw, 80px);       /*  80 */
  --band:    clamp(56px, 8.334vw, 120px);      /* 120 */

  --nav-h: 108px;
}

/* ------------------------------------------------------------------ base -- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 500;
  font-size: var(--fs-body-s);
  line-height: 1.43;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; }
a   { color: inherit; text-decoration: none; }
h1, h2, h3, p, blockquote, figure { margin: 0; }
ul  { margin: 0; padding: 0; list-style: none; }
address { font-style: normal; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }

:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

/* ------------------------------------------------- smooth scroll plumbing -- */
/* When JS enables inertial scrolling the content is translated inside a fixed
   viewport and <body> is padded out to the real document height. Without JS
   (or with reduced motion / touch) everything stays in normal flow. */
html.is-smooth #smooth-wrapper {
  position: fixed;
  inset: 0;
  overflow: hidden;
  will-change: transform;
}
html.is-smooth #smooth-content { will-change: transform; }
html:not(.is-smooth) { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html:not(.is-smooth) { scroll-behavior: auto; }
}

/* ------------------------------------------------------- reveal-on-scroll -- */
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity .7s cubic-bezier(.22, 1, .36, 1),
              transform .7s cubic-bezier(.22, 1, .36, 1);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* The hero's own entrance is bigger and slower than the scroll reveals — it
   plays on the load-in white sheet, before the photo mosaic starts, so it can
   afford to: a longer rise and a soft blur that resolves as each line lands. */
.hero [data-reveal] {
  transform: translate3d(0, 36px, 0);
  filter: blur(10px);
  transition: opacity   1.15s cubic-bezier(.22, 1, .36, 1),
              transform 1.15s cubic-bezier(.22, 1, .36, 1),
              filter    1.15s cubic-bezier(.22, 1, .36, 1);
}
/* transform is repeated here on purpose: `.hero [data-reveal]` above and
   `[data-reveal].is-in` weigh the same, so source order alone decided it and
   the hero's 36px rise never came back to zero — the text rested 36px below
   where the frame puts it, which is exactly what the cap trim exists to get
   right. */
.hero [data-reveal].is-in { transform: none; filter: blur(0); }

/* "no load animation" on the bottom-right switch: the text skips its rise
   too — heromesh pins the photo to its settled state the same way */
:root[data-loadstyle="0"] .hero [data-reveal] {
  opacity: 1;
  transform: none;
  filter: none;
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  .hero [data-reveal] { filter: none; }
}

/* --------------------------------------------------------- text-box trim --
   Figma measures these text nodes cap-to-baseline (`text-box-trim: trim-both`,
   `text-box-edge: cap alphabetic`), which is why a 48px heading is 34px tall
   in the frame. Chrome/Safari implement it; browsers that don't just render a
   few px of extra leading. Every block height on this page derives from it. */
.eyebrow,
.h1, .lede,
.hero__title, .hero__lede,
.why__title, .why__item h3, .why__item p,
.ten__title, .ten__num,
.tile__title, .tile__foot p,
.eco__name, .eco__desc,
.cases__title, .case__q, .case__quote cite, .case__headline, .case__body p,
.split__title,
.btn {
  text-box: trim-both cap alphabetic;
}

/* ======================================================= heading type-in =
   Figma: CW / node 78:147 — the storyboard for the hero heading.

   A caret appears at the start of the line; a solid bar grows out of it to
   the line's full width; then the bar sweeps off to the right and the text is
   uncovered behind its trailing edge. One bar per line, the second lagging
   the first. The text is not merely faded in — it does not exist ahead of the
   bar, which is why the bar has to be the thing that carries the reveal.

   Each line has to be its own block for the bar to know how wide it is, so
   the cap-to-baseline trim that gives the heading its measured height moves
   onto the lines: every line is trimmed to its cap box and the leading that
   the trim removes is added back between them. The heading measures exactly
   what it did as one <br>-separated block — 197.04px at 1440 on the home
   page — and the ratios below are that font's, measured, not assumed. */
.tl {
  --tl-cap: .70;         /* Rig Sans cap height: 84 / 120, measured */
  position: relative;
  display: block;
  width: max-content;
  max-width: 100%;
  white-space: pre-wrap;  /* the breaks are already decided — see titles.js */
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}
/* The leading the trim took out, put back between the lines. --tl-lh is the
   heading's own line-height ratio; titles.js sets it per heading, because it
   differs from block to block and getting it wrong changes the height. */
.tl + .tl { margin-top: calc(1em * (var(--tl-lh, .942) - var(--tl-cap))); }

.tl__t {
  display: block;
  /* The clip only ever moves horizontally, so it is let out top and bottom:
     the line's box is trimmed to cap-and-baseline, and a clip flush with that
     shaves the overshoot of round letters and cuts descenders off outright. */
  clip-path: inset(-.3em 0 -.3em 0);         /* resting: fully uncovered */
}
.tl::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  /* the frame's bar stands a little proud of the caps, top and bottom */
  top: -.08em;
  height: calc(var(--tl-cap) * 1em + .16em);
  background: currentColor;
  pointer-events: none;
  clip-path: inset(0 0 0 100%);              /* resting: swept off the end */
}
.tl:nth-child(2) { --tl-delay: .34s; }

/* ---- when each heading plays ----------------------------------------
   The two hero headings are on screen at load, so they run from CSS with a
   delay — no script, no frame where they could be caught undressed. Every
   other heading waits for its own scroll: titles.js parks it in .tl-wait and
   swaps that for .tl-go when it comes into view. The resting state, with
   neither class, is the finished heading — so no script or no animation
   support leaves the page simply readable. */
.hero__title .tl__t,
.cpu-hero__title .tl__t,
.tl-go .tl__t { animation: tl-text var(--tl-dur, .95s) var(--tl-delay, .2s) both; }

.hero__title .tl::after,
.cpu-hero__title .tl::after,
.tl-go .tl::after { animation: tl-bar var(--tl-dur, .95s) var(--tl-delay, .2s) both; }

.tl-wait .tl__t { clip-path: inset(-.3em 100% -.3em 0); }
.tl-wait .tl::after { clip-path: inset(0 100% 0 0); }
/* the heroes are never parked, so this only ever guards a heading that some
   later change puts on the letter path */
.tl-wait .tl__c { opacity: 0; }

/* One stroke, start to finish. The line begins empty; the leading edge runs
   the width of the line, and without pausing at the end the trailing edge
   follows it across, the text landing behind that edge exactly.

   Ease-in-out over the whole move, which means the two halves carry one curve
   between them: ease-in up to the turn, ease-out away from it. Easing at both
   ends of each half is what made it read as two moves — the bar settled in
   the middle before setting off again.

   The curves are deep (.78 in, .22 out) so the stroke leaves slowly and
   arrives slowly, carrying its speed through the middle. */
@keyframes tl-bar {
  0%   { clip-path: inset(0 100% 0 0); animation-timing-function: cubic-bezier(.78, 0, 1, 1); }
  46%  { clip-path: inset(0 0 0 0);    animation-timing-function: cubic-bezier(0, 0, .22, 1); }
  100% { clip-path: inset(0 0 0 100%); }
}
@keyframes tl-text {
  0%   { clip-path: inset(-.3em 100% -.3em 0); }
  46%  { clip-path: inset(-.3em 100% -.3em 0); animation-timing-function: cubic-bezier(0, 0, .22, 1); }
  100% { clip-path: inset(-.3em 0 -.3em 0); }
}

/* ---- style 2: the letters resolve, in no order ----------------------- */
/* Each letter fades up from nothing out of a heavy blur, and they are dealt
   random start times, so the heading precipitates rather than being written.
   titles.js splits the text; the bar and its clip stand down.

   The hero headings only. One element per letter across all 39 headings on
   the two pages was ~570 spans of blurred text and the page paid for it; the
   section headings keep the bar, which costs one pseudo-element each. */
:root[data-titles="2"] .hero__title .tl::after,
:root[data-titles="2"] .cpu-hero__title .tl::after { animation: none; }
:root[data-titles="2"] .hero__title .tl__t,
:root[data-titles="2"] .cpu-hero__title .tl__t { animation: none; clip-path: none; }

/* ---- "no titles animation" ------------------------------------------- */
/* The resting state is the finished heading, so switching everything off is
   just that: text uncovered, bar parked past the end, letters at full. */
:root[data-titles="0"] .tl__t,
:root[data-titles="0"] .tl::after,
:root[data-titles="0"] .tl__c { animation: none; }

.tl__c { opacity: 1; }
.hero__title .tl__c,
.cpu-hero__title .tl__c,
.tl-go .tl__c {
  animation: tl-char var(--tl-char-dur, .9s) var(--d, 0s) cubic-bezier(.22, 1, .36, 1) both;
}
@keyframes tl-char {
  from { opacity: 0; filter: blur(.4em); }   /* ≈50px at the frame's 120px */
  to   { opacity: 1; filter: blur(0); }
}

/* replaying the pick from the switch: drop the animations for one frame */
:root.tl-reset .tl__t,
:root.tl-reset .tl::after,
:root.tl-reset .tl__c { animation: none !important; }

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

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

/* ============================================================== primitives = */

/* eyebrow — diamond + 12px condensed mono, uppercase */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-weight: 600;
  font-size: var(--fs-label);
  line-height: 1;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--ink);
}
.eyebrow img { flex: none; width: 12px; height: 12px; }
.eyebrow--light { color: var(--white); }

/* headings shared across sections */
.h1 {
  font-weight: 600;
  font-size: var(--fs-h1);
  line-height: 1.042;      /* 50 / 48 */
  letter-spacing: -.005em;
}
.lede {
  font-weight: 500;
  font-size: var(--fs-lede);
  line-height: 1.4;        /* 28 / 20 */
  max-width: 583px;
}

/* buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: var(--fs-label);
  line-height: 1.4;
  white-space: nowrap;
  transition: background-color .25s ease, color .25s ease, border-color .25s ease;
}
.btn--solid {
  flex: 1 0 0;
  min-width: 0;
  height: 40px;
  padding: 16px 20px;
  background: var(--ink);
  color: var(--white);
}
.btn--solid:hover { background: var(--blue); }

.btn--ghost {
  flex: 1 0 0;
  min-width: 0;
  height: 40px;
  padding: 16px 20px;
  border: 1px solid var(--ink-40);
  color: var(--ink);
}
.btn--ghost:hover { border-color: var(--ink); background: rgba(3, 6, 22, .04); }

/* inline-block, not flex — text-box trim only applies to a real text box, and
   the trim is what makes this button 32px tall like the Figma node */
.btn--outline {
  display: inline-block;
  padding: 12px 14px;
  /* inset shadow rather than a border: Figma strokes don't grow the box */
  box-shadow: inset 0 0 0 1px var(--ink-30);
  border-radius: 2px;
  text-align: center;
  color: var(--ink);
}
/* the outline darkens on hover; no fill */
.eco__row:hover .btn--outline,
.case:hover .btn--outline { box-shadow: inset 0 0 0 1px var(--ink); }

/* pill (Log In) */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 16px;
  border-radius: 100px;
  background: var(--ink);
  color: var(--white);
  font-weight: 500;
  font-size: var(--fs-nav);
  line-height: 1;
  transition: background-color .25s ease;
}
.pill:hover { background: var(--blue); }

/* 32px circled arrow. The ring is a pseudo-element so it can grow out of its
   own centre on hover while the glyph — and the control's position — hold
   still; the SVG carries the arrow only. */
.arrow {
  position: relative;
  display: block;
  flex: none;
  width: 32px;
  height: 32px;
  --ring: var(--ink-30);
  --ring-scale: var(--arrow-ring);
  /* the ring overhangs its 32px box symmetrically, so push the box right by
     that overhang and the circle's left edge lands on the text's left edge —
     which is nothing at all when the ring rests at scale 1 */
  margin-left: calc(32px * (var(--ring-scale) - 1) / 2);
}
/* the ring rests at what used to be its hover size (32 → ~41px) and grows a
   little further on hover; both are transforms, so the control still occupies
   its 32px box and nothing around it reflows */
.arrow::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--ring);
  border-radius: 50%;
  transform: scale(var(--ring-scale));
  transform-origin: 50% 50%;
  transition: transform .4s cubic-bezier(.22, 1, .36, 1),
              border-color .4s ease;
}
.arrow:hover::before,
.arrow:focus-visible::before { transform: scale(var(--arrow-ring-hover)); }
.arrow img { position: relative; width: 100%; height: 100%; }
.arrow--light { --ring: rgba(255, 255, 255, .3); }

/* --------------------------------------------- white → navy transition --
   Ecosystem and Case Studies share this backdrop. The zone is navy — the
   colour both sections end on — and the effect layer paints white over it,
   from the top of Ecosystem to a screen past the seam, turning it over as the
   seam crosses the viewport. Both sections are transparent and stack above it,
   so their own backgrounds never draw an edge between them, and the effect is
   behind their content rather than covering it. Out of flow: no page height. */
.tzone { position: relative; background: var(--navy); }
/* The layer bleeds past the top of the section instead of meeting the white
   band above it edge to edge. Flush, the two whites abutted over the navy
   parent at a fractional y that the inertial scroll changes every frame, and
   the sub-pixel seam between them flickered navy — the canvas rasterises on
   its own compositing layer, so the two edges never round the same way.
   transition-switch.js reads this back to size the layer. */
.tzone__fx {
  position: absolute;
  left: 0;
  right: 0;
  top: -2px;
  z-index: 0;
  pointer-events: none;
}

.curtain {
  position: absolute;
  inset: 0;
  overflow: hidden;
  --curtain-mass: #ffffff;
}
.curtain__lift { position: absolute; inset: 0; will-change: transform; }
/* if the script never runs, this is a plain white sheet — the sections read
   exactly as they did before the transition existed */
.curtain__flat { position: absolute; inset: 0; background: var(--curtain-mass); }
.curtain.is-live .curtain__flat { display: none; }
.curtain__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: none; }
.curtain.is-live .curtain__canvas { display: block; }

/* style 2 — the rhombus wave, same slot, same white → navy */
.rhombus {
  position: absolute;
  inset: 0;
  overflow: hidden;
  --rhombus-light: #ffffff;
  --rhombus-dark: #060d2d;
}
.rhombus canvas { display: block; width: 100%; height: 100%; }

/* only one transition is live at a time */
:root[data-transition="1"] .rhombus { display: none; }
:root[data-transition="2"] .curtain { display: none; }

/* ------------------------------------------------ prototype-only control -- */
/* the prototype's dev switches, stacked bottom-right */
.switches {
  position: fixed;
  z-index: 60;
  right: 16px;
  bottom: 16px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.tswitch {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: 100px;
  background: rgba(255, 255, 255, .9);
  box-shadow: 0 2px 14px rgba(3, 6, 22, .18), inset 0 0 0 1px var(--ink-20);
  backdrop-filter: blur(8px);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .02em;
}
.tswitch button {
  padding: 8px 14px;
  border-radius: 100px;
  color: var(--ink);
  opacity: .55;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .2s ease, opacity .2s ease;
}
/* the display above beats the UA's [hidden], so say it here */
.tswitch[hidden] { display: none; }
.tswitch button:hover { opacity: .85; }
.tswitch button[aria-pressed="true"] { background: var(--ink); color: var(--white); opacity: 1; }

@media (max-width: 640px) {
  .switches { right: 10px; bottom: 10px; gap: 6px; }
  .tswitch { font-size: 10px; }
  .tswitch button { padding: 7px 10px; }
}

/* the 120px spacer bands that separate the Figma sections */
.band { height: var(--band); }
.band--white { background: var(--white); }
.band--navy  { background: var(--navy); }

/* ==================================================================== nav = */
.nav {
  position: fixed;
  z-index: 50;
  top: 0;
  left: 0;
  right: 0;
  padding: 24px;
  transition: transform .4s cubic-bezier(.22, 1, .36, 1);
}
.nav.is-hidden { transform: translateY(calc(-100% - 8px)); }

.nav__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--white);
  border-radius: 2px;
  overflow: clip;
}

.nav__left {
  display: flex;
  flex: 1 0 0;
  min-width: 0;
  align-items: center;
  gap: 24px;
  padding: 12px 16px 12px 8px;
}
.nav__right {
  display: flex;
  flex: 1 0 0;
  min-width: 0;
  height: 60px;
  align-items: center;
  justify-content: flex-end;
  padding: 20px 8px;
}

/* nothing in the bar shrinks — the search field is sized to the room that is
   actually free (navmenu.js), so flexbox never has to guess */
.nav__logo, .nav__links, .nav__search, .nav__cta { flex: none; }

.nav__logo { display: flex; align-items: center; padding: 0 12px; }
.nav__logo-box { position: relative; display: block; width: 150px; height: 20px; }
.nav__logo-box img { position: absolute; }
/* insets straight off the Figma node (31:396) */
.nav__logo-a { inset: .47% 76.93% 2.17% 0;  width: auto; height: auto; }
.nav__logo-b { inset: 0 86.97% 42.37% 9.04%; }
.nav__logo-c { inset: 16.29% 0 0 25.98%; }
.nav__logo-box img { width: auto; height: auto; }
.nav__logo-a, .nav__logo-b, .nav__logo-c { width: auto; height: auto; }

.nav__links { display: flex; align-items: center; gap: 4px; }
.nav__links a {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  padding: 0 12px;
  border-radius: 6px;
  font-weight: 500;
  font-size: var(--fs-nav);
  line-height: 1;
  white-space: nowrap;
  transition: background-color .2s ease;
}
.nav__links a:hover { background: rgba(3, 6, 22, .06); }

.nav__search { display: flex; align-items: center; padding: 0 12px; }
.nav__search img { width: 16px; height: 16px; }

.nav__cta { padding: 0 12px; }

.nav__burger { display: none; width: 36px; height: 36px; margin-left: 4px; }
.nav__burger span {
  display: block;
  width: 18px;
  height: 1.5px;
  margin: 4px auto;
  background: var(--ink);
  transition: transform .3s ease, opacity .3s ease;
}
.nav__burger[aria-expanded="true"] span:first-child { transform: translateY(2.75px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:last-child  { transform: translateY(-2.75px) rotate(-45deg); }

.nav__panel {
  display: flex;
  flex-direction: column;
  margin-top: 4px;
  padding: 8px;
  background: var(--white);
  border-radius: 2px;
}
.nav__panel a {
  padding: 12px;
  font-weight: 500;
  font-size: var(--fs-nav);
}
.nav__panel[hidden] { display: none; }

/* ============================================================= nav menus = */
/* Figma: CW / node 54:1330 — five dropdowns plus the search state.
   All five are the same 254-wide white card, so there is one card in the DOM
   and it slides between the triggers rather than closing and reopening. The
   panels live inside it and cross-fade. */

/* the sliding pill behind the nav links — one per list, driven by navmenu.js */
.nav__links { position: relative; }
.nav__pill {
  position: absolute;
  top: 0;
  left: 0;
  height: 36px;
  border-radius: 6px;
  background: rgba(3, 6, 22, .06);
  opacity: 0;
  pointer-events: none;
  transform: translate3d(0, 0, 0);
  transition: transform .38s cubic-bezier(.22, 1, .36, 1),
              width     .38s cubic-bezier(.22, 1, .36, 1),
              opacity   .22s ease;
}
.nav__links.has-pill a:hover { background: none; }   /* the pill does this now */

/* --- the search field ------------------------------------------------- */
/* collapsed it is the 40px icon button the page always had; open it is the
   446px field from the frame. Width and padding animate; nothing jumps. */
.nav__search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 40px;
  height: 36px;
  padding: 0 12px;
  border-radius: 4px;
  background: rgba(3, 6, 22, 0);
  transition: width      .48s cubic-bezier(.22, 1, .36, 1),
              padding    .48s cubic-bezier(.22, 1, .36, 1),
              background-color .3s ease;
}
.nav__search-btn { display: flex; align-items: center; flex: none; }
.nav__search img { width: 16px; height: 16px; }
.nav__search-input {
  flex: 1;
  min-width: 0;
  width: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-weight: 500;
  font-size: var(--fs-nav);
  line-height: 1;
  color: var(--ink);
  opacity: 0;
  transition: opacity .22s ease;
}
.nav__search-input::placeholder { color: var(--ink); opacity: .2; }
.nav__search-input::-webkit-search-cancel-button { display: none; }
/* the field carries the focus ring, not the bare input inside it */
.nav__search-input:focus-visible { outline: none; }
.nav__search:focus-within { box-shadow: inset 0 0 0 1px var(--ink-30); }

/* 446 at 1440, as in the frame; navmenu.js measures what is actually free so
   the field never squeezes Careers / Contact Us / Log In into two lines */
.nav.is-search .nav__search {
  width: var(--search-w, 446px);
  padding: 0 16px;
  background: rgba(3, 6, 22, .05);
}
.nav.is-search .nav__search-input { opacity: 1; transition-delay: .12s; }
/* with the field open the left group is content-sized, as in the frame */
.nav.is-search .nav__left { flex: 0 0 auto; padding-right: 8px; }

/* --- the card --------------------------------------------------------- */
.navmenu {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.navmenu__box {
  position: absolute;
  top: 92px;                 /* 24 nav padding + 60 bar + 8 gap, off the frame */
  left: 0;
  width: 254px;
  height: 0;
  overflow: hidden;
  background: var(--white);
  border-radius: 2px;
  /* The frame has no shadow — on its grey artboard it doesn't need one. Over
     this page's white sections a shadowless white card is invisible, so it
     gets the lightest one that separates it. */
  box-shadow: 0 16px 40px rgba(3, 6, 22, .10), 0 2px 6px rgba(3, 6, 22, .06);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate3d(0, -8px, 0);
  transition: transform .42s cubic-bezier(.22, 1, .36, 1),
              width     .42s cubic-bezier(.22, 1, .36, 1),
              height    .42s cubic-bezier(.22, 1, .36, 1),
              opacity   .26s ease,
              visibility 0s linear .26s;
}
.navmenu.is-open .navmenu__box {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0s, 0s, 0s, 0s, 0s;
}

.navmenu__panel {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  gap: 32px;
  width: 254px;
  padding: 24px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
}
.navmenu__panel.is-active { opacity: 1; pointer-events: auto; }
.navmenu__panel--search { width: 446px; }

.navmenu__group { display: flex; flex-direction: column; gap: 11px; }

.navmenu__eyebrow {
  font-weight: 700;
  font-size: var(--fs-label);
  line-height: 1.25;               /* 15 / 12, the frame's row height */
  text-transform: uppercase;
  color: var(--ink-30);
}
/* zero height in layout, one pixel on screen — the way Figma draws it */
.navmenu__rule {
  height: 1px;
  margin-block: -.5px;
  background: rgba(3, 6, 22, .05);
}

/* 25px leading less 4px of margin either side puts each row on the frame's
   17px (42px when it wraps), and the flex gap then rides on top of the shrunk
   margin box — so 8px here is the frame's 25px row pitch, not 8px of air. */
.navmenu__links { display: flex; flex-direction: column; gap: 8px; }
.navmenu__links a {
  margin-block: -4px;
  font-weight: 500;
  font-size: var(--fs-nav);
  line-height: 25px;
  letter-spacing: -.01em;
  color: var(--ink);
  opacity: .8;
  /* underline as a decoration rather than a border: the two-line entries wrap,
     and only this underlines each line rather than the box */
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: transparent;
  transition: opacity .18s ease, text-decoration-color .18s ease;
}
.navmenu__links a:hover { opacity: 1; text-decoration-color: currentColor; }

/* Industries and the search results are flat lists whose wrapped lines sit
   tight, so they keep normal leading */
.navmenu__panel--flat .navmenu__links { gap: 8px; }
.navmenu__panel--search .navmenu__links { gap: 16px; }
.navmenu__panel--flat .navmenu__links a,
.navmenu__panel--search .navmenu__links a { margin-block: 0; line-height: normal; }

/* --- the cascade ------------------------------------------------------ */
.navmenu__panel > * {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition: opacity .34s cubic-bezier(.22, 1, .36, 1),
              transform .34s cubic-bezier(.22, 1, .36, 1);
}
.navmenu.is-open .navmenu__panel.is-active > * { opacity: 1; transform: none; }
.navmenu.is-open .navmenu__panel.is-active > *:nth-child(1) { transition-delay: .05s; }
.navmenu.is-open .navmenu__panel.is-active > *:nth-child(2) { transition-delay: .09s; }
.navmenu.is-open .navmenu__panel.is-active > *:nth-child(3) { transition-delay: .13s; }
.navmenu.is-open .navmenu__panel.is-active > *:nth-child(4) { transition-delay: .17s; }
.navmenu.is-open .navmenu__panel.is-active > *:nth-child(5) { transition-delay: .21s; }

/* --- the mobile accordion --------------------------------------------- */
.nav__panel .navsub {
  overflow: hidden;
  height: 0;
  transition: height .38s cubic-bezier(.22, 1, .36, 1);
}
.nav__panel .navsub__inner { padding: 0 12px 12px 24px; }
.nav__panel .navsub__eyebrow {
  padding: 10px 0 6px;
  font-weight: 700;
  font-size: var(--fs-label);
  line-height: 1.25;
  text-transform: uppercase;
  color: var(--ink-30);
}
.nav__panel .navsub a { display: block; padding: 7px 0; opacity: .8; }
.nav__panel [data-acc] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 12px;
  font-weight: 500;
  font-size: var(--fs-nav);
  text-align: left;
}
.nav__panel [data-acc]::after {
  content: "";
  width: 7px;
  height: 7px;
  margin-right: 4px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  opacity: .4;
  transition: transform .3s cubic-bezier(.22, 1, .36, 1);
}
.nav__panel [data-acc][aria-expanded="true"]::after { transform: translateY(1px) rotate(-135deg); }

@media (prefers-reduced-motion: reduce) {
  .nav__pill,
  .nav__search,
  .nav__search-input,
  .navmenu__box,
  .navmenu__panel,
  .navmenu__panel > *,
  .nav__panel .navsub { transition: none; }
  .navmenu.is-open .navmenu__panel.is-active > * { transition-delay: 0s; }
}

/* =================================================================== hero = */
/* the hero fills one screen; 860 — the frame's height — is its floor */
.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  min-height: 620px;
  overflow: clip;
  background: var(--ink);
  isolation: isolate;
}
.hero__bg { position: absolute; inset: 0; z-index: -1; }
.hero__grid {
  position: absolute;
  inset: 0;
  opacity: .1;
  background-image: url("assets/grid.png");
  background-size: 96px 96.6px;
  background-position: top left;
}
.hero__photo { position: absolute; inset: 0; overflow: hidden; }
/* the mesh canvas replaces the photo once WebGL is up (heromesh.js) */
.hero__photo canvas {
  position: absolute;
  inset: 0;
  display: none;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.hero__photo.is-mesh canvas { display: block; }
.hero__photo.is-mesh img { visibility: hidden; }
/* The photo is placed mirrored in Figma — hence scaleX(-1). Width and offset
   are both driven by the hero's width so the crop stays identical at every
   viewport; a % translateY resolves against the image's own height. */
.hero__photo img {
  position: absolute;
  left: -.76%;
  top: 0;
  width: 111.13%;
  height: auto;
  max-width: none;
  transform: translateY(-10.94%) scaleX(-1);
}
/* the nav strip carries a second pass of the grid on top of the photo */
.hero__topgrid {
  position: absolute;
  inset: 0 0 auto 0;
  height: var(--nav-h);
  opacity: .1;
  background-image: url("assets/grid.png");
  background-size: 96px 96.6px;
  background-position: top left;
  pointer-events: none;
}
.hero__inner {
  position: absolute;
  left: 44px;
  right: 36px;
  top: calc(50% - 59px);
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 48px;
}
.hero__title {
  font-weight: 600;
  font-size: var(--fs-hero);
  line-height: .942;        /* 113 / 120 */
  letter-spacing: -.03em;
  color: var(--ink);
}
.hero__lede {
  max-width: 583px;
  font-weight: 500;
  font-size: var(--fs-lede);
  line-height: 1.4;
  color: var(--ink);
}
.hero__actions { display: flex; align-items: center; gap: 16px; width: 340px; max-width: 100%; }

/* ============================================================ why coreweave = */
.why {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 760px;
  background: var(--pale);
}
.why__left {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  padding: var(--gutter);
}
.why__title {
  max-width: 587px;
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.191;      /* 50 / 42 */
  letter-spacing: -.005em;
}
.why__right {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* vertical padding trimmed from 80 to 63 so the 18px copy still lands the
     section on the frame's 760; the horizontal inset is unchanged */
  padding: var(--why-pad) var(--pad-80);
  background: var(--blue);
}
.why__list { display: flex; flex-direction: column; gap: 64px; width: 100%; }
/* full width of the column — flush with the rules above and below */
.why__item { display: flex; flex-direction: column; gap: 32px; width: 100%; }
.why__item h3 {
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1;
  color: var(--white);
}
.why__item p {
  font-weight: 500;
  font-size: var(--fs-body-s);
  line-height: 1.43;
  color: var(--white);
}
.why__list hr { width: 100%; height: 0; margin: 0; border: 0; border-top: 1px solid var(--white); }

/* ================================================================== ten =  */
.ten {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 760px;
  background: var(--pale);
}
.ten__left { position: relative; overflow: hidden; background: var(--blue); min-height: 380px; }
.ten__num {
  position: absolute;
  display: block;
  font-size: var(--fs-ten);
  line-height: .365;       /* 113 / 310 */
  letter-spacing: -.03em;
  color: var(--white);
  white-space: nowrap;
}
.ten__num--solid { font-weight: 500; left: 9.72%; top: 11.18%; }
.ten__num--ghost { font-weight: 100; left: 2.92%; top: 59.87%; width: 88.9%; text-align: right; opacity: .2; }
.ten__line {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 80.53%;             /* 579.828 / 720 */
  height: 5px;
  max-width: none;
  transform: translate(-50%, -50%) rotate(141.77deg);
  transform-origin: center;
}

.ten__right {
  display: flex;
  flex-direction: column;
  padding: var(--gutter) var(--gutter) 34px;
}
.ten__head { display: flex; flex-direction: column; align-items: flex-start; gap: 40px; }
.ten__title {
  max-width: 389px;
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.191;
  letter-spacing: -.005em;
}
.ten__wall { width: 100%; max-width: 643px; height: auto; margin-top: auto; padding-top: 40px; }

/* ============================================================ 3-up call-out = */
.cta3 {
  display: flex;
  flex-direction: column;
  gap: var(--band);
  padding-top: var(--gutter);
  background: var(--white);
}
.cta3__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  padding: 0 var(--gutter);
}
.cta3__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }

.tile {
  display: flex;
  min-width: 0;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--pad-48);
  min-height: 470px;
  padding: var(--pad-48);
  background: var(--blue);
}
.cta3__row .tile + .tile { border-left: 1px solid var(--white); }
.tile__title {
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.2;        /* 48 / 40 */
  color: var(--white);
}
.tile__foot { display: flex; flex-direction: column; gap: 24px; }
.tile__foot p {
  font-weight: 500;
  font-size: var(--fs-body-s);
  line-height: 1.43;
  color: var(--white);
}

/* ============================================================== ecosystem = */
/* transparent — the shared transition backdrop shows through (see .tzone) */
.eco {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--band);
  padding-top: var(--gutter);
  background: transparent;
}
.eco__head, .eco__rows { position: relative; z-index: 1; }
.eco__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  padding: 0 var(--gutter);
}
.eco__title { max-width: 647px; }

.eco__rows { display: flex; flex-direction: column; }
.eco__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 72px var(--gutter);
  box-shadow: inset 0 1px 0 var(--rule);
  transition: background-color .3s ease;
}
.eco__rows .eco__row:last-child { box-shadow: inset 0 1px 0 var(--rule), inset 0 -1px 0 var(--rule); }
.eco__row:hover { background: var(--pale); }
.eco__name {
  flex: none;
  width: 220px;
  font-family: var(--mono);
  font-weight: 500;
  font-size: var(--fs-mono-xl);
  line-height: 1.191;
}
.eco__desc {
  flex: 1 1 880px;
  max-width: 880px;
  font-family: var(--mono);
  font-weight: 600;
  font-size: var(--fs-mono-m);
  line-height: 1.25;
}
.eco__row .btn--outline { flex: none; width: 102px; }

/* =========================================================== case studies = */
.cases {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 80px;
  padding: var(--gutter);
  background: transparent;   /* the .tzone backdrop supplies the navy */
  overflow: clip;
}
.cases__head { display: flex; flex-direction: column; align-items: flex-start; gap: 40px; }
.cases__title { color: var(--white); }

.carousel { position: relative; display: flex; flex-direction: column; gap: 32px; }
.carousel__viewport { overflow: visible; }
.carousel__track {
  display: flex;
  gap: 80px;
  will-change: transform;
  transition: transform .7s cubic-bezier(.22, 1, .36, 1);
}
.carousel.is-dragging .carousel__track { transition: none; }

.case {
  flex: none;
  width: var(--case-w, 1120px);
  display: flex;
  flex-direction: column;
  gap: 60px;
  padding: var(--pad-80) 0;
  background: var(--white);
  box-shadow: inset 0 0 0 1px var(--ink-50);
  overflow: clip;
  transition: opacity .7s cubic-bezier(.22, 1, .36, 1);
}
.case[aria-hidden="true"] { opacity: .3; }

.case__top { display: flex; align-items: flex-start; }
.case__media { flex: none; width: 46.43%; }        /* 520 / 1120 */
.case__media img { width: 100%; height: 614px; object-fit: cover; }

.case__quote {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(40px, 10.15vw, 146px);
  padding: 0 var(--pad-80);
}
.case__mark { width: 49px; height: 35px; margin: 0 auto; }
.case__quote blockquote { display: flex; flex-direction: column; gap: 40px; margin: 0; }
.case__q {
  font-weight: 600;
  font-size: var(--fs-quote);
  line-height: 1.077;      /* 56 / 52 */
  letter-spacing: -.03em;
}
.case__quote cite {
  font-style: normal;
  font-weight: 500;
  font-size: var(--fs-body-m);
  line-height: 1.15;
}

.case__bottom { display: flex; align-items: flex-start; gap: 80px; padding-right: var(--pad-80); }
.case__headline {
  flex: none;
  width: 46.43%;
  padding-left: 67px;
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.2;
  letter-spacing: -.003em;
}
.case__body { display: flex; flex-direction: column; align-items: flex-start; gap: 32px; max-width: 440px; }
.case__body p {
  font-weight: 500;
  font-size: var(--fs-body-m);
  line-height: 1.445;      /* 26 / 18 */
  letter-spacing: -.01em;
}

.carousel__next {
  position: absolute;
  top: 486px;
  left: min(1163px, calc(100% - 60px));
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 100px;
  background: var(--white);
  border: 1px solid var(--rule-dot);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .25);
  transition: transform .3s ease;
}
.carousel__next:hover { transform: scale(1.06); }
.carousel__next img { width: 12px; height: 22px; }

.carousel__dots { display: flex; gap: 8px; }
.carousel__dots button {
  width: 16px;
  height: 16px;
  border-radius: 30px;
  border: 1px solid var(--rule-dot);
  transition: background-color .3s ease, border-color .3s ease;
}
.carousel__dots button[aria-selected="true"] { background: var(--white); border-color: var(--white); }

/* ================================================================ 50 / 50 = */
/* a hard 50/50 split at every width — the media never eats into the copy */
.split { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; background: var(--blue); }
.split__media { min-height: 760px; background: var(--black); }
.split__media img { width: 100%; height: 100%; min-height: 760px; object-fit: cover; }

/* the second module's panel is a transparent WebGL canvas over its own photo,
   which doubles as the still fallback if the module can't run (split3d.js) */
.split__media--3d {
  position: relative;
  background: url("assets/split-3d-bg.jpg") center / cover no-repeat;
}
/* absolute, so the canvas fills the cell instead of sizing it — otherwise its
   intrinsic ratio feeds back through the renderer and the panel creeps taller */
.split__media--3d canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.split__text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  padding: var(--gutter);
}
.split__title {
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.191;
  letter-spacing: -.005em;
  color: var(--white);
}

/* ============================================================== final cta = */
.final { background: var(--white); padding-top: var(--gutter); }
.final__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  padding: 0 var(--gutter);
  margin-bottom: clamp(64px, 10.56vw, 152px);
}
/* exact halves — the tall card and the stacked pair each take 50% */
.final__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; }
/* unlike the 3-up row, these cards stack from the top with a 48px gap */
.final__grid .tile { justify-content: flex-start; }
.final__grid > .tile--tall { min-height: 692px; border-right: 1px solid var(--white); }
.final__stack { display: flex; min-width: 0; flex-direction: column; }
.final__stack .tile { min-height: 346px; }
.final__stack .tile + .tile { border-top: 1px solid var(--white); }

/* ================================================================= footer = */
.footer {
  padding: 70px 24px 31px;
  background: var(--black);
  color: var(--white);
}
/* exact halves — the link column starts at 50% at every width, as in the frame */
.footer__top { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
.footer__logo { width: 109px; margin-top: 16px; }
.footer__logo img { width: 100%; height: auto; }

.footer__nav { display: flex; flex-direction: column; }
.footer__nav a {
  display: flex;
  align-items: center;
  padding: 16px 0;
  box-shadow: inset 0 -1px 0 var(--rule-light);
  font-weight: 700;
  font-size: var(--fs-nav-lg);
  line-height: 1.1875;   /* 38 / 32 → 70px rows */
  letter-spacing: -.02em;
  transition: color .25s ease, padding-left .25s ease;
}
.footer__nav a:hover { color: var(--pale); padding-left: 8px; }

.footer__mid {
  display: grid;
  grid-template-columns: 50% 25.72% auto;   /* 696 / 358 / rest of 1392 */
  gap: 0;
  margin-top: 71px;
  font-weight: 400;
  font-size: var(--fs-mono-m);
  line-height: 1.4;
}
.footer__list li a { transition: opacity .25s ease; }
.footer__list li a:hover { opacity: .65; }

.footer__legal {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 68px;
  padding-top: 11px;
  border-top: 1px solid var(--rule-light);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  text-transform: uppercase;
}

/* ========================================================================= */
/*                              responsive                                   */
/* ========================================================================= */

/* the carousel arrow sits inside the card at 1440; keep it on the seam below */
@media (max-width: 1439px) {
  .carousel__next { left: auto; right: 4px; top: 40%; }
}

/* ---- 1180px: nav collapses, ecosystem rows tighten -------------------- */
@media (max-width: 1180px) {
  /* no triggers at this width — the menu lives in the burger panel instead */
  .nav__links, .nav__search, .navmenu { display: none; }
  .nav__burger { display: block; }
  .nav__left  { padding: 12px 8px; }
  .nav__right { height: auto; padding: 12px 8px; }

  .eco__row { flex-wrap: wrap; padding: 48px var(--gutter); }
  .eco__name { width: 100%; }
  .eco__desc { flex: 1 1 auto; }

  .case__quote { gap: 48px; }
  .case__headline { padding-left: var(--pad-80); }
}

/* ---- 1024px: two-column sections stack ------------------------------- */
@media (max-width: 1024px) {
  /* The 1440 crop puts the pale part of the photo behind the headline. A
     portrait viewport can't hold that framing, so below 1024 the photo covers
     and a scrim in the same pale keeps the type readable over it. */
  .hero { height: auto; min-height: 100svh; }
  .hero__photo img {
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 78% 8%;
    transform: scaleX(-1);
  }
  .hero__bg::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
      rgba(216, 255, 255, .95) 0%,
      rgba(216, 255, 255, .88) 42%,
      rgba(216, 255, 255, .40) 72%,
      rgba(216, 255, 255, 0) 100%);
  }
  .hero__inner {
    position: static;
    transform: none;
    padding: 168px var(--gutter) 120px;
  }

  .why, .ten { grid-template-columns: 1fr; min-height: 0; }
  .why__right { padding: var(--pad-80) var(--gutter); }
  .ten__left  { min-height: 420px; }
  .ten__right { padding-bottom: var(--gutter); }
  .ten__wall  { margin-top: 40px; }

  .split { grid-template-columns: 1fr; }
  .split--b .split__media { grid-row: 1; }
  .split__media { min-height: 0; }
  .split__media img { min-height: 0; height: auto; }
  /* the canvas has no intrinsic size — give it the sketch's frame ratio */
  .split__media--3d { aspect-ratio: 720 / 760; }
  .split__media--3d canvas { min-height: 0; }

  .case__top { flex-direction: column; }
  .case__media { width: 100%; }
  .case__media img { height: auto; aspect-ratio: 520 / 614; }
  .case__quote { padding: var(--pad-80) var(--pad-80) 0; width: 100%; }
  .case__mark { margin: 0; }
  .case__bottom { flex-direction: column; gap: 32px; padding: 0 var(--pad-80); }
  .case__headline { width: 100%; padding-left: 0; }
  .case__body { max-width: none; }

  .footer__top { grid-template-columns: 1fr; gap: 40px; }
  .footer__mid { grid-template-columns: 1fr 1fr; margin-top: 48px; }
}

/* ---- 840px: 3-up grids stack ----------------------------------------- */
@media (max-width: 840px) {
  .cta3__row { grid-template-columns: 1fr; }
  .cta3__row .tile + .tile { border-left: 0; border-top: 1px solid var(--white); }
  .tile { min-height: 0; }
  .tile__foot { margin-top: 48px; }

  .final__grid { grid-template-columns: 1fr; }
  .final__grid > .tile--tall { min-height: 0; border-right: 0; border-bottom: 1px solid var(--white); }
  .final__stack .tile { min-height: 0; }
}

/* ---- 640px: phone ----------------------------------------------------- */
@media (max-width: 640px) {
  .hero__inner { gap: 32px; padding: 140px var(--gutter) 88px; }
  .hero__actions { width: 100%; }

  .why__left, .ten__right, .cta3__head, .eco__head, .cases__head, .final__head { gap: 28px; }

  .cases { gap: 48px; }
  .carousel__track { gap: 24px; }
  .case { padding: var(--pad-80) 0 40px; }
  .case__quote { padding: 32px 24px 0; gap: 32px; }
  .case__bottom { padding: 0 24px; }
  .carousel__next { width: 44px; height: 44px; top: 32%; }

  .footer { padding: 48px 20px 32px; }
  .footer__mid { grid-template-columns: 1fr; gap: 28px; }
  .footer__legal { flex-direction: column; align-items: flex-start; gap: 8px; margin-top: 40px; }
}
