/* ============================================================
   Bluefin Studio — page styles (built from Figma 1:1)
   ============================================================ */

@font-face {
  font-family: "Saans";
  src: url("fonts/Saans-Regular.woff2") format("woff2"),
       url("fonts/Saans-Regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: "Saans SemiMono";
  src: url("fonts/SaansSemiMono-Regular.woff2") format("woff2"),
       url("fonts/SaansSemiMono-Regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

:root {
  /* Container system — Apple-style tiers: content lives in a centered
     column capped at --ct-max; XL screens get margin, never bigger type.
     --side resolves to the real gutter at any viewport. */
  --ct-max:    1240px;
  --ct-gutter: 64px;
  --side:      max(var(--ct-gutter), calc((100vw - var(--ct-max)) / 2));

  --blue:          #2200FF;
  --blue-deep:     #005BFE;
  --blue-mid:      #0085FE;
  --blue-aqua:     #00AAFE;
  --blue-violet:   #573DFF;
  --blue-haze:     #C3CEFF;
  --blue-cyan:     #00D0FF;
  --blue-bright:   #1B10DC;
  --blue-indigo:   #13008F;
  --blue-ink:      #0B0054;

  /* Spotlight palette — Figma node 378:1574/1549/1624/1599/1524/1498.
     Gradient runs from #006cdb (surface) to #001759 (sea floor), matching
     the "diving deeper" metaphor as you scroll through the project list. */
  --spot-tnt:    #006cdb;  /* TNT Simmonds       (Fin)             */
  --spot-knine:  #005bc1;  /* K-Nine Solutions   (Bubble drift)    */
  --spot-astro:  #004aa7;  /* Astro              (Jellyfish)       */
  --spot-pal:    #00398d;  /* PAL Puppy          (Kelp + bubbles)  */
  --spot-donna:  #002873;  /* Donna Berg         (School of fish)  */
  --spot-stark:  #001759;  /* Stark Galleries    (Sea floor)       */
  --paper:         #FAFDFF;
  --off-white:     #FCFCFF;
  --pill:          rgba(184,184,184,0.20);
  --black:         #000;
  --white:         #FFF;
  --display: "Saans", ui-sans-serif, system-ui, sans-serif;
  --mono:    "Saans SemiMono", ui-monospace, "SF Mono", Menlo, monospace;
  --ease:    cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Global text selection — blue highlight matches hover state colour */
::selection         { background: var(--blue); color: var(--white); }
::-moz-selection    { background: var(--blue); color: var(--white); }

/* Visible keyboard-focus ring — only shows for keyboard nav, not mouse clicks.
   Links/buttons/interactive items had no focus affordance before. */
a:focus-visible, button:focus-visible,
.project-row__head:focus-visible, .m-project-row__head:focus-visible,
.item:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--blue-deep);
  outline-offset: 3px;
  border-radius: 2px;
}

*, *::before, *::after { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0;
  background: var(--paper);
  color: var(--black);
  font-family: var(--mono);
  font-weight: 400;          /* Saans Regular only — no bold anywhere */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
body { overflow-x: clip; }

/* Scroll-lock during hero intro video. Removed when the intro video ends
   (or the safety timeout fires). !important beats the inline overflow-x
   that fit() writes on body. */
html.scroll-locked,
html.scroll-locked body {
  overflow: hidden !important;
  /* No touch-action:none — overflow:hidden already locks scroll during the intro
     (and the overlay covers the page). touch-action:none left the *first* post-
     intro swipe "dead" on iOS because the gesture began while it was still set,
     which is what made the page feel frozen until several hard swipes. */
}
img, svg, video { display: block; max-width: 100%; }
/* Chat widget disabled on this branch — its geometry was coupled to the
   retired canvas-scaling engine. Re-anchoring it is tracked follow-up work. */
#chat-root { display: none !important; }
button, input, textarea { font: inherit; color: inherit; }
h1, h2, h3, h4, h5, h6, strong, b { font-weight: 400; }   /* never bold */

.page {
  position: relative;
  width: 100%;
  margin: 0 auto;
  background: var(--paper);
  overflow: clip;
}

/* ----- TOP NAV -----
   Fixed at the top of the viewport so it can fade in/out independent of
   page scroll. Lives outside .page (transform issue). Sizes scale with
   the viewport via clamp() so the same layout reads well from 1440px down
   to a 320px phone — no separate breakpoints needed for the dimensions
   themselves. */
.nav {
  position: fixed;
  top: clamp(16px, 2.5vw, 36px);
  left: var(--side);
  width: calc(100vw - 2 * var(--side));
  transform: none;
  height: clamp(44px, 3.5vw, 50px);
  z-index: 50;
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* Hidden until the hero intro video finishes — see main.js revealUI().
     After that, scroll-direction toggles .is-hidden (scroll down) and
     .is-revealed handles the initial fade. */
  opacity: 0;
  pointer-events: none;
  transition: opacity 600ms ease, transform 380ms cubic-bezier(.16, 1, .3, 1);
}
.nav.is-revealed {
  opacity: 1;
  pointer-events: auto;
}
.nav.is-hidden {
  opacity: 0;
  /* Clear the full height PLUS the top offset so no sliver lingers mid-fade
     (top is at most 36px across the desktop-nav tiers). */
  transform: translateY(calc(-100% - 40px));
  pointer-events: none;
}
.wordmark {
  /* Scales from 95px on a phone up to 126px on desktop. */
  width: clamp(95px, 8.8vw, 126px);
  height: clamp(22px, 2.1vw, 30px);
  display: block;
}
/* The provided wordmark SVG is white (#FCFCFF) — invert it so it reads black on white paper */
.wordmark img {
  width: 100%; height: 100%;
  filter: invert(1);
}
.nav-cluster {
  display: flex; align-items: center;
  height: 100%;
  background: rgba(235, 236, 240, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.60);
  border-radius: 30px;
  padding: 0 clamp(18px, 2vw, 28px);
  gap: clamp(20px, 2.5vw, 36px);
}
.nav-cluster a {
  font-family: var(--mono);
  font-size: clamp(14px, 1.27vw, 18.36px);
  line-height: 1;
  color: var(--black);
  text-decoration: none;
  transition: color 300ms var(--ease);
}
.nav-cluster a:hover { color: var(--blue); }

/* L tier (≥1069px): nav + logo hold their largest size across the whole
   tier instead of scaling with vw between 1069 and 1440. The base clamp()
   rules above still drive the M tier (735–1068) down to phone widths. */
/* Nav + logo hold their largest (L-tier) size across BOTH the desktop
   tiers — M (tablet) and L — instead of scaling with vw. Below 735px the
   mobile nav (.m-nav-header) takes over, so the base clamp() only matters
   there. */
@media (min-width: 735px) {
  .nav         { top: 36px; height: 50px; }
  .wordmark    { width: 126px; height: 30px; }
  .nav-cluster { padding: 0 28px; gap: 36px; }
  .nav-cluster a { font-size: 18.36px; }
}

/* "Work" nav anchor lands the Select Work section below the fixed nav with
   breathing room. Single source of truth for both the desktop JS smooth
   scroll (reads this value) and the mobile native anchor jump. */
#work, #m-work { scroll-margin-top: clamp(90px, 12vh, 140px); }

/* ----- HERO ----- */
/* ----- LOAD-IN INTRO -----
   One-time intro video overlay (lives outside .page). Starts white; the video
   fades in from white, plays, then a white wash fades in and the whole overlay
   dissolves to reveal the site beneath. Sequenced by main.js §9b. */
#loadin {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  pointer-events: none;   /* purely visual — never intercept touches */
}
#loadin video {
  width: 100%;
  height: 100%;
  object-fit: cover;              /* full-bleed */
}
/* A white layer sitting over the video. It starts opaque (white screen), fades
   to 0 to reveal the already-playing video (fade-IN, overlaps the start), then
   fades back to 1 over the video's final moment (fade-OUT, overlaps the end) —
   so the video is still moving through both transitions. */
#loadin::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--paper);
  opacity: 1;
  transition: opacity 600ms ease;  /* fade-in: white clears off the playing video */
  pointer-events: none;
}
#loadin.is-revealed::after { opacity: 0; }
#loadin.is-washing::after  { opacity: 1; transition: opacity 1000ms ease; }  /* fade-out */
#loadin.is-done {                  /* once white, dissolve the overlay into the site */
  opacity: 0;
  transition: opacity 600ms ease;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  #loadin { display: none; }
}

/* Hero art band — decorative pixel-speckle texture between hero and page.
   Figma node 378:1324 (1440x44). The source PNG is 2172x724 and Figma
   renders it scaled to 1440x480 with the band cropping a 44px slice at
   y ≈ -245px (the part where the deep-blue area transitions into speckles
   that fade down into white). Matching that exact crop here. */
.hero-art-band {
  position: relative;
  width: 100%;
  height: calc(100vw * 0.030556);                 /* 44/1440 */
  background-image: url('assets/hero-art-band.png');
  background-size: 100vw calc(100vw / 3);          /* 1440x480 slice, scaled */
  background-position: 0 calc(100vw * -0.179167);  /* -258/1440 */
  background-repeat: no-repeat;
  pointer-events: none;
  z-index: 4;
}

/* Hero reef removed in new Figma design (Frame 1400005071) */
/* Legacy .hero-fin element removed — superseded by #fish in the chat widget. */
/* Hero .ai-input placeholder removed in Phase 4 (BLU-49) — replaced by
   the Blu chat widget mounted outside .page; see #chat-root rules below. */

/* ----- ABOUT / "Let's dive in" ----- */
/* Wrapper for the split headline + paragraph (production spacing). Everything
   below stays hidden (reveal-init) until the first scroll, so only the intro
   shows on landing. flow-root just contains the headline's top margin. */
.hero-intro {
  display: flow-root;
}
/* New Figma headline: "Bluefin {fin} is a digital design studio" at 60px.
   inline-flex keeps the fin between the two text runs with a sensible gap.
   Split into two lines (fin travels with "Bluefin") so the landing sequence
   can fade them in as separate steps. */
.dive-line--1 { display: inline-flex; align-items: center; gap: 18px; }
.dive-headline {
  position: relative;
  margin: 300px var(--side) 0;
  max-width: 1248px;
  font-family: var(--display);
  font-weight: 400;
  font-size: 60px;
  line-height: normal;
  letter-spacing: normal;
  color: var(--black);
  display: inline-flex;
  align-items: center;
  gap: 18px;
}
.dive-headline .dive-fin {
  width: 53px; height: 46px;
  display: inline-block;
}
.dive-headline .dive-fin img { width: 100%; height: 100%; }
/* Body bumped to 40px to match the new design — bigger so it reads as a
   primary intro line, not a supporting caption. */
.dive-paragraph {
  position: relative;
  margin: 40px var(--side) 0;
  max-width: 1248px;
  font-family: var(--display);
  font-size: 40px;
  line-height: normal;
  color: var(--black);
}

/* ----- EYEBROW (mono label + 6px blue underline) ----- */
.eyebrow {
  position: absolute;
  font-family: var(--mono);
  font-size: 24px;
  line-height: 1;
  color: var(--black);
  display: inline-flex;
  flex-direction: column;
  gap: 0;
}
.eyebrow::after {
  content: "";
  display: block;
  height: 52px;
  margin-bottom: 0;
  background: url('assets/blue-line.gif') no-repeat center / 100% 100%;
}
.eyebrow--select-work {
  position: relative;
  left: 0; top: 0;
  width: 143px;
  margin: 300px 0 70px var(--side);
}
.eyebrow--select-work::after { width: 143px; }
.eyebrow--services    { left: 70px; }
.eyebrow--services::after { width: 155px; }

/* ----- PROJECT LIST (accordion) ----- */
.project-list {
  position: relative;
  margin: 0 var(--side) 140px;
  border-bottom: 1px solid var(--black);
}
.project-row {
  border-top: 1px solid var(--black);
  cursor: pointer;
  background: transparent;
  position: relative;
  isolation: isolate;
  transition: border-color 300ms var(--ease);
  z-index: 0;
}
.project-row:not(.is-open):hover {
  z-index: 1;
}
.project-row__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  padding: 70px 0 22px 0;
  min-height: 152px;
  position: relative;
  overflow: hidden;
  transition: padding 500ms var(--ease),
              min-height 500ms var(--ease),
              max-height 500ms var(--ease);
}
.project-row:hover .project-row__head { padding-left: 12px; }
.project-row__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: 60px;
  line-height: 1;
  letter-spacing: normal;
  color: var(--black);
  margin: 0;
  align-self: flex-end;
  transition: color 300ms var(--ease),
              opacity 350ms var(--ease);
}
.project-row:not(.is-open):hover .project-row__title { color: var(--white); }

/* full-bleed hover fill behind the row — extends 1px past the top and bottom
   borders so the color block cleanly covers the black lines on hover */
.project-row::before {
  content: "";
  position: absolute;
  top: -1px; bottom: -2px;
  left: calc(-1 * var(--side)); right: calc(-1 * var(--side));
  background: transparent;
  z-index: -1;
  pointer-events: none;
  transition: background 300ms var(--ease);
}

/* per-project hover fill (matches the expanded spotlight color) — Figma palette */
.project-row:not(.is-open)[data-project="donna"]:hover::before  { background: var(--spot-donna); }
.project-row:not(.is-open)[data-project="tnt"]:hover::before    { background: var(--spot-tnt); }
.project-row:not(.is-open)[data-project="knine"]:hover::before  { background: var(--spot-knine); }
.project-row:not(.is-open)[data-project="stark"]:hover::before  { background: var(--spot-stark); }
.project-row:not(.is-open)[data-project="pal"]:hover::before    { background: var(--spot-pal); }
.project-row:not(.is-open)[data-project="astro"]:hover::before  { background: var(--spot-astro); }
.project-row__plus {
  width: 40px; height: 40px;
  background: transparent;
  border-radius: 50%;
  position: relative;
  flex-shrink: 0;
  margin: 0;
  align-self: flex-end;
  z-index: 4;
  pointer-events: auto;
  transition: transform 600ms var(--ease);
}
.project-row__plus::before,
.project-row__plus::after {
  content: ""; position: absolute;
  background: var(--black);
  border-radius: 1px;
  transition: background 200ms var(--ease);
}
.project-row__plus::before { left: 50%; top: 0; bottom: 0; width: 2px; transform: translateX(-1px); }
.project-row__plus::after  { top: 50%; left: 0; right: 0; height: 2px; transform: translateY(-1px); }
.project-row:hover .project-row__plus { transform: none; }
.project-row:hover .project-row__plus::before,
.project-row:hover .project-row__plus::after { background: var(--white); }

/* ----- SERVICES GRID ----- */
.services-section { position: relative; padding: 160px var(--side) 140px; margin-bottom: 0; }
.services-section .eyebrow { position: relative; left: 0; top: 0; margin-bottom: 64px; }

.services {
  display: flex; flex-direction: row;
  flex-wrap: wrap;
  gap: 50px 75px;
}
.services .item {
  font-family: var(--display);
  font-weight: 400;
  font-size: 60px;
  line-height: 1;
  letter-spacing: normal;
  color: var(--black);
  cursor: pointer;
  position: relative;
  display: inline-block;
  transition: color 450ms var(--ease),
              transform 450ms var(--ease);
}
.services .item::before {
  /* sliding blue fill that wipes from left on hover */
  content: attr(data-label);
  position: absolute; left: 0; top: 0;
  width: 0; overflow: hidden; white-space: nowrap;
  color: var(--blue);
  transition: width 600ms var(--ease);
  pointer-events: none;
}
.services .item:hover::before { width: 100%; }
.services .item:hover { transform: translateY(-2px); }
.services .item--more {
  color: var(--black);
  cursor: default;
  pointer-events: none;
}
.services .item--more::before { content: none; }

/* Cursor-following hover image revealed on service-item hover */
.services { position: relative; }
.services-hover-img {
  position: fixed;
  top: 0; left: 0;
  width: 360px;
  height: 270px;
  object-fit: cover;
  border-radius: 16px;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(-9999px, -9999px, 0) scale(0.94);
  transition: opacity 220ms var(--ease),
              transform 220ms var(--ease);
  z-index: 50;
  box-shadow: 0 30px 60px rgba(0,0,0,0.18);
  will-change: transform, opacity;
}
.services-hover-img.is-visible { opacity: 1; }

/* "hover me!" hint */
.hover-hint {
  position: absolute;
  top: -44px;
  right: -22px;
  font-family: var(--mono);
  font-size: 18px;
  color: var(--blue);
  transform: rotate(-20deg);
  display: inline-block;
  pointer-events: none;
  white-space: nowrap;
}

/* ----- OUR ETHOS ----- */
.ethos-section {
  position: relative;
  padding: 160px var(--side) 300px;
  background: var(--paper);
}
.ethos-section .eyebrow {
  position: relative; left: 0; top: 0;
  margin-bottom: 80px;
}
.eyebrow--ethos::after { width: 118px; }

.ethos-body {
  font-family: var(--display);
  font-weight: 400;
  font-size: 40px;
  line-height: normal;
  letter-spacing: normal;
  color: var(--black);
  max-width: 1248px;
  margin: 0 0 60px 0;
}
.ethos-cta {
  font-family: var(--display);
  font-weight: 400;
  font-size: 40px;
  line-height: normal;
  letter-spacing: normal;
  color: var(--black);
  text-decoration: none;
  display: inline-flex;
  align-items: baseline;
  gap: 12px;
  cursor: pointer;
  will-change: transform;
  transition: color 300ms var(--ease), transform 300ms var(--ease);
}
.ethos-cta:hover {
  color: var(--blue);
  transform: translateY(-2px);
}
.ethos-cta__arrow {
  font-family: var(--display);
  display: inline-block;
  transition: transform 300ms var(--ease);
}
.ethos-cta:hover .ethos-cta__arrow {
  transform: translateX(3px) translateY(-2px);
}

/* ----- CONTACT FORM (shared by the floating modal) ----- */

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 1300px;
}
.contact-form__row {
  display: flex;
  gap: 16px;
}
.contact-form__row .contact-form__input {
  flex: 1;
}
.contact-form__input,
.contact-form__textarea {
  font-family: var(--mono);
  font-size: 20px;
  color: var(--black);
  background: var(--white);
  border: 1.5px solid var(--blue);
  border-radius: 14px;
  padding: 0 24px;
  outline: none;
  width: 100%;
  transition: border-color 300ms var(--ease),
              box-shadow 300ms var(--ease);
}
.contact-form__input {
  height: 70px;
}
.contact-form__textarea {
  height: 200px;
  padding: 20px 24px;
  resize: none;
  line-height: normal;
}
.contact-form__input::placeholder,
.contact-form__textarea::placeholder {
  color: rgba(0,0,0,0.35);
}
.contact-form__input:focus,
.contact-form__textarea:focus {
  border-color: var(--blue-deep);
  box-shadow: 0 0 0 3px rgba(34,0,255,0.08);
}
.contact-form__submit {
  align-self: flex-start;
  margin-top: 8px;
  height: 60px;
  padding: 0 28px;
  border-radius: 100px;
  background: transparent;
  border: 1.5px solid var(--blue);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 20px;
  color: var(--black);
  cursor: pointer;
  will-change: transform;
  transition: background 400ms var(--ease),
              color 400ms var(--ease),
              transform 400ms var(--ease);
}
.contact-form__submit:hover {
  background: var(--blue);
  color: var(--white);
  transform: translateY(-2px);
}
.contact-form__submit .arrow {
  font-family: var(--display);
  display: inline-block;
  transition: transform 400ms var(--ease);
}
.contact-form__submit:hover .arrow { transform: translateX(3px) translateY(-2px); }
.contact-form__submit:disabled { opacity: 0.55; cursor: default; transform: none; }
/* Honeypot — kept out of the layout and away from keyboard/AT users. */
.contact-form__botcheck {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  opacity: 0;
  pointer-events: none;
}
/* Success / error message under the send button. */
.contact-form__status {
  margin: 4px 0 0;
  font-family: var(--mono);
  font-size: 17px;
  line-height: 1.4;
  color: var(--blue-deep);
}
.contact-form__status.is-error { color: #c0392b; }
.contact-form__status.is-success { color: var(--blue-deep); }

/* ----- FOOTER ----- */
.footer-section {
  position: relative;
  padding: 60px var(--side) 50px;
  background: #012048;
  overflow: hidden;
  isolation: isolate;
}
/* Footer underwater video — pinned to the BOTTOM of .footer-section at
   full width with natural aspect ratio (no cropping; kelp stays visible).
   The giant "bluefin" wordmark sits on top via .wordmark-giant z-index 1.
   Has to override the `.footer-section > * { position: relative; z-index: 1 }`
   rule that applies to direct children. */
.footer-section > .footer-bg-video {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: auto;
  opacity: 0.45;
  pointer-events: none;
  z-index: 0;
}
.footer-section > * { position: relative; z-index: 1; }
.footer-row {
  display: flex; align-items: center; justify-content: space-between;
  height: 50px; margin-bottom: 90px;
}
.pill-status {
  height: 50px;
  padding: 0 28px;
  background: rgba(255, 255, 255, 0.30);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--mono);
  font-size: 18.36px;
  line-height: 1;
  color: var(--white);
  text-decoration: none;
}
.pill-status:hover { background: rgba(0,0,0,0.15); }

.footer-bottom {
  position: relative;
  display: flex; align-items: flex-end; justify-content: center;
  padding-bottom: 0;
}
.wordmark-giant {
  width: 100%;
  display: block;
  pointer-events: none;
  margin-top: 80px;
  /* No overflow:hidden here — let .footer-section clip instead so the
     wordmark appears to rise from the very bottom of the browser window. */
  position: relative;
  z-index: 1;
}
.wordmark-giant__inner {
  position: relative;
  width: 100%;
  transform: translate3d(0, 110%, 0);
  opacity: 0;
  will-change: transform, opacity;
  transition: transform 3600ms cubic-bezier(.16, 1, .3, 1),
              opacity 2400ms cubic-bezier(.16, 1, .3, 1);
}
.wordmark-giant.is-revealed .wordmark-giant__inner {
  transform: translate3d(0, 0, 0);
  opacity: 1;
}
.wordmark-giant__text {
  width: 100%; height: auto;
  display: block;
}

html, body { width: 100%; }

/* ===== reveal classes used by GSAP ===== */
.reveal-init { opacity: 0; transform: translateY(12px); }   /* subtle rise + fade */

/* ============================================================
   BLU CHAT WIDGET (BLU-49) — host-side overlay
   Ported from products/bluefin-concierge/blu/sandbox/bluefin-demo.html
   (lines ~469–645). The demo's #chat-bar element is omitted because
   the iframe IS the bar in mini-mode (concierge collapses to a pill
   via its own @media (max-height: 140px)).
   ============================================================ */
#chat-root {
  position: fixed;
  inset: 0;
  pointer-events: none;  /* children re-enable where needed */
  z-index: 100;
  /* JS writes these every frame */
  --bar-left: 0px;
  --bar-top: 400px;
  --bar-width: 800px;
  --bar-height: 60px;
  --surface-top: 400px;
  --surface-op: 0;
  --fish-op: 1;
  --page-scale: 1;
  /* Hidden until just after the nav fades in — see main.js revealUI().
     Opacity here multiplies with --fish-op / --surface-op so the descendants
     keep their state-driven fades on top of the master reveal. */
  opacity: 0;
  transition: opacity 1.6s ease;
}
#chat-root.is-revealed { opacity: 1; }

/* Fish icon sits above the bar's hero position. Fades out via --fish-op.
   Uses the same 8-bit blu.svg as the rest of the site (matches .hero-fin
   77×45 aspect from Figma node 284:411). Scales with the page, but JS can
   override on mobile via --fish-scale so the fish doesn't shrink to a dot. */
#fish {
  position: fixed;
  --_fs: var(--fish-scale, var(--page-scale));
  left: calc(var(--bar-left) + (var(--bar-width) / 2) - (77px * var(--_fs) / 2));
  top: calc(var(--bar-top) - 64px * var(--_fs));
  width: calc(77px * var(--_fs));
  height: calc(45px * var(--_fs));
  opacity: var(--fish-op);
  transition: opacity 260ms ease;
  pointer-events: none;
}
#fish img,
#fish video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: -webkit-optimize-contrast;
}

/* Glass surface — purely decorative chrome that materializes behind the
   iframe in open state. In hero/docked --surface-op=0 hides it entirely. */
#chat-surface {
  position: fixed;
  left: var(--bar-left);
  top: var(--surface-top);
  /* bottom anchors just above the iframe in open state */
  bottom: calc(100vh - var(--bar-top) - var(--bar-height));
  width: var(--bar-width);
  background: rgba(252, 252, 255, 0.55);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(34, 0, 255, 0.08);
  border-radius: 20px;
  opacity: var(--surface-op);
  pointer-events: none;
  overflow: hidden;
  transition: opacity 380ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* The iframe is both bar and surface. In hero/docked it sits at the bar
   box (mini-pill renders inside via concierge's media query). In open
   state it spans from --surface-top to bar bottom — one unified rect. */
#blu-frame {
  position: fixed;
  left: var(--bar-left);
  top: var(--bar-top);
  width: var(--bar-width);
  height: var(--bar-height);
  border: 0;
  background: transparent;
  border-radius: 20px;
  pointer-events: auto;
  color-scheme: light;
}

#chat-root[data-state="open"] #blu-frame {
  top: var(--surface-top);
  height: calc(var(--bar-top) + var(--bar-height) - var(--surface-top));
}

/* Animated transitions — only during click-driven state changes
   (scroll is 1:1 and should not be smoothed by CSS). */
#chat-root.is-animating #blu-frame,
#chat-root.is-animating #chat-surface,
#chat-root.is-animating #fish {
  transition: top 420ms cubic-bezier(0.16, 1, 0.3, 1),
              left 420ms cubic-bezier(0.16, 1, 0.3, 1),
              width 420ms cubic-bezier(0.16, 1, 0.3, 1),
              height 420ms cubic-bezier(0.16, 1, 0.3, 1),
              bottom 420ms cubic-bezier(0.16, 1, 0.3, 1),
              opacity 420ms cubic-bezier(0.16, 1, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  #blu-frame, #chat-surface, #fish {
    transition: none !important;
  }
}

/* ----- CONTACT MODAL -----
   Fixed overlay that floats above everything. Opened by the "Contact" nav
   link and the "hello@bluefin.studio" footer pill. Lives outside .page so
   the scale transform doesn't affect it. */
#contact-modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms var(--ease);
}
#contact-modal.is-open {
  pointer-events: auto;
  opacity: 1;
}
.contact-modal__overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 10, 40, 0.72);
}
.contact-modal__card {
  position: relative;
  background: var(--paper);
  border-radius: 28px;
  padding: 64px;
  width: min(720px, 100%);
  max-height: 92vh;
  overflow-y: auto;
  transform: translateY(28px);
  transition: transform 400ms var(--ease);
}
#contact-modal.is-open .contact-modal__card {
  transform: translateY(0);
}
.contact-modal__close {
  position: absolute;
  top: 28px; right: 28px;
  width: 40px; height: 40px;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  outline: none;
}
.contact-modal__close span {
  position: absolute;
  top: 50%; left: 50%;
  width: 22px; height: 2px;
  background: var(--black);
  border-radius: 1px;
  display: block;
  transition: background 200ms var(--ease);
}
.contact-modal__close span:first-child { transform: translate(-50%, -50%) rotate(45deg); }
.contact-modal__close span:last-child  { transform: translate(-50%, -50%) rotate(-45deg); }
.contact-modal__close:hover span { background: var(--blue); }

.contact-modal__label {
  font-family: var(--mono);
  font-size: 16px;
  color: var(--blue);
  margin: 0 0 14px 0;
  line-height: 1;
  letter-spacing: 0.04em;
}
.contact-modal__headline {
  font-family: var(--display);
  font-weight: 400;
  font-size: 52px;
  line-height: normal;
  letter-spacing: normal;
  color: var(--black);
  margin: 0 0 44px 0;
}
/* override the 1300px width the in-page form uses */
#contact-modal .contact-form { width: 100%; }
#contact-modal .contact-form__input    { height: 68px; font-size: 18px; }
#contact-modal .contact-form__textarea { height: 160px; font-size: 18px; }

/* Mobile contact modal — tighter padding, stacked fields, headline on one line */
@media (max-width: 734px) {
  #contact-modal { padding: 14px; }
  .contact-modal__card { padding: 36px 22px 28px; border-radius: 22px; }
  .contact-modal__label { margin-bottom: 10px; }
  .contact-modal__headline {
    font-size: clamp(34px, 11vw, 48px);
    white-space: nowrap;
    margin-bottom: 28px;
  }
  .contact-modal__close { top: 18px; right: 18px; }
  .contact-form__row { flex-direction: column; gap: 14px; }
  /* Column layout: reset the flex used for the side-by-side row, otherwise
     flex:1 flexes the VERTICAL axis and collapses the input's height. */
  .contact-form__row .contact-form__input { flex: none; }
  #contact-modal .contact-form__input    { height: 68px; font-size: 16px; }
  #contact-modal .contact-form__textarea { height: 150px; font-size: 16px; }
}


/* ============================================================
   M TIER  (735–1068px) — tablet steps (Apple medium tier)
   Same composition as L, one type/spacing step down; the open
   spotlight recomposes from absolute coordinates into a stacked
   flow column (thumb leads via flex order).
   ============================================================ */
@media (max-width: 1068px) {
  :root { --ct-gutter: 40px; }

  /* Tablet: zoom the pixel art-band in so it reads at desktop density instead
     of shrinking thin with the viewport. */
  /* Pixel art band removed on tablet + mobile (per design). Desktop (≥1069px)
     keeps it via the base .hero-art-band rule above. */
  .hero-art-band { display: none; }

  /* type steps */
  /* Flow the headline as natural text so wrapped lines return to the left
     margin (the inline-flex version indents the wrap after the fin). */
  .dive-headline { font-size: 44px; margin-top: 220px; display: block; }
  .dive-headline .dive-fin { width: 40px; height: 35px; vertical-align: middle; margin: 0 10px; }
  /* Fluid body that fills the same column as the headline (no narrow cap). */
  .dive-paragraph { font-size: 28px; margin-top: 32px; }
  .eyebrow { font-size: 20px; }
  .eyebrow::after { height: 44px; }
  /* Underline matches the header text width. The L base pins fixed widths
     on both the eyebrow container and its ::after (tuned for 24px text);
     at M's 20px those read too wide. Let the container hug the text
     (fit-content) and the underline fill it (100%). */
  .eyebrow--select-work,
  .eyebrow--services,
  .eyebrow--ethos { width: fit-content; }
  .eyebrow--select-work::after,
  .eyebrow--services::after,
  .eyebrow--ethos::after { width: 100%; }
  .eyebrow--select-work { margin: 220px 0 52px var(--side); }
  .project-row__head { padding: 48px 0 18px 0; min-height: 122px; }
  .project-row__title { font-size: 44px; }
  .project-row__plus { width: 33px; height: 33px; }
  .services-section { padding: 120px var(--side) 100px; }
  .services-section .eyebrow { margin-bottom: 48px; }
  .services { gap: 36px 52px; }
  .services .item { font-size: 44px; }
  /* Tablet is touch — relabel the hint "tap me!" (matches the S tier).
     Hide the inline "hover me!" text and render the new label via ::after
     so it inherits the blue mono styling + rotation. */
  .hover-hint { font-size: 0; top: -36px; }
  .hover-hint::after { content: 'tap me!'; font-size: 16px; }
  .ethos-section { padding: 120px var(--side) 200px; }
  .ethos-section .eyebrow { margin-bottom: 56px; }
  .ethos-body { font-size: 28px; max-width: 36ch; margin-bottom: 44px; }
  .ethos-cta { font-size: 28px; }
  .footer-row { margin-bottom: 64px; }
  .pill-status { font-size: 16px; height: 46px; padding: 0 22px; }
}

/* ============================================================
   MOBILE / S TIER  (≤ 734px) — tidy-lp methodology
   Same art direction, real flow layout. Every size is a rubber
   band: clamp(min, vw-preferred, max), tuned so a 390px viewport
   matches the approved Figma values exactly, smaller phones get
   the min, larger phones get the max. No canvas, no transform —
   the browser owns layout; JS only clears its old inline styles.
   Desktop (≥744px) never sees anything inside this block.
   ============================================================ */

:root {
  /* type */
  --m-display: clamp(32px, 9.2vw, 46px);    /* 36 @ 390 */
  --m-sub:     clamp(26px, 7.7vw, 38px);    /* 30 @ 390 */
  --m-body-lg: clamp(21px, 6.2vw, 31px);    /* 24 @ 390 */
  --m-mono:    clamp(14px, 4.4vw, 18px);    /* 17 @ 390 */
  --m-eyebrow: clamp(17px, 5.1vw, 24px);    /* 20 @ 390 */
  --m-tag:     clamp(19px, 5.6vw, 26px);    /* 22 @ 390 */
  --m-label:   clamp(14px, 4.1vw, 17px);    /* 16 @ 390 */
  /* space */
  --m-gutter:  clamp(18px, 5.1vw, 30px);    /* 20 @ 390 */
  --m-sect:    clamp(130px, 38.5vw, 210px); /* 150 @ 390 */
  --m-ease:    cubic-bezier(.16, 1, .3, 1);
}

#page-mobile  { display: none; }
.m-nav-header { display: none; }
.m-modal      { display: none; } /* exists only in the mobile zone */

@media (max-width: 734px) {
  #page, .nav { display: none !important; }
  #chat-root  { display: none !important; }
  #page-mobile  { display: block; background: var(--paper); }
  .m-nav-header { display: flex; }
  body { overflow-x: clip; }

  /* iOS 26 dropped support for <meta name="theme-color">; Safari now tints the
     top status/URL bar and bottom toolbar from the background-color of the
     fixed element at the viewport edge, falling back to <body>. We want plain
     white bars everywhere, matching the paper page — so keep <body> paper and
     make every full-screen fixed overlay paper too (see #loadin and .m-modal,
     whose spot colour is moved onto an inner element). */
  body { background-color: var(--paper); }

  /* ── Nav ── */
  .m-nav-header {
    position: fixed;
    top: calc(20px + env(safe-area-inset-top, 0px));
    left: 0; right: 0;
    z-index: 50;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--m-gutter);
    /* Fade only (no swipe). Per-direction timing: reappearing on scroll-up
       fades in gently (this base transition); hiding on scroll-down stays
       snappy (the .is-hidden transition below). */
    transition: opacity 520ms ease;
  }
  .m-nav-header.is-hidden {
    opacity: 0;
    pointer-events: none;
    transition: opacity 300ms ease;
  }
  .m-wordmark img {
    width: clamp(88px, 25vw, 112px);
    height: auto;
    display: block;
    filter: invert(1); /* white SVG → black, same as desktop */
  }
  .m-nav-pills {
    display: flex;
    align-items: center;
    background: rgba(235, 236, 240, 0.72);
    border: 1px solid rgba(255, 255, 255, 0.60);
    border-radius: 30px;
    height: 44px;
    padding: 0 6px;
    /* No backdrop-filter — matches the desktop pill and avoids the glass
       "glitch-in" flicker during the nav fade on mobile. */
  }
  .m-nav-pill {
    font-family: var(--mono);
    font-size: clamp(14px, 4.1vw, 16px);
    color: var(--black);
    text-decoration: none;
    padding: 0 16px;
    height: 100%;
    display: flex;
    align-items: center;
  }

  /* ── Hero removed — the #loadin intro overlay replaces it ── */

  /* ── Art band — same zoomed pixel band as tablet, for consistency ── */

  /* ── About ── */
  .m-about {
    padding: clamp(190px, 61.5vw, 300px) var(--m-gutter); /* 240 @ 390 (production) */
  }
  .m-about__heading {
    font-family: var(--display);
    font-weight: 400;
    font-size: var(--m-display);
    line-height: normal;
    letter-spacing: normal;
    color: var(--black);
    margin: 0 0 clamp(40px, 12.8vw, 64px); /* 50 @ 390 */
    max-width: 480px;
  }
  .m-about__fin {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    margin: 0 clamp(8px, 2.5vw, 13px);
  }
  .m-about__fin img { width: clamp(30px, 8.7vw, 42px); height: auto; }
  .m-about__body {
    font-family: var(--display);
    font-size: var(--m-body-lg);
    line-height: normal;
    color: var(--black);
    max-width: 30ch;
    margin: 0;
  }

  /* ── Shared eyebrow ── */
  .m-eyebrow {
    display: inline-flex;
    flex-direction: column;
    font-family: var(--mono);
    font-size: var(--m-eyebrow);
    line-height: 1;
    color: var(--black);
    margin: 0 0 0 var(--m-gutter);
  }
  .m-eyebrow::after {
    content: '';
    display: block;
    height: clamp(40px, 13.3vw, 56px);
    background: url('assets/blue-line.gif') no-repeat center / 100% 100%;
    margin-top: clamp(-12px, -3vw, -8px);
    overflow: hidden;
  }
  .m-eyebrow--work::after     { width: clamp(100px, 30.5vw, 132px); }
  .m-eyebrow--services::after { width: clamp(108px, 32.8vw, 142px); }
  .m-eyebrow--ethos::after    { width: clamp(82px, 25.1vw, 110px); }

  /* ── Select Work ── */
  .m-select-work { padding-top: 20px; }
  .m-select-work .m-eyebrow { margin-bottom: clamp(24px, 7.7vw, 40px); }

  .m-project-list { border-bottom: 1px solid var(--black); }
  .m-project-row {
    border-top: 1px solid var(--black);
    cursor: pointer;
    position: relative;
    -webkit-tap-highlight-color: transparent;
  }
  .m-project-row__head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    padding: clamp(28px, 9.2vw, 48px) clamp(20px, 6.2vw, 34px)
             clamp(14px, 4.1vw, 20px) var(--m-gutter);
    min-height: clamp(126px, 38.5vw, 196px); /* 150 @ 390 */
    box-sizing: border-box;
    transition: background-color 250ms var(--m-ease);
  }
  .m-project-row__title {
    font-family: var(--display);
    font-weight: 400;
    font-size: var(--m-display);
    line-height: normal;
    letter-spacing: normal;
    color: var(--black);
    margin: 0 14px 0 0;
    transition: color 300ms var(--m-ease);
  }
  .m-project-row__plus {
    position: relative;
    width: clamp(28px, 8.5vw, 38px);
    height: clamp(28px, 8.5vw, 38px);
    flex-shrink: 0;
    align-self: flex-end;
    margin-bottom: 3px;
  }
  .m-project-row__plus::before,
  .m-project-row__plus::after {
    content: '';
    position: absolute;
    background: var(--black);
    transition: background 300ms var(--m-ease);
  }
  .m-project-row__plus::before { left: 0; right: 0; top: 50%; height: 1px; transform: translateY(-0.5px); }
  .m-project-row__plus::after  { top: 0; bottom: 0; left: 50%; width: 1px; transform: translateX(-0.5px); }
  /* press feedback — row floods with its project color, same as desktop hover */
  .m-project-row[data-project="tnt"]   .m-project-row__head:active { background: var(--spot-tnt); }
  .m-project-row[data-project="knine"] .m-project-row__head:active { background: var(--spot-knine); }
  .m-project-row[data-project="astro"] .m-project-row__head:active { background: var(--spot-astro); }
  .m-project-row[data-project="pal"]   .m-project-row__head:active { background: var(--spot-pal); }
  .m-project-row[data-project="donna"] .m-project-row__head:active { background: var(--spot-donna); }
  .m-project-row[data-project="stark"] .m-project-row__head:active { background: var(--spot-stark); }
  .m-project-row__head:active .m-project-row__title { color: var(--white); }
  .m-project-row__head:active .m-project-row__plus::before,
  .m-project-row__head:active .m-project-row__plus::after { background: var(--white); }
  /* Accordion panels never open on mobile — the modal is the open state */
  .m-project-row__panel { display: none; }

  /* ── Services ── */
  .m-services-section { padding-top: var(--m-sect); }
  .m-services-list {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    gap: clamp(16px, 5.1vw, 28px) clamp(16px, 5.1vw, 24px);
    padding: clamp(20px, 6.4vw, 34px) var(--m-gutter) 0;
    max-width: 600px;
  }
  .m-services-list span {
    font-family: var(--display);
    font-size: clamp(22px, 6.7vw, 32px); /* 26 @ 390 */
    letter-spacing: normal;
    color: var(--black);
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
  }
  .m-services-list span.m-tap-me {
    position: absolute;
    top: 0;
    left: 66%;
    font-family: var(--mono);
    font-size: clamp(12px, 3.6vw, 14px);
    color: var(--blue);
    transform: rotate(-30deg);
    pointer-events: none;
  }
  .m-services-tap-img {
    position: absolute;
    width: clamp(200px, 61.5vw, 300px);
    aspect-ratio: 4 / 3;
    height: auto;
    object-fit: cover;
    border-radius: 14px;
    pointer-events: none;
    opacity: 0;
    transform: scale(0.6) rotate(-6deg);
    transition: opacity 200ms var(--ease),
                transform 480ms cubic-bezier(.34, 1.56, .64, 1);
    z-index: 5;
    box-shadow: 0 18px 50px rgba(0, 4, 60, 0.28);
  }
  .m-services-tap-img.is-visible {
    opacity: 1;
    transform: scale(1) rotate(var(--tilt, -2.5deg));
  }

  /* ── Ethos ── */
  .m-ethos-section { padding-top: var(--m-sect); }
  .m-ethos-body {
    padding: clamp(20px, 6.4vw, 34px) var(--m-gutter) 0;
    font-family: var(--display);
    font-size: var(--m-body-lg);
    line-height: normal;
    color: var(--black);
    max-width: calc(28ch + 2 * var(--m-gutter));
    margin: 0;
  }
  .m-ethos-cta {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
    margin: clamp(40px, 12.8vw, 64px) var(--m-gutter) var(--m-sect);
    font-family: var(--display);
    font-size: var(--m-body-lg);
    color: var(--black);
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  .m-ethos-cta:active { color: var(--blue); }

  /* ── Footer ── */
  .m-footer-section {
    position: relative;
    width: 100%;
    min-height: 100svh;
    min-height: 100dvh;   /* fill the full visible screen (dvh where supported) */
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: #00123e;   /* matches the image's deep-water top so edges blend */
    padding-top: calc(clamp(28px, 9.5vw, 48px) + env(safe-area-inset-top, 0px));
  }
  .m-footer-bg-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center bottom;
  }
  .m-footer-pills {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: clamp(20px, 6.9vw, 34px);
    align-items: center;
    z-index: 1;
  }
  .m-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: clamp(44px, 12.8vw, 54px);
    width: min(66.4vw, 259px); /* 259 @ 390, fluid below */
    background: rgba(255, 255, 255, 0.3);
    border-radius: 30px;
    font-family: var(--mono);
    font-size: clamp(15px, 4.7vw, 18px);
    color: var(--white);
    text-decoration: none;
    white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
  }
  .m-pill-email:active { background: rgba(255, 255, 255, 0.45); }
  .m-footer-wordmark {
    position: relative;
    margin-top: auto;
    z-index: 1;
  }
  .m-footer-wordmark__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-bottom: calc(clamp(28px, 9.5vw, 44px) + env(safe-area-inset-bottom, 0px));
    gap: 8px;
  }
  .m-footer-wordmark__text { width: min(92vw, 600px); height: auto; }
}

/* ════════════════════════════════════════════════════════════════
   FULL-SCREEN CASE-STUDY MODAL — Figma case-study pop-out (558:26)
   Photo + spot-color content panel (title, body, Services/Industry/
   Location metadata, "See it in action" CTA). Built to FIT the viewport
   at every breakpoint — no scrolling.
   ≤1068px: stacked (photo on top).   ≥1069px: split (photo left).
   ════════════════════════════════════════════════════════════════ */
.m-modal {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 200;
  overflow: hidden;
  transform: translateY(100%);
  transition: transform 480ms var(--m-ease);
  /* Paper (not the spot colour) so iOS 26 Safari samples this fixed element and
     keeps the bars white — even while open, and with nothing to "stick" on
     close. The spot colour lives on the inner .m-modal__stage below, which
     fills the screen visually but isn't a fixed element Safari samples. */
  background: var(--paper);
}
.m-modal.is-open { transform: none; }
.m-modal[data-project="tnt"]   .m-modal__stage { background: var(--spot-tnt); }
.m-modal[data-project="knine"] .m-modal__stage { background: var(--spot-knine); }
.m-modal[data-project="astro"] .m-modal__stage { background: var(--spot-astro); }
.m-modal[data-project="pal"]   .m-modal__stage { background: var(--spot-pal); }
.m-modal[data-project="donna"] .m-modal__stage { background: var(--spot-donna); }
.m-modal[data-project="stark"] .m-modal__stage { background: var(--spot-stark); }

/* Mobile: serve the smaller 1280px case-study photos (webp) so modals open
   fast on phones. !important beats the inline 2560px image-set on .cs-media. */
@media (max-width: 734px) {
  .m-spotlight[data-project="tnt"]   .cs-media { background-image: url('assets/fig/tnt-m.webp')   !important; }
  .m-spotlight[data-project="knine"] .cs-media { background-image: url('assets/fig/knine-m.webp') !important; }
  .m-spotlight[data-project="astro"] .cs-media { background-image: url('assets/fig/astro-m.webp') !important; }
  .m-spotlight[data-project="pal"]   .cs-media { background-image: url('assets/fig/pal-m.webp')   !important; }
  .m-spotlight[data-project="donna"] .cs-media { background-image: url('assets/fig/donna-m.webp') !important; }
  .m-spotlight[data-project="stark"] .cs-media { background-image: url('assets/fig/stark-m.webp') !important; }
}

/* Plain × in the top-right — same size & line weight as the row "+" (40px / 2px) */
.m-modal__close {
  position: fixed;
  top: calc(clamp(22px, 4.4vw, 36px) + env(safe-area-inset-top, 0px));
  right: clamp(18px, 4.4vw, 40px);
  z-index: 201;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.m-modal__close-icon { position: relative; display: block; width: 40px; height: 40px; transform: rotate(45deg); }
.m-modal__close-icon::before,
.m-modal__close-icon::after {
  content: ''; position: absolute; background: var(--paper); border-radius: 1px;
  filter: drop-shadow(0 1px 2px rgba(0, 8, 40, 0.25));
}
.m-modal__close-icon::before { left: 50%; top: 0; bottom: 0; width: 2px; transform: translateX(-1px); }
.m-modal__close-icon::after  { top: 50%; left: 0; right: 0; height: 2px; transform: translateY(-1px); }
.m-modal__close:hover .m-modal__close-icon::before,
.m-modal__close:hover .m-modal__close-icon::after { background: var(--white); }

.m-modal__stage { height: 100%; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.m-modal__inner { min-height: 100%; display: flex; }

/* ── Layout shell (stacked by default) ── */
.m-spotlight {
  flex: 1;
  width: 100%;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}
/* Stacked: the image flexes to fill whatever height the content block doesn't
   need, so case studies with longer/shorter copy all fit the viewport. */
.cs-media {
  flex: 1 1 auto;
  width: 100%;
  min-height: clamp(150px, 22svh, 290px);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
/* Pal Puppy: anchor the photo to top-center so crops trim from the bottom */
.m-spotlight[data-project="pal"] .cs-media { background-position: center top; }
.cs-panel {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 4svh, 40px) var(--m-gutter)
           calc(clamp(24px, 4svh, 40px) + env(safe-area-inset-bottom, 0px));
}
.cs-foot { margin-top: 0; padding-top: clamp(30px, 5.4svh, 58px); }

.cs-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(22px, 6.4vw, 26px);   /* 25 @ 390 */
  line-height: normal;
  letter-spacing: normal;
  color: var(--paper);
  margin: 0;
}
.cs-desc {
  font-family: var(--mono);
  font-size: clamp(15px, 4.1vw, 17px);   /* 16 @ 390 */
  line-height: normal;
  color: var(--paper);
  max-width: 60ch;
  margin: clamp(14px, 3.6svh, 22px) 0 0;
}

/* Metadata table — Services / Industry / Location, solid dividers */
.cs-meta { margin: 0; padding: 0; }
.cs-row {
  display: grid;
  grid-template-columns: clamp(86px, 24vw, 96px) 1fr;
  gap: 12px;
  /* label baseline-aligns to the bottom line of the value; text sits low in the row */
  align-items: end;
  padding: clamp(15px, 2.3svh, 24px) 0 clamp(6px, 1svh, 10px);
  border-top: 1px solid rgba(250, 253, 255, 0.4);
}
.cs-row:last-child { border-bottom: 1px solid rgba(250, 253, 255, 0.4); }
.cs-row dt {
  font-family: var(--mono);
  font-size: clamp(13px, 3.6vw, 14px);   /* 14 @ 390 */
  color: rgba(250, 253, 255, 0.5);
}
.cs-row dd {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(16px, 4.6vw, 19px);   /* 18 @ 390 */
  line-height: normal;
  color: var(--paper);
}
/* Mobile keeps Services to a single line — third item shows on tablet/desktop */
.cs-svc-3 { display: none; }

/* "See it in action" — same metrics & hover as the contact "Send it" button,
   adapted to the colored panel (white outline → fills white on hover). */
.cs-cta {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: clamp(20px, 3.4svh, 30px);
  height: 50px;
  padding: 0 24px;
  background: transparent;
  border: 1.5px solid var(--paper);
  border-radius: 100px;
  font-family: var(--mono);
  font-size: 16px;
  line-height: 1;
  color: var(--paper);
  text-decoration: none;
  box-sizing: border-box;
  cursor: pointer;
  will-change: transform;
  -webkit-tap-highlight-color: transparent;
  transition: background 400ms var(--ease), color 400ms var(--ease), transform 400ms var(--ease);
}
.cs-cta:hover { background: var(--paper); color: var(--black); transform: translateY(-2px); }
.cs-cta__arrow { display: inline-block; font-family: var(--display); transition: transform 400ms var(--ease); }
.cs-cta:hover .cs-cta__arrow { transform: translateX(3px) translateY(-2px); }

/* Entrance: media fades, panel content rises as the sheet slides up */
.m-modal .cs-media { opacity: 0; transition: opacity 600ms var(--m-ease) 120ms; }
.m-modal.is-open .cs-media { opacity: 1; }
.m-modal .cs-body, .m-modal .cs-foot {
  opacity: 0; transform: translateY(14px);
  transition: opacity 460ms var(--m-ease) 200ms, transform 540ms var(--m-ease) 200ms;
}
.m-modal.is-open .cs-body, .m-modal.is-open .cs-foot { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .m-modal { transition: none; }
  .m-modal .cs-media, .m-modal .cs-body, .m-modal .cs-foot { transition: none !important; }
}

/* ── ≥735px (tablet + desktop): larger type per Figma, bigger CTA ── */
@media (min-width: 735px) {
  .cs-media { min-height: clamp(260px, 34svh, 520px); }
  .cs-panel { padding-left: 40px; padding-right: 40px; }
  .cs-title { font-size: 40px; letter-spacing: 0.01em; }
  .cs-desc  { font-size: 20px; max-width: 70ch; margin-top: clamp(18px, 3svh, 28px); }
  .cs-row   { grid-template-columns: 96px 1fr; padding: clamp(18px, 2.7svh, 27px) 0 clamp(8px, 1.1svh, 11px); }
  .cs-row dt { font-size: 16px; }
  .cs-row dd { font-size: 20px; }
  .cs-svc-3 { display: inline; }
  .cs-cta { gap: 10px; height: 60px; padding: 0 28px; font-size: 20px; }
}

/* ── ≥1069px (desktop): split — photo left, content panel right ── */
@media (min-width: 1069px) {
  .m-spotlight { flex-direction: row; }
  .cs-media {
    flex: none;
    width: 62.5%;
    height: 100svh;
    min-height: 0;
    max-height: none;
  }
  .cs-panel {
    width: 37.5%;
    height: 100svh;
    padding: clamp(72px, 16svh, 168px) 44px clamp(44px, 6svh, 60px) 36px;
  }
  /* split: re-pin metadata + CTA to the bottom of the full-height panel */
  .cs-foot { margin-top: auto; }
  .cs-desc { max-width: 46ch; }
}
