/* ================================================================
   ART PRO DESIGN v2 — dark theme · chartreuse identity
   ================================================================ */

:root {
  --font-display: 'Space Grotesk', system-ui, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, sans-serif;

  --bg:           #07070b;
  --bg-2:         #0d0d16;
  --bg-3:         rgba(16, 16, 28, 0.66);
  --surface:      rgba(255, 255, 255, 0.035);
  --border:       rgba(197, 255, 61, 0.14);
  --border-hover: rgba(197, 255, 61, 0.5);
  --line:         rgba(255, 255, 255, 0.09);

  --accent:       #c5ff3d;
  --accent-glow:  rgba(197, 255, 61, 0.18);
  --violet:       #8b5cf6;

  --text:         #ececf2;
  --text-2:       rgba(236, 236, 242, 0.6);
  --text-3:       rgba(236, 236, 242, 0.32);

  --ease:         cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out:     cubic-bezier(0.2, 0.7, 0.2, 1);
  /* long, soft tail — almost no acceleration at the start and a very gentle
     settle; used by the scroll reveal, where the motion should be felt rather
     than seen arriving */
  --ease-glide:   cubic-bezier(0.16, 1, 0.3, 1);
  /* Two levels of heading on the page and nothing else:
       white uppercase display  — the heading
       violet uppercase caps    — the subheading
     `--head-gap` is the distance between them, everywhere. It used to be 6px
     in the body and 8px in the page header, which read as a mistake. */
  --head-gap:     18px;
  --header-h:     104px;
  --max:          1200px;
  --radius:       8px;
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

::selection { background: rgba(197, 255, 61, 0.6); color: #07070b; }

html { overflow-x: hidden; scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 300;
  line-height: 1.65;
  min-height: 100dvh;
  overflow-x: hidden;
  cursor: none;
}
html.is-touch body { cursor: auto; }

a { text-decoration: none; color: inherit; cursor: none; }
button, input, textarea, [role="button"] { cursor: none; font-family: inherit; }
html.is-touch a, html.is-touch button,
html.is-touch input, html.is-touch textarea { cursor: auto; }

img { max-width: 100%; display: block; }

/* Text caret only inside real form fields — everything else keeps the ring */
h1, h2, h3, h4, h5, h6, p, li, blockquote, span, cite, strong, em { cursor: none; }
html.is-touch h1, html.is-touch h2, html.is-touch h3,
html.is-touch h4, html.is-touch h5, html.is-touch h6,
html.is-touch p, html.is-touch li, html.is-touch blockquote,
html.is-touch span, html.is-touch cite { cursor: auto; }

body.cursor-text input:not([type="file"]):not([type="checkbox"]),
body.cursor-text textarea { cursor: text !important; }
body.cursor-text #cursor-ring,
body.cursor-text #cursor-dot { opacity: 0 !important; }

/* ================================================================
   BACKGROUND LAYERS
   ================================================================ */
#bg-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -2;
  pointer-events: none;
}
#bg-canvas.bg-fallback {
  background:
    radial-gradient(ellipse 80% 60% at 20% 10%, rgba(139, 92, 246, 0.14), transparent 60%),
    radial-gradient(ellipse 60% 50% at 85% 85%, rgba(197, 255, 61, 0.07), transparent 55%),
    var(--bg);
}
#bg-overlay {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 120% 90% at 50% 40%, transparent 45%, rgba(7, 7, 11, 0.42) 100%);
}

/* ================================================================
   CURSOR
   ================================================================ */
#cursor-glow { display: none; }
/* Positioner only. Moved with transform so the pointer never triggers layout —
   with left/top the browser reflows every frame, which shows up as flicker
   once the cursor is a large opaque disc sitting over moving content. */
#cursor-ring {
  position: fixed;
  left: 0;
  top: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  will-change: transform;
  transition: opacity 0.3s ease;
}
.ring-inner {
  width: 34px;
  height: 34px;
  border: 1px solid rgba(197, 255, 61, 0.65);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: width 0.3s var(--ease-out), height 0.3s var(--ease-out),
              border-color 0.25s ease, background 0.3s ease;
}
/* arrow lives inside the ring, hidden until a work card is hovered */
.cursor-arrow {
  width: 22px;
  height: 22px;
  color: #07070b;
  opacity: 0;
  transform: scale(0.5) translateX(-4px);
  transition: opacity 0.25s var(--ease-out), transform 0.35s var(--ease-out);
}
#cursor-dot {
  position: fixed;
  left: 0;
  top: 0;
  pointer-events: none;
  z-index: 9999;
  width: 5px;
  height: 5px;
  background: var(--accent);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  will-change: transform;
  transition: opacity 0.3s ease;
}
body.cursor-hover .ring-inner {
  width: 56px;
  height: 56px;
  border-color: rgba(197, 255, 61, 0.25);
}
/* over a project card: ring becomes a filled chartreuse disc with an arrow */
body.cursor-view .ring-inner {
  width: 84px;
  height: 84px;
  background: var(--accent);
  border-color: var(--accent);
}
body.cursor-view .cursor-arrow {
  opacity: 1;
  transform: scale(1) translateX(0);
}
body.cursor-view #cursor-dot { opacity: 0 !important; }

/* over a zoomable screen: same disc, but an eye instead of the arrow */
.cursor-eye {
  position: absolute;
  width: 26px;
  height: 26px;
  color: #07070b;
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 0.25s var(--ease-out), transform 0.35s var(--ease-out);
}
body.cursor-eye .ring-inner {
  width: 78px;
  height: 78px;
  background: var(--accent);
  border-color: var(--accent);
}
body.cursor-eye .cursor-eye {
  opacity: 1;
  transform: scale(1);
}
body.cursor-eye #cursor-dot { opacity: 0 !important; }
html.is-touch #cursor-ring,
html.is-touch #cursor-dot { display: none; }

/* ================================================================
   HEADER
   ================================================================ */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  padding: 0 max(2rem, calc(50vw - var(--max) / 2));
  background: linear-gradient(to bottom,
    rgba(7, 7, 11, 0.92) 0%,
    rgba(7, 7, 11, 0.82) 62%,
    rgba(7, 7, 11, 0.55) 88%,
    rgba(7, 7, 11, 0.0) 100%);
  backdrop-filter: blur(14px) saturate(120%);
  -webkit-backdrop-filter: blur(14px) saturate(120%);
}
/* soft blurred skirt so the edge doesn't cut hard across the shader */
.site-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 26px;
  pointer-events: none;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  background: linear-gradient(to bottom, rgba(7, 7, 11, 0.45), rgba(7, 7, 11, 0));
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent);
          mask-image: linear-gradient(to bottom, #000, transparent);
}
.header-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 0 18px;
}

.header-controls {
  display: flex;
  align-items: center;
  gap: 14px;
}
.cv-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 10px 18px;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 999px;
  transition: border-color 0.3s ease, color 0.3s ease, background 0.3s ease;
}
.cv-btn:hover {
  border-color: var(--border-hover);
  color: var(--accent);
}
.lang-btn {
  padding: 10px 14px;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--text-2);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: border-color 0.3s ease, color 0.3s ease;
}
.lang-btn:hover { border-color: var(--border-hover); color: var(--accent); }

.header-divider {
  height: 1px;
  background: var(--line);
}

.main-nav {
  position: relative;
  display: flex;
  align-items: center;
  gap: 34px;
  padding: 0;
}
.main-nav a {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-2);
  transition: color 0.3s ease;
  position: relative;
  padding-bottom: 4px;
}
.main-nav a:hover { color: var(--text); }
.main-nav a.active { color: var(--accent); }

/* Driven by transform, not left/width: those are layout properties, so the
   browser reflowed on every frame of the slide — visibly rough once other
   things on the page are moving. Base width is 1px and scaleX carries the
   real width. */
#nav-indicator {
  position: absolute;
  bottom: -2px;
  left: 0;
  width: 1px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
  transform-origin: left center;
  transform: translateX(0) scaleX(0);
  will-change: transform;
  transition: transform 0.4s var(--ease-out), opacity 0.3s ease;
  opacity: 0;
}
#nav-indicator.on { opacity: 1; }

/* ================================================================
   APP / PAGES
   ================================================================ */
#app {
  position: relative;
  padding-top: var(--header-h);
  min-height: 100dvh;
}
.page {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 2rem 36px;   /* the footer is the last thing — no need for a deep skirt */
  animation: pageIn 0.55s var(--ease-out) both;
}
@keyframes pageIn {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: translateY(0); }
}
.page.leaving {
  animation: pageOut 0.3s ease both;
}
@keyframes pageOut {
  to { opacity: 0; transform: translateY(-18px); }
}

/* reveal on scroll */
/* Name and work fill the opening screen exactly, so nothing from the next
   section peeks above the fold and invites a half-scroll. */
.first-screen {
  min-height: calc(100dvh - var(--header-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.reveal {
  opacity: 0;
  /* a shorter travel over a longer time: the block glides to rest instead of
     decelerating hard at the end, which is what read as abrupt */
  transform: translateY(20px);
  transition: opacity 1s var(--ease-glide), transform 1.3s var(--ease-glide);
  transition-delay: var(--d, 0s);
  will-change: opacity, transform;
}
.reveal.in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* An image that had not finished decoding when its block revealed fades in by
   itself, so a late arrival still arrives softly instead of snapping on.
   `is-fade` is set from script — without it nothing here applies. */
.case-hero img.is-fade {
  opacity: 0;
  transition: opacity 0.85s var(--ease-glide);
}
.case-hero img.is-fade.is-ready { opacity: 1; }

/* Section headings wipe up from behind their own baseline while the block
   fades in — two speeds instead of one makes the arrival feel composed. */
.section-head h2 {
  clip-path: inset(0 0 108% 0);
  transition: clip-path 0.95s var(--ease-out) var(--d, 0s);
}
.section-head.in h2 { clip-path: inset(0 0 -20% 0); }

/* section scaffolding */
.section { padding: 90px 0 0; }
/* work sits right under the hero — keep it inside the first screen */
.section#work { padding-top: 26px; }
.section-head {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 48px;
}
/* a section head can sit against either edge or on the centre line; the
   heading's wipe animation is unaffected, only the box moves */
.section-head.is-right { align-items: flex-end; text-align: right; }
.section-head.is-centered { align-items: center; text-align: center; }
.services-lede.is-centered { margin-left: auto; margin-right: auto; text-align: center; }
.section-head h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(30px, 4.5vw, 52px);
  letter-spacing: -0.01em;
  line-height: 1.05;
}
.section-num {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* ================================================================
   HERO
   ================================================================ */
.hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 28px 0 40px;
}
.hero-name {
  font-family: var(--font-display);
  font-weight: 700;
  /* one line — scales down on narrow screens instead of wrapping */
  font-size: clamp(30px, 6.4vw, 92px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.hero-name .line { display: block; overflow: hidden; }
.hero-name .line > span {
  display: inline-block;
  transform: translateY(110%);
  animation: heroLine 0.9s var(--ease-out) forwards;
}
.hero-name em {
  font-style: normal;
  color: var(--accent);
}
@keyframes heroLine { to { transform: translateY(0); } }

.hero-role {
  margin-top: 22px;
  font-family: var(--font-display);
  font-size: clamp(13px, 1.4vw, 16px);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--violet);
}
.hero-desc {
  margin-top: 18px;
  /* --hero-w is measured from the name line in JS, so both share one edge */
  max-width: min(100%, var(--hero-w, 62ch));
  font-size: clamp(14.5px, 1.25vw, 16px);
  color: var(--text-2);
}
.hero-availability {
  margin-top: 24px;
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-size: 14px;
  color: var(--text-2);
}
.hero-availability .pulse {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 0 rgba(197, 255, 61, 0.5);
  animation: pulse 2s infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(197, 255, 61, 0.45); }
  70%  { box-shadow: 0 0 0 9px rgba(197, 255, 61, 0); }
  100% { box-shadow: 0 0 0 0 rgba(197, 255, 61, 0); }
}

/* ================================================================
   FEATURED WORK CARD
   ================================================================ */
.work-card {
  position: relative;
  display: block;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--line);
  background-color: #12101e;
  aspect-ratio: 3168 / 1344;
  min-height: 420px;
  isolation: isolate;
  transition: border-color 0.4s ease, box-shadow 0.5s ease;
}
.work-card:hover {
  border-color: var(--border-hover);
  box-shadow: 0 0 60px rgba(197, 255, 61, 0.07);
}
.work-card-bg {
  position: absolute;
  inset: 0;
  background-image: url('assets/prodigy_hero.jpg');
  background-size: cover;
  background-position: center;
  transition: transform 0.9s var(--ease-out), filter 0.5s ease;
  z-index: 0;
}

/* ---- horizontal works carousel (full-bleed) ---- */
.works-rail-wrap {
  position: relative;
  width: var(--vw, 100vw);
  margin-left: calc(50% - var(--vw, 100vw) / 2);
}
.works-rail {
  display: flex;
  gap: 18px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
  padding: 4px 0;
  -webkit-overflow-scrolling: touch;
}
.works-rail::-webkit-scrollbar { display: none; }
.works-rail.dragging { scroll-behavior: auto; }

.works-rail .work-card {
  flex: 0 0 auto;
  height: clamp(210px, 38vh, 420px);   /* single-line name freed up vertical space */
  width: auto;                          /* aspect-ratio drives the width */
  min-height: 0;
}
.works-rail .work-card.is-bare { aspect-ratio: 1436 / 747; }
.works-rail .work-card.has-sketch { aspect-ratio: 16 / 9; }

/* rail controls */
.rail-ui {
  max-width: var(--max);
  margin: 20px auto 0;
  padding: 0 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.rail-dots { display: flex; gap: 8px; }
.rail-dot {
  width: 26px;
  height: 3px;
  border: 0;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.16);
  transition: background 0.35s ease, width 0.35s var(--ease-out);
}
.rail-dot.on { background: var(--accent); width: 44px; }

/* soft fade at both ends so the loop has no hard cut */
.works-rail-wrap::before,
.works-rail-wrap::after {
  content: "";
  position: absolute;
  top: 0;
  /* exactly the rail's own height — card height plus its 4px padding top and
     bottom. It used to be `bottom: 62px`, a number picked to clear the arrow
     buttons; once those were removed the row shrank and the fade sat too high. */
  height: calc(clamp(210px, 38vh, 420px) + 8px);
  width: clamp(40px, 7vw, 110px);
  pointer-events: none;
  z-index: 2;
}
.works-rail-wrap::before {
  left: 0;
  background: linear-gradient(to right, var(--bg), transparent);
}
.works-rail-wrap::after {
  right: 0;
  background: linear-gradient(to left, var(--bg), transparent);
  transition: background 0.35s ease, width 0.35s var(--ease-out);
}

@media (max-width: 860px) {
  .works-rail { gap: 12px; }
  .works-rail .work-card { height: clamp(150px, 22vh, 220px); }
  .rail-ui { padding: 0 1.3rem; }
}

/* ---- image-first card: caption + CTA appear on hover ---- */
.work-card.is-bare { aspect-ratio: 1436 / 747; min-height: 0; }
.work-card.is-static { cursor: none; }

/* ---- before/after: sketch wiped diagonally by the pointer ---- */
.work-card.has-sketch {
  --wipe: 42%;
  aspect-ratio: 16 / 9;    /* matches the fission artwork, no cropping */
}
.work-card-sketch {
  position: absolute;
  inset: 0;
  z-index: 1;
  background-size: cover;
  background-position: center;
  /* must move exactly like .work-card-bg or the two halves drift apart */
  transition: transform 0.9s var(--ease-out), filter 0.5s ease;
  will-change: transform;
  /* diagonal cut: sketch on the left of the seam, final on the right */
  -webkit-mask-image: linear-gradient(108deg, #000 calc(var(--wipe) - 1.2%), transparent calc(var(--wipe) + 1.2%));
          mask-image: linear-gradient(108deg, #000 calc(var(--wipe) - 1.2%), transparent calc(var(--wipe) + 1.2%));
}
.work-card.has-sketch:hover .work-card-sketch {
  transform: scale(1.045);
  filter: brightness(1.06);
}
.work-card-seam {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(108deg,
    transparent calc(var(--wipe) - 0.35%),
    rgba(197, 255, 61, 0.55) var(--wipe),
    transparent calc(var(--wipe) + 0.35%));
  opacity: 0.7;
  transition: opacity 0.4s ease;
}
.work-card.has-sketch:hover .work-card-seam { opacity: 1; }
/* touch: the seam is fixed, so it should not advertise itself as a control */
html.is-touch .work-card-seam { opacity: 0.45; }


.work-card.is-bare .work-card-content {
  align-items: flex-end;
  justify-content: flex-start;
  padding: 44px 48px 26px;   /* caption sits lower on the card */
}
.work-card.is-bare .work-card-inner {
  max-width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}

/* scrim only fades in on hover — the artwork is clean at rest */
.work-card.is-bare .work-card-scrim {
  opacity: 0;
  transition: opacity 0.5s var(--ease-out);
  background: linear-gradient(to top,
    rgba(4, 4, 8, 0.80) 0%,
    rgba(4, 4, 8, 0.38) 30%,
    rgba(4, 4, 8, 0.0) 62%);
}
.work-card.is-bare:hover .work-card-scrim { opacity: 1; }

.work-card.is-bare .work-card-tag,
.work-card.is-bare .work-card-cta {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.45s var(--ease-out), transform 0.55s var(--ease-out),
              background 0.35s ease, color 0.35s ease, border-color 0.35s ease;
}
.work-card.is-bare:hover .work-card-tag,
.work-card.is-bare:focus-visible .work-card-tag,
.work-card.is-bare:hover .work-card-cta,
.work-card.is-bare:focus-visible .work-card-cta {
  opacity: 1;
  transform: translateY(0);
}
/* caption leads, CTA follows a beat later */
.work-card.is-bare:hover .work-card-cta,
.work-card.is-bare:focus-visible .work-card-cta { transition-delay: 0.09s; }

.work-card.is-bare .work-card-tag {
  margin-bottom: 0;
  font-size: clamp(15px, 1.6vw, 20px);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: none;
  color: #fff;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.6);
}
/* plain text link, no button */
.work-card.is-bare .work-card-cta {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7);
}
.work-card.is-bare:hover .work-card-cta {
  background: none;
  border: 0;
  color: var(--violet);
}
.work-card:hover .work-card-bg {
  transform: scale(1.045);
  filter: brightness(1.06);
}
.work-card-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to left,
    rgba(4, 4, 8, 0.72) 0%,
    rgba(4, 4, 8, 0.45) 32%,
    rgba(4, 4, 8, 0.05) 58%,
    transparent 72%);
  pointer-events: none;
}
.work-card-content {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 60px 5.5%;
}
.work-card-inner { max-width: 440px; width: 100%; }
.work-card-tag {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 22px;
}
.work-card-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(22px, 2.2vw, 34px);
  line-height: 1.22;
  color: #fff;
  margin-bottom: 34px;
}
.work-card-metrics {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px 28px;
  margin-bottom: 32px;
}
.work-card-metrics .metric span {
  display: block;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  margin-bottom: 4px;
}
.work-card-metrics .metric strong {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 14px;
  color: #fff;
}
.work-card-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 24px;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 999px;
  transition: background 0.35s ease, color 0.35s ease, border-color 0.35s ease;
}
.work-card-cta .arrow {
  display: inline-block;
  transition: transform 0.4s var(--ease-out);
}
.work-card:hover .work-card-cta {
  background: var(--accent);
  border-color: var(--accent);
  color: #07070b;
}
.work-card:hover .work-card-cta .arrow { transform: translateX(6px); }

/* ================================================================
   SERVICES
   ================================================================ */
/* same type scale as .hero-desc so every lede on the site reads at one size */
.services-lede {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: clamp(14.5px, 1.25vw, 16px);
  line-height: 1.65;
  color: var(--text-2);
  /* wide enough for both sentences to sit on two lines */
  max-width: 86ch;
  text-wrap: balance;
  margin-bottom: 44px;
}

.services-grid {
  position: relative;
  display: grid;
  /* six services, so three across and two down — four would leave a ragged
     half-row, and the extra width lets each title sit on one line */
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.service-card {
  position: relative;
  overflow: hidden;
  padding: 30px 26px 34px;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 16px;
  /* Frosted glass, painted rather than sampled.
     backdrop-filter is deliberately NOT used here: the WebGL canvas behind the
     page repaints continuously, so the browser re-runs the blur every frame and
     the result shimmers. Layered translucent gradients give the same read on a
     dark background and are completely stable. */
  background:
    linear-gradient(150deg,
      rgba(255, 255, 255, 0.085) 0%,
      rgba(255, 255, 255, 0.032) 46%,
      rgba(255, 255, 255, 0.050) 100%),
    radial-gradient(120% 90% at 12% 0%,
      rgba(139, 92, 246, 0.20) 0%, rgba(139, 92, 246, 0) 62%),
    radial-gradient(110% 80% at 95% 100%,
      rgba(90, 120, 255, 0.13) 0%, rgba(90, 120, 255, 0) 60%),
    rgba(14, 14, 22, 0.55);
  box-shadow:
    0 1px 0 0 rgba(255, 255, 255, 0.12) inset,
    0 0 0 1px rgba(255, 255, 255, 0.02) inset,
    0 -1px 0 0 rgba(255, 255, 255, 0.03) inset,
    0 18px 40px -22px rgba(0, 0, 0, 0.65);
  transition: border-color 0.35s ease, transform 0.35s var(--ease-out),
              box-shadow 0.35s ease;
}
/* chartreuse glow along the top edge — fades in on hover */
.service-card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 62%;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(197, 255, 61, 0.16) 0%,
    rgba(197, 255, 61, 0.05) 42%,
    rgba(197, 255, 61, 0) 100%
  );
  opacity: 0;
  transition: opacity 0.35s ease;
}
.service-card:hover {
  border-color: var(--border-hover);
  box-shadow:
    0 -1px 0 0 rgba(197, 255, 61, 0.35) inset,
    0 -1px 0 0 rgba(255, 255, 255, 0.04) inset,
    0 26px 50px -24px rgba(0, 0, 0, 0.7);
  transform: translateY(-4px);
}
.service-card:hover::before { opacity: 1; }
.service-card > * { position: relative; z-index: 1; }
.service-card.reveal.in:hover { transform: translateY(-4px); }
.service-num {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 500;
  color: var(--violet);
  margin-bottom: 14px;
}
.service-card h4 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(16px, 1.5vw, 19px);
  letter-spacing: -0.005em;
  white-space: nowrap;
  margin-bottom: 18px;
  transition: color 0.35s ease;
}
.service-card:hover h4 { color: var(--accent); }
.service-card p {
  font-size: 13.5px;
  line-height: 1.62;
  color: var(--text-2);
  transition: color 0.35s ease;
}
/* lift the body copy to full white on hover — the chartreuse wash across the
   top of the card eats contrast otherwise */
.service-card:hover p { color: var(--text); }

/* ================================================================
   TESTIMONIALS
   ================================================================ */
.testimonials-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 40px 48px;
}
.testimonial {
  position: relative;
  overflow: hidden;
  padding: 30px 30px 34px;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 16px;
  /* Painted glass — same approach as .service-card.
     No backdrop-filter: the WebGL canvas behind the page repaints every frame
     and would make the blur shimmer. */
  background:
    linear-gradient(150deg,
      rgba(255, 255, 255, 0.085) 0%,
      rgba(255, 255, 255, 0.032) 46%,
      rgba(255, 255, 255, 0.050) 100%),
    radial-gradient(120% 90% at 12% 0%,
      rgba(139, 92, 246, 0.20) 0%, rgba(139, 92, 246, 0) 62%),
    radial-gradient(110% 80% at 95% 100%,
      rgba(90, 120, 255, 0.13) 0%, rgba(90, 120, 255, 0) 60%),
    rgba(14, 14, 22, 0.55);
  box-shadow:
    0 1px 0 0 rgba(255, 255, 255, 0.12) inset,
    0 0 0 1px rgba(255, 255, 255, 0.02) inset,
    0 -1px 0 0 rgba(255, 255, 255, 0.03) inset,
    0 18px 40px -22px rgba(0, 0, 0, 0.65);
  transition: border-color 0.35s ease, transform 0.35s var(--ease-out),
              box-shadow 0.35s ease;
}
/* chartreuse glow along the top edge — fades in on hover */
.testimonial::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 62%;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(197, 255, 61, 0.16) 0%,
    rgba(197, 255, 61, 0.05) 42%,
    rgba(197, 255, 61, 0) 100%
  );
  opacity: 0;
  transition: opacity 0.35s ease;
}
.testimonial:hover {
  border-color: var(--border-hover);
  box-shadow:
    0 -1px 0 0 rgba(197, 255, 61, 0.35) inset,
    0 -1px 0 0 rgba(255, 255, 255, 0.04) inset,
    0 26px 50px -24px rgba(0, 0, 0, 0.7);
  transform: translateY(-4px);
}
.testimonial:hover::before { opacity: 1; }
.testimonial > * { position: relative; z-index: 1; }
.testimonial.reveal.in:hover { transform: translateY(-4px); }
.testimonial cite {
  display: flex;
  align-items: center;
  gap: 14px;
  font-style: normal;
  margin-bottom: 22px;
}
.testimonial-avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid var(--line);
}
.testimonial cite strong {
  display: block;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 15px;
  color: var(--text);
}
.testimonial cite span {
  font-size: 12.5px;
  color: var(--text-3);
}
.testimonial blockquote {
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-2);
  transition: color 0.35s ease;
}
.testimonial:hover blockquote { color: var(--accent); }

/* ================================================================
   CASE STUDY PAGE
   ================================================================ */
.case-head {
  /* one number drives both sides of the header, so the client's mark can never
     drift out of step with the title it stands opposite */
  --case-title: clamp(40px, 6.4vw, 88px);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 26px;
  flex-wrap: wrap;
}
.case-head-text { min-width: 0; }
/* the project name gets the same display treatment as the section headings */
.case-head h1.case-display {
  font-size: var(--case-title);
  margin-bottom: var(--head-gap);
}
/* the client's mark, set to the cap height of the title rather than to its
   line box — matching the box would leave the logo visibly taller than the
   letters it sits beside */
.case-client {
  height: calc(var(--case-title) * 0.8);
  width: auto;
  margin-top: calc(var(--case-title) * 0.06);
  /* no effect on a cut-out mark; softens the ones that come as a solid badge */
  border-radius: 10px;
  flex: none;
  align-self: flex-start;
}
.case-head .case-subtitle { margin-bottom: 0; }

/* ---------- auto-scrolling screen strip ---------- */
/* Driven by scrollLeft in JS, not by a transform animation.
   A transform-animated track is one composited layer as wide as all the
   images put together — past ~16k px Chrome cannot keep it as a texture and
   drops to software rasterising, which is what made the screen flicker.
   Scrolling only ever rasterises the visible slice. */
.case-strip {
  position: relative;
  width: var(--vw, 100vw);
  margin-left: calc(50% - var(--vw, 100vw) / 2);
  /* vertical padding leaves room for the hover zoom — the container clips,
     so without it the enlarged screen loses its top and bottom edges */
  padding: 22px 0;
  margin-bottom: 34px;
  overflow: hidden;
  scroll-behavior: auto;
  /* Fence the strip off from the rest of the page. Without containment,
     scrolling a full-viewport-width box every frame invalidates paint outside
     it too — including the fixed WebGL canvas underneath, which then redraws
     constantly and flashes the whole screen. */
  contain: layout paint style;
  will-change: scroll-position;
}
.case-strip-track {
  display: flex;
  width: max-content;
}
.case-strip-run {
  display: flex;
  gap: 18px;
  padding-right: 18px;
}
/* no frame, no background — the artwork carries its own rounded device edge
   in the alpha channel, so it sits straight on the page */
.case-strip figure {
  margin: 0;
  flex: 0 0 auto;
  height: clamp(200px, 30vh, 340px);
}
/* The hovered screen grows a little — the click affordance.
   Scoped to `.is-still`, which JS only sets once the strip has parked: while
   the images are sliding, a per-image :hover would flip on and off as the
   gaps pass under the pointer. Parked, a transform is compositor-only and
   costs nothing. */
.case-strip img {
  transform-origin: center;
  transition: transform 0.35s var(--ease-out);
}
.case-strip.is-still figure:hover img {
  transform: scale(1.07);
}

/* No hover transform here on purpose.
   The track runs an infinite transform animation on one large composited
   layer. Any transform or filter on a child mid-animation forces Chrome to
   re-rasterise that layer every frame, which reads as the whole screen
   flickering and the strip stuttering. The eye cursor already signals that
   the screens are clickable, so the hover cue costs nothing to drop. */
.case-strip img {
  display: block;
  height: 100%;
  width: auto;
}
@media (prefers-reduced-motion: reduce) {
  .case-strip { overflow-x: auto; }
}

/* ---------- lightbox ---------- */
.case-strip, .case-strip img { cursor: none; }

/* `display: none` when closed, and no backdrop-filter.
   A full-viewport backdrop-filter sits over the WebGL canvas even while
   hidden, so Chrome re-blurs the entire screen on every canvas frame — that
   is what was flickering, not the strip. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  align-items: center;
  justify-content: center;
  /* no padding and no gap: the controls float over the image instead of
     taking a column each, so the picture gets the whole viewport */
  gap: 0;
  padding: 0;
  background: rgba(5, 5, 9, 0.96);
  opacity: 0;
  transition: opacity 0.25s ease;
}
body.lb-open .lightbox { display: flex; }
body.lb-open .lightbox.is-in { opacity: 1; }
body.lb-open { overflow: hidden; }

.lb-img {
  max-width: 100vw;
  max-height: 100vh;
  width: auto;
  height: auto;
  object-fit: contain;
  /* never let the browser soften the full-resolution original */
  image-rendering: -webkit-optimize-contrast;
  /* Opacity only — no scale, no slide. Every shot is a different width, so a
     transform made the frame jump around as it resized between images. */
  opacity: 0;
  transition: opacity 0.17s var(--ease);
}
body.lb-open .lightbox.is-in .lb-img { opacity: 1; }

/* stepping between shots: fade out, swap, fade back in */
body.lb-open .lightbox.is-in.swapping .lb-img { opacity: 0; }

/* thin progress hint while the full-size file is still downloading */
.lightbox.is-loading::after {
  content: '';
  position: absolute;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  background: linear-gradient(90deg,
    transparent, var(--accent), transparent);
  animation: lb-load 1.1s linear infinite;
}
@keyframes lb-load {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

.lb-close,
.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  backdrop-filter: none;
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.05);
  color: var(--text-2);
  transition: color 0.25s ease, border-color 0.25s ease, background 0.25s ease;
}
.lb-close:hover,
.lb-nav:hover {
  color: var(--accent);
  border-color: var(--border-hover);
  background: rgba(197, 255, 61, 0.08);
}
.lb-prev { left: 18px; }
.lb-next { right: 18px; }
.lb-close {
  position: absolute;
  top: 22px;
  right: 22px;
  z-index: 2;
  /* the image now runs to the edges, so the controls need their own ground
     to stay legible over a bright corner */
  background: rgba(5, 5, 9, 0.55);
  border-radius: 50%;
  padding: 9px;
}
.lb-count {
  background: rgba(5, 5, 9, 0.55);
  padding: 5px 12px;
  border-radius: 999px;
}
.lb-count {
  position: absolute;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--text-3);
}
/* In viewing mode the halves of the picture are the controls, so the arrow on
   the side you are about to go brightens as a hint. */
.lightbox.to-prev .lb-prev,
.lightbox.to-next .lb-next {
  color: var(--text);
  border-color: rgba(255, 255, 255, 0.45);
  background: rgba(255, 255, 255, 0.12);
}

/* one image on its own: nothing to step to */
.lightbox.is-single .lb-nav,
.lightbox.is-single .lb-count { display: none; }
@media (max-width: 640px) {
  .lightbox { padding: 0; gap: 0; }
  .lb-nav { width: 38px; height: 38px; }
  .lb-prev { left: 8px; }
  .lb-next { right: 8px; }
}

/* ---------- project brief ---------- */
.case-brief {
  margin-bottom: 48px;
}
/* Contact is a separate screen from the work — give it real air above so the
   two never read as one continuous block. */
#contacts { padding-top: 150px; }

/* Same idea inside a case study: the rail of other projects is a new chapter,
   not a continuation of the one being read. */
.case-brief + #work,
.case-gallery + #work { padding-top: 130px; }
.brief-lede {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(19px, 2.2vw, 30px);
  line-height: 1.38;
  letter-spacing: -0.01em;
  color: var(--text);
  max-width: 30ch;
  text-wrap: balance;
  margin-bottom: 36px;
}

/* facts strip — company · year · role · scope
   No panel: the type sits straight on the page, each column marked by a thin
   rule that fades out downwards, with a bright chartreuse tick at the top. */
.brief-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0 34px;
  margin-bottom: 30px;
}
.brief-fact {
  position: relative;
  padding: 2px 0 4px 18px;
}
/* one thin rule of even weight, muted grey-violet — structure, not accent */
.brief-fact::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: rgba(150, 138, 190, 0.30);
}
.brief-fact dt {
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 7px;
}
.brief-fact dd {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.4;
  color: var(--text);
}
/* the two facts that carry the most weight, one accent each */
.brief-fact.is-key dd {
  color: var(--accent);
  font-weight: 500;
}
.brief-fact.is-alt dd {
  color: var(--violet);
  font-weight: 500;
}

/* the narrative — problem · contribution · outcome */
.brief-body {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}
.brief-block {
  position: relative;
  overflow: hidden;
  padding: 26px 26px 30px;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 16px;
  /* painted glass — same recipe as the service cards */
  background:
    linear-gradient(150deg,
      rgba(255, 255, 255, 0.085) 0%,
      rgba(255, 255, 255, 0.032) 46%,
      rgba(255, 255, 255, 0.050) 100%),
    radial-gradient(120% 90% at 12% 0%,
      rgba(139, 92, 246, 0.20) 0%, rgba(139, 92, 246, 0) 62%),
    radial-gradient(110% 80% at 95% 100%,
      rgba(90, 120, 255, 0.13) 0%, rgba(90, 120, 255, 0) 60%),
    rgba(14, 14, 22, 0.55);
  box-shadow:
    0 1px 0 0 rgba(255, 255, 255, 0.12) inset,
    0 -1px 0 0 rgba(255, 255, 255, 0.03) inset,
    0 18px 40px -22px rgba(0, 0, 0, 0.65);
  transition: border-color 0.35s ease, transform 0.35s var(--ease-out),
              box-shadow 0.35s ease;
}
.brief-block::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 62%;
  pointer-events: none;
  background: linear-gradient(to bottom,
    rgba(197, 255, 61, 0.16) 0%,
    rgba(197, 255, 61, 0.05) 42%,
    rgba(197, 255, 61, 0) 100%);
  opacity: 0;
  transition: opacity 0.35s ease;
}
.brief-block:hover {
  border-color: var(--border-hover);
  box-shadow:
    0 -1px 0 0 rgba(197, 255, 61, 0.35) inset,
    0 26px 50px -24px rgba(0, 0, 0, 0.7);
  transform: translateY(-4px);
}
.brief-block:hover::before { opacity: 1; }
.brief-block > * { position: relative; z-index: 1; }
.brief-num {
  display: block;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 500;
  color: var(--violet);
  margin-bottom: 12px;
  /* own layer so the shake never nudges the text below it */
  transform-origin: left center;
  will-change: transform;
  transition: color 0.35s ease;
}
@keyframes brief-num-shake {
  0%   { transform: translateX(0)      rotate(0deg); }
  12%  { transform: translateX(-2.5px) rotate(-4deg); }
  26%  { transform: translateX(2.5px)  rotate(4deg); }
  40%  { transform: translateX(-2px)   rotate(-3deg); }
  54%  { transform: translateX(2px)    rotate(3deg); }
  68%  { transform: translateX(-1.2px) rotate(-1.8deg); }
  82%  { transform: translateX(1.2px)  rotate(1.8deg); }
  100% { transform: translateX(0)      rotate(0deg); }
}
.brief-block:hover .brief-num {
  color: var(--accent);
  animation: brief-num-shake 0.55s var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  .brief-block:hover .brief-num { animation: none; }
}
.brief-block h3 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(15px, 1.4vw, 18px);
  letter-spacing: -0.005em;
  margin-bottom: 14px;
  transition: color 0.35s ease;
}
.brief-block:hover h3 { color: var(--accent); }
.brief-block p {
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--text-2);
  transition: color 0.35s ease;
}
/* lift the body copy to full white on hover — the chartreuse wash across the
   top of the card eats contrast otherwise */
.brief-block:hover p { color: var(--text); }

@media (max-width: 640px) {
  .brief-lede { max-width: none; }
  .brief-facts { grid-template-columns: repeat(2, 1fr); }
}

/* one continuous stack — the frame lives on the container so nothing
   separates the images from each other */
.case-gallery {
  display: grid;
  gap: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  line-height: 0;
}
/* the frames open full-screen, so the border lifts under the pointer to say so */
.case-gallery.is-gallery { transition: border-color 0.35s ease; }
.case-gallery.is-gallery:hover { border-color: var(--border-hover, rgba(255,255,255,0.24)); }
.case-gallery figure {
  margin: 0;
  overflow: hidden;
}
.case-gallery img { display: block; width: 100%; height: auto; }

/* interactive embed (Figma prototype, video, …) */
.case-embed {
  --embed-ratio: 16 / 9;
  margin: 28px 0;
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  background: #0a0a10;
}
.case-embed iframe {
  display: block;
  width: 100%;
  aspect-ratio: var(--embed-ratio);
  border: 0;
}
.case-embed figcaption {
  padding: 13px 18px;
  font-size: 12.5px;
  color: var(--text-3);
  border-top: 1px solid var(--line);
}
@media (max-width: 860px) {
  .case-embed { --embed-ratio: 4 / 3; }
}

/* ================================================================
   CONTACT
   ================================================================ */
.contact-grid {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: 60px;
  align-items: start;
}
.contact-text h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(30px, 4.5vw, 52px);
  letter-spacing: -0.01em;
  line-height: 1.05;
  margin: 10px 0 24px;
}
.contact-text h2 em {
  font-style: normal;
  color: var(--accent);
}
.contact-text p {
  font-size: 16px;
  color: var(--text-2);
  max-width: 44ch;
}
.contact-text strong { font-weight: 500; color: var(--text); }

/* the address sits between the copy and the social row — the direct way to
   reach me, for people who would rather not fill in a form */
.contact-mail {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 28px;
  flex-wrap: wrap;
}
.contact-mail a {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-family: var(--font-display);
  font-size: clamp(17px, 2vw, 24px);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-1);
  transition: color 0.3s ease;
}
.contact-mail a:hover { color: var(--accent); }
/* drawn in currentColor, so it turns chartreuse with the address on hover.
   Sized off the text rather than fixed, so the two scale together. */
.mail-icon {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  opacity: 0.7;
  transition: opacity 0.3s ease;
}
.contact-mail a:hover .mail-icon { opacity: 1; }
.contact-mail + .socials-row { margin-top: 26px; }

.contact-form {
  background: var(--bg-3);
  border: 1px solid var(--line);
  padding: 22px;
  border-radius: 16px;
  display: grid;
  gap: 12px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.form-lede {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: clamp(14.5px, 1.25vw, 16px);
  line-height: 1.65;
  color: var(--text-2);
  margin: 4px 4px 8px;
}
.hp-field { display: none; }
.form-card {
  background: rgba(255, 255, 255, 0.045);
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 15px 18px;
  transition: border-color 0.3s ease, background 0.3s ease;
}
.form-card:focus-within {
  border-color: var(--border-hover);
  background: rgba(255, 255, 255, 0.06);
}
.form-card input,
.form-card textarea {
  width: 100%;
  background: transparent;
  border: 0;
  outline: 0;
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--text);
  padding: 0;
}
.form-card textarea {
  resize: vertical;
  min-height: 104px;
  line-height: 1.55;
  display: block;
}
.form-card input::placeholder,
.form-card textarea::placeholder { color: var(--text-3); opacity: 1; }

.form-card.is-file { padding: 13px 18px; }
.form-card.is-file input[type="file"] {
  font-size: 13.5px;
  color: var(--text-3);
}
.form-card.is-file input[type="file"]::file-selector-button {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 7px 14px;
  margin-right: 12px;
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--text);
  cursor: none;
  transition: border-color 0.3s ease;
}
.form-card.is-file input[type="file"]::file-selector-button:hover {
  border-color: var(--border-hover);
}
.form-card .file-hint {
  font-size: 11px;
  color: var(--text-3);
  letter-spacing: 0.04em;
  margin-top: 7px;
}

.form-verify {
  background: rgba(255, 255, 255, 0.045);
  border-radius: 10px;
  padding: 13px 18px;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  user-select: none;
  font-size: 13.5px;
  color: var(--text-2);
}
.form-verify input { position: absolute; opacity: 0; pointer-events: none; }
.verify-box {
  width: 21px;
  height: 21px;
  border: 1.5px solid var(--line);
  border-radius: 5px;
  position: relative;
  flex-shrink: 0;
  transition: background 0.25s ease, border-color 0.25s ease;
}
.form-verify input:checked + .verify-box {
  background: var(--accent);
  border-color: var(--accent);
}
.form-verify input:checked + .verify-box::after {
  content: '';
  position: absolute;
  left: 6px;
  top: 2px;
  width: 5px;
  height: 10px;
  border: solid #07070b;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.form-submit {
  display: block;
  width: 100%;
  padding: 16px 24px;
  background: var(--accent);
  color: #07070b;
  border: 0;
  border-radius: 10px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: background 0.3s ease, transform 0.25s var(--ease-out), box-shadow 0.3s ease;
}
.form-submit:hover {
  background: #d4ff6a;
  box-shadow: 0 0 32px rgba(197, 255, 61, 0.25);
  transform: translateY(-1px);
}
.form-submit:disabled { opacity: 0.5; }
.form-status {
  font-size: 13px;
  color: var(--text-3);
  text-align: center;
  min-height: 18px;
}
.form-status.is-error   { color: #f87171; }
.form-status.is-success { color: var(--accent); }

/* socials row */
.socials-row {
  display: flex;
  gap: 26px;
  margin-top: 36px;
}
.socials-row a {
  display: inline-flex;
  color: var(--text-2);
  transition: color 0.3s ease, transform 0.3s var(--ease-out);
}
/* the SVGs carry width/height attributes — override both */
.socials-row a svg {
  width: 34px;
  height: 34px;
}
/* Behance is a wide wordmark, so it gets its own proportions rather than a
   square box. Painted as a mask over currentColor so it still turns
   chartreuse on hover like the other two. */
.icon-behance {
  display: block;
  width: 42px;
  height: 27px;          /* artwork is 126 × 80 */
  background-color: currentColor;
  /* inlined as a data URI: Chrome refuses to load a mask image from a
     file:// URL, and the element then renders as nothing at all */
  -webkit-mask-image: url("data:image/png;base64,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");
          mask-image: url("data:image/png;base64,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");
  -webkit-mask-size: contain;   mask-size: contain;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
.socials-row a:hover { color: var(--accent); transform: translateY(-2px); }

/* ================================================================
   FOOTER
   ================================================================ */
.site-footer {
  border-top: 1px solid var(--line);
  margin-top: 76px;
  padding: 34px 0 6px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 14px;
  font-size: 12px;
  color: var(--text-3);
}

/* ================================================================
   RESPONSIVE
   ================================================================ */
@media (max-width: 1023px) {
  .services-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  :root { --header-h: 96px; }
  .cv-btn span#cv-label { display: none; }
  .cv-btn { padding: 10px 13px; }
  .main-nav { gap: 20px; overflow-x: auto; scrollbar-width: none; }
  .main-nav::-webkit-scrollbar { display: none; }
  .main-nav a { font-size: 11px; letter-spacing: 0.12em; white-space: nowrap; }
  .hero { padding: 20px 0 60px; }
  .work-card { aspect-ratio: auto; min-height: 520px; }
  .work-card-content { align-items: flex-end; padding: 40px 26px; }
  .work-card-inner { max-width: 100%; }
  .work-card-tag { white-space: normal; font-size: 11px; }
  .work-card-scrim {
    background: linear-gradient(to top,
      rgba(4, 4, 8, 0.8) 0%, rgba(4, 4, 8, 0.45) 42%, rgba(4, 4, 8, 0.08) 100%);
  }
  .services-grid { grid-template-columns: 1fr; }
  .service-card h4 { white-space: normal; }
  .testimonials-grid { grid-template-columns: 1fr; gap: 24px; }
  .contact-grid { grid-template-columns: 1fr; gap: 40px; }
  .page { padding: 0 1.4rem 28px; }
  .site-header { padding: 0 1.4rem; }
}

/* ================================================================
   PHONE LAYER
   Applied only when the device is both touch and physically small, so a
   narrow desktop window keeps the desktop layout. Type and spacing only —
   the structure of every page is identical to desktop.
   ================================================================ */
html.is-phone .hero {
  padding: 8px 0 44px;
}
/* The name is the loudest thing on the screen. On a phone it can afford to
   be much larger relative to the viewport, and it wraps onto two lines
   instead of shrinking to fit one. */
html.is-phone .hero-name {
  font-size: clamp(38px, 13.5vw, 68px);
  line-height: 0.98;
  letter-spacing: -0.03em;
  white-space: normal;
}
html.is-phone .hero-name .line,
html.is-phone .hero-name .line > span {
  display: block;
  white-space: normal;
}
html.is-phone .hero-role {
  margin-top: 18px;
  font-size: 12px;
  letter-spacing: 0.16em;
}
/* --hero-w is measured from the desktop name line; on a phone the copy
   should simply run the full width of the screen. */
html.is-phone .hero-desc {
  max-width: none !important;
  font-size: 16px;
  line-height: 1.6;
}
html.is-phone .hero-desc br { display: none; }
html.is-phone .hero-availability { margin-top: 26px; }

/* section headings and lede */
html.is-phone .section { padding-top: 64px; }
html.is-phone .section-head { margin-bottom: 30px; }
html.is-phone .section-head h2 { font-size: clamp(26px, 8.5vw, 40px); }
html.is-phone .services-lede {
  max-width: none;
  font-size: 15.5px;
  line-height: 1.62;
  margin-bottom: 30px;
}

/* cards: a little more room to breathe, a little less type */
html.is-phone .service-card { padding: 26px 22px 28px; }
html.is-phone .service-card p,
html.is-phone .brief-block p { font-size: 14px; line-height: 1.6; }
html.is-phone .testimonial { padding: 24px 22px 26px; }
html.is-phone .testimonial blockquote { font-size: 15px; }

/* case study head and facts */
html.is-phone .case-head { margin-bottom: 20px; }
html.is-phone .case-head h1 { font-size: clamp(22px, 7.5vw, 34px); }
html.is-phone .brief-facts {
  grid-template-columns: 1fr 1fr;
  gap: 20px 26px;
  margin-bottom: 26px;
}
html.is-phone .brief-fact dd { font-size: 15px; }

/* the big vertical gaps read as empty on a small screen */
html.is-phone #contacts { padding-top: 90px; }
html.is-phone .case-brief + #work,
html.is-phone .case-gallery + #work { padding-top: 80px; }
html.is-phone .case-strip { margin-bottom: 26px; }
html.is-phone .site-footer { margin-top: 56px; }

/* the opening screen is taller than a phone viewport anyway — let it size
   to its content rather than forcing extra empty space above the fold */
html.is-phone .first-screen { min-height: 0; }

/* first gallery frame: visible from the first paint, never waits on a scroll */
.case-gallery figure.is-first { opacity: 1; }

/* ---------- project key visual ---------- */
.case-hero {
  margin: 0 0 44px;
  line-height: 0;
}
.case-hero img { display: block; width: 100%; height: auto; }
html.is-phone .case-hero { margin-bottom: 30px; }

/* Per-block colour grading, driven from content by a `tone` field.
   The filter sits on the section rather than on each image, so hover filters
   inside it still apply and simply compose with this one. */
.has-tone { filter: var(--tone, none); }

/* ---------- colour code ----------
   Four groups of swatches. The card is `.brief-block`, like every other panel
   on the site, so the glass and the hover behaviour cannot drift from it. */
.case-palette {
  display: grid;
  grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr));
  gap: 16px;
  margin: 0 0 56px;
  /* every card takes the height of the tallest: a ragged bottom edge reads
     as a layout mistake, empty space inside a card does not */
  align-items: stretch;
}
.pal-group { display: flex; flex-direction: column; }
/* the heading reserves two lines whether or not it needs them, so a group
   whose name wraps does not push its swatches down past its neighbours */
.pal-group h3 {
  line-height: 1.3;
  min-height: 2.6em;
  margin-bottom: 22px;
}
/* and the list reserves the tallest group's four rows, so every description
   starts on the same line across the row as well */
.pal-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* border-box, so the reserve has to carry the padding and the rule as well
     as the four swatch rows — otherwise a four-colour group outgrows it and
     its divider drops below everyone else's */
  min-height: calc(4 * 30px + 3 * 12px + 26px + 1px);
  /* a hairline closes the swatches off from the copy: the rule is the same
     hairline the cards are outlined with, so it reads as part of the recipe */
  padding-bottom: 26px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.09);
  margin-bottom: 26px;
}
.pal-item { display: flex; align-items: center; gap: 12px; }
.pal-chip {
  width: 30px;
  height: 30px;
  border-radius: 9px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  flex: none;
}
/* the swatch is the value; the number is only its index in the sheet, so it
   stays quiet and lets the colour do the talking */
.pal-no {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
  transition: color 0.35s ease;
}
.pal-group:hover .pal-no { color: var(--text-2); }
/* with the heading and the list both reserved, the copy starts on the same
   line in every card; any slack is left at the foot of the card */
.pal-group .pal-note {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-2);
  transition: color 0.35s ease;
}
.pal-group .pal-note + .pal-note { margin-top: 12px; }
.pal-group:hover .pal-note { color: var(--text); }
@media (max-width: 1000px) {
  .case-palette { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .case-palette { grid-template-columns: 1fr; }
}

/* ---------- vector diagram ---------- */
.case-diagram { margin: 0 0 56px; }
.case-diagram svg {
  display: block;
  width: 100%;
  height: auto;
  /* the diagram inherits the page type rather than carrying its own */
  font-family: var(--font-display);
}
.diagram-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 26px;
  margin-top: 22px;
  font-size: 12.5px;
  color: var(--text-2);
}
.legend-item { display: inline-flex; align-items: center; }
.legend-item::before {
  content: '';
  width: 22px;
  height: 2px;
  margin-right: 9px;
  background: var(--c, var(--text-3));
}
.legend-item.is-dashed::before {
  height: 0;
  border-top: 2px dashed var(--c, var(--text-3));
  background: none;
}
/* on a phone the chart is unreadable at page width — it scrolls sideways
   instead of shrinking the labels into nothing */
@media (max-width: 760px) {
  .case-diagram { overflow-x: auto; }
  .case-diagram svg { min-width: 900px; }
}

/* ---------- intro spread: the cards that frame the project ----------
   The card itself is `.brief-block`, so the glass, the hover lift, the wash and
   the colour changes all come from there and cannot drift apart from it. What
   follows is only what this variant adds: the flag pair, the list, the second
   heading and the closing line. */
.case-intro {
  display: grid;
  grid-template-columns: repeat(var(--cards, 3), minmax(0, 1fr));
  align-items: stretch;
  gap: 16px;
  margin: 0 0 56px;
}
.intro-card { display: flex; flex-direction: column; }
.intro-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 14px;
}
.intro-head h3 { margin-bottom: 0; }
.intro-flags { display: inline-flex; gap: 8px; flex: none; }
.intro-flags img { width: 26px; height: 26px; display: block; }

/* lists read as copy, so they take the paragraph colour and its hover change */
.intro-card ul li {
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--text-2);
  list-style: disc;
  transition: color 0.35s ease;
}
.brief-block:hover .intro-card li,
.intro-card:hover li { color: var(--text); }
.intro-card p + p,
.intro-card ul { margin-top: 12px; }
.intro-card ul { padding-left: 17px; }
.intro-card li + li { margin-top: 4px; }

/* the "why it mattered" turn inside the third card */
.intro-sub {
  margin-top: 24px;
  margin-bottom: 10px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(14px, 1.3vw, 17px);
  color: var(--violet);
  transition: color 0.35s ease;
}
.intro-card:hover .intro-sub { color: var(--accent); }
.intro-card .intro-aside { font-style: italic; }

/* the closing line, pushed to the foot so the cards end on one baseline
   however uneven the copy above them is */
.intro-card .intro-note {
  margin-top: auto;
  padding-top: 24px;
  font-style: italic;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--violet);
  transition: color 0.35s ease;
}
.intro-card:hover .intro-note { color: var(--accent); }
.intro-card .intro-note strong { font-weight: 500; color: inherit; }

/* four-up cards get a two-column step before collapsing: at this width a
   quarter column is too narrow for a sentence to keep its rhythm */
@media (max-width: 1160px) {
  .case-intro:has(> :nth-child(4)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1000px) {
  .case-intro { grid-template-columns: 1fr; gap: 12px; }
  .intro-note { margin-top: 20px; padding-top: 0; }
}
html.is-phone .case-intro { margin-bottom: 34px; }

/* ---------- outcome spread: one figure leads, two support ---------- */
.case-impact { margin: 0 0 56px; }
.impact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 18px;
  align-items: stretch;
}
/* The card itself is `.brief-block` — one recipe for every panel on the site.
   Hierarchy here comes from size and type, not from a second card style: two
   different glass treatments side by side read as two different components. */
.impact-lead { padding: 50px 46px 46px; }
.impact-kicker {
  display: block;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 26px;
}
.impact-lead .impact-fig {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(60px, 9.5vw, 140px);
  line-height: 0.9;
  letter-spacing: -0.05em;
  color: var(--accent);
}
/* the starting point is stated, not shouted — it is the reference, not the news */
.impact-was {
  display: block;
  font-size: 0.16em;
  font-weight: 500;
  letter-spacing: 0.02em;
  margin-bottom: 14px;
}
.impact-lead .impact-lead-note {
  margin-top: 22px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-2);
  max-width: 34ch;
  transition: color 0.35s ease;
}
.impact-lead:hover .impact-lead-note,
.impact-mini:hover .mini-label,
.brief-block.impact-mini:hover .mini-label { color: var(--text); }
.impact-side {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.impact-mini {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 30px;
}
.impact-mini .mini-fig {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(26px, 3.2vw, 40px);
  line-height: 1;
  letter-spacing: -0.03em;
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}
.impact-mini .mini-label {
  margin-top: 12px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-2);
}
.impact-mini .mini-label strong { font-weight: 500; color: var(--text); }
.impact-foot {
  margin-top: 22px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text-3);
  max-width: 78ch;
}
@media (max-width: 900px) {
  .impact-grid { grid-template-columns: 1fr; }
  .impact-lead { padding: 34px 26px 30px; }
  .impact-mini { padding: 24px 22px; }
}

/* ---------- before → after figures ---------- */
.case-metrics { margin: 0 0 56px; }
.metric-row {
  position: relative;
  text-align: center;
  padding: 44px 0;
}
/* Decorative artwork inside a block — game pieces around a figure, a star in
   the margin. Decoration only: never takes the pointer, hidden from screen
   readers, and dropped entirely on narrow screens where space is the content. */
.decor-art {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--s);
  height: auto;
  pointer-events: none;
  transform: rotate(var(--r));
  animation: gem-float 7s var(--ease) var(--dl, 0s) infinite;
  filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.45));
}
@keyframes gem-float {
  0%   { transform: rotate(var(--r)) translateY(0); }
  50%  { transform: rotate(calc(var(--r) + 5deg)) translateY(-11px); }
  100% { transform: rotate(var(--r)) translateY(0); }
}
/* a star does not float, it twinkles */
.decor-art.is-star {
  animation: star-twinkle 6.5s var(--ease) var(--dl, 0s) infinite;
  filter: none;
}
@keyframes star-twinkle {
  0%, 100% { opacity: 0.35; transform: rotate(var(--r)) scale(0.92); }
  50%      { opacity: 0.9;  transform: rotate(calc(var(--r) + 8deg)) scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  .decor-art { animation: none; }
}
/* below the wide breakpoint the layout needs every pixel for the content */
@media (max-width: 720px) {
  .decor-art { display: none; }
}
/* a block that hosts decoration has to be a positioning context */
.case-text { position: relative; }
/* a hairline between rows only — no box, so the numbers carry the section */
.metric-row + .metric-row { border-top: 1px solid rgba(255, 255, 255, 0.08); }
.metric-figure {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(46px, 8vw, 104px);
  line-height: 1;
  letter-spacing: -0.04em;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: clamp(12px, 1.6vw, 26px);
  flex-wrap: wrap;
}
/* the number being left behind: present, but clearly the past tense.
   It recedes a little once the new figure has finished counting. */
.m-from {
  color: var(--text);
  transition: opacity 0.8s var(--ease-glide), transform 0.8s var(--ease-glide);
}
.metric-row.is-counted .m-from { opacity: 0.5; transform: scale(0.94); }
/* Three roles in every figure, and each has exactly one treatment:
     .m-from — the value it started at, full strength
     .m-link — the connecting word, secondary: it is syntax, not data
     .m-to   — the result, in the accent
   The size of the connector is set per context, because it sits inside type
   that ranges from 14px to 140px; the colour never varies. */
.m-link {
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--text-3);
}
.metric-figure .m-link,
.impact-mini .mini-fig .m-link { font-size: 0.42em; }
.m-to {
  color: var(--accent);
  /* The count must not reflow the line, so the box is reserved for the widest
     value it passes through — "~42s" is wider than "~5s". That slack has to
     fall to the right, where the line ends: centred, half of it sat between
     "to" and the number and read as a broken gap. */
  display: inline-block;
  text-align: left;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  transition: text-shadow 0.6s ease;
}
/* a breath of light the moment it lands */
.m-to.is-done { text-shadow: 0 0 34px rgba(197, 255, 61, 0.28); }
.metric-label {
  margin-top: 20px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--text-2);
}
.metric-label strong { font-weight: 500; color: var(--text); }
.metrics-note {
  margin-top: 8px;
  text-align: center;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-3);
}
html.is-phone .metric-row { padding: 30px 0; }
html.is-phone .metric-label { font-size: 14px; margin-top: 14px; }

/* Full width of the page: the figure cancels the column's side padding and
   nothing more. Measuring against the viewport needs the scrollbar width,
   the page centring and the container padding to agree to the pixel — one of
   them being off puts the picture past the right edge, which is what happened.
   Cancelling a padding it can actually see cannot overflow. */
.case-hero.is-bleed {
  width: auto;
  max-width: none;
  margin-left: -2rem;
  margin-right: -2rem;
}
/* the column's padding drops to 1.4rem below 860px — the bleed follows it */
@media (max-width: 860px) {
  .case-hero.is-bleed { margin-left: -1.4rem; margin-right: -1.4rem; }
}

/* a diagram that is square or portrait has no business filling 1200px — the
   block says how wide it may run and the figure centres inside the column */
.case-hero.is-narrow {
  max-width: var(--fig-max, 560px);
  margin-left: auto;
  margin-right: auto;
}

/* ---------- chapter marker ----------
   A hollow number and a hairline above the heading. Chapters used to differ
   only by type size, so at scrolling speed the boundary between them was
   invisible. The number is outlined rather than filled: it marks the place
   without competing with the heading for attention. */
.case-text.is-numbered {
  position: relative;
  /* the rule needs room to read as a boundary rather than as an underline
     attached to the chapter number sitting under it */
  padding-top: 82px;
}
/* The rule is drawn rather than bordered: a hairline that fades out at both
   ends, lit in the accent at its middle, with a soft bloom under the lit part.
   Two background layers, so it stays one element and one paint. */
.case-text.is-numbered::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 9px;
  pointer-events: none;
  background:
    linear-gradient(90deg,
      transparent,
      rgba(255, 255, 255, 0.12) 24%,
      rgba(197, 255, 61, 0.75) 50%,
      rgba(255, 255, 255, 0.12) 76%,
      transparent) top left / 100% 1px no-repeat,
    radial-gradient(70px 9px at 50% 0, rgba(197, 255, 61, 0.3), transparent 72%);
}
/* chapters that open a stretch rather than divide one: the number alone is
   enough of a marker, and a rule there only cuts the page up */
.case-text.is-numbered.is-flush { padding-top: 0; }
.case-text.is-numbered.is-flush::before { content: none; }
.chapter-no {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(30px, 4.2vw, 58px);
  line-height: 0.85;
  letter-spacing: -0.04em;
  margin-bottom: var(--head-gap);
  /* outlined, but no longer hollow: a faint accent wash fills the counter so
     the figure holds together at a glance, and the stroke carries more of the
     accent than before so it survives on a dark page */
  color: transparent;
  -webkit-text-stroke: 1.5px rgba(197, 255, 61, 0.72);
  background-image: linear-gradient(100deg,
    rgba(197, 255, 61, 0.05) 38%,
    rgba(197, 255, 61, 0.30) 50%,
    rgba(197, 255, 61, 0.05) 62%);
  background-size: 300% 100%;
  background-position: 120% 0;
  -webkit-background-clip: text;
  background-clip: text;
}
/* the light drifts across the figure and back — nine seconds each way, so it
   is movement you notice only if you stay on the section */
.case-text.in .chapter-no { animation: chapterDrift 9s ease-in-out infinite; }
@keyframes chapterDrift {
  0%, 100% { background-position: 120% 0; }
  50%      { background-position: -20% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .case-text.in .chapter-no { animation: none; background-position: 50% 0; }
}
html.is-phone .case-text.is-numbered { padding-top: 48px; }
html.is-phone .case-text.is-numbered.is-flush { padding-top: 0; }

/* ---------- caption ----------
   What the picture is, and what to look at in it. Without one the reader has
   to work that out alone, and usually does not bother. */
.fig-cap {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text-3);
  max-width: 88ch;
}
.fig-cap b { color: var(--text-2); font-weight: 500; white-space: nowrap; }
.case-hero.is-bleed .fig-cap { padding: 0 2rem; }
@media (max-width: 860px) {
  .case-hero.is-bleed .fig-cap { padding: 0 1.4rem; }
}

/* ---------- case study body blocks ---------- */
.case-hero.is-in-body { margin: 8px 0 46px; }

.case-text { margin: 0 0 46px; }

.case-text h2,
.case-split-text h2 {
  font-family: var(--font-display);
  font-weight: 500;
  /* the old 34px ceiling was timid on a full-width case study; the display
     face holds a much larger size and wants tighter tracking as it grows */
  font-size: clamp(26px, 3.4vw, 46px);
  line-height: 1.08;
  letter-spacing: -0.025em;
  margin-bottom: 20px;
}
/* One even paragraph, run wide so each passage lands on about three lines.
   This is a longer measure than is ideal for reading — the trade is a
   deliberate one: three tight lines under a large heading read as a caption
   to the work, where a narrow column would read as an article. */
.case-body {
  /* Around 70 characters a line. The container is 1200px wide and this copy is
     16px, so an unconstrained paragraph ran to about 150 — the eye loses the
     start of the next line and the whole passage reads as grey mass. */
  max-width: 72ch;
  font-size: 16px;
  line-height: 1.7;
  color: var(--text-2);
}
.case-body + .case-body,
.case-body + .case-list,
.case-list + .case-body { margin-top: 18px; }
/* the opening sentence, in the display face — the same treatment the brief
   lede already uses, so the role is stated the same way everywhere */
.case-lede { margin-bottom: 28px; max-width: 44ch; }
.case-text.is-centered .case-lede { margin-left: auto; margin-right: auto; }

.case-list { list-style: none; max-width: 72ch; }
/* plain bullets, marker inside the line so a centred list stays centred
   together with its markers instead of hanging them off to the left */
.case-list.is-bullet li {
  list-style: disc inside;
  padding-left: 0;
}
.case-text.is-centered .case-list { margin-left: auto; margin-right: auto; }
.case-list li {
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--text);
}
.case-list li + li { margin-top: 14px; }
/* checklist: the tick is drawn in CSS rather than shipped as an icon, so it
   takes the accent colour and scales with the type it sits beside */
.case-list.is-check li {
  position: relative;
  padding-left: 34px;
}
.case-list.is-check li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 0.52em;
  width: 13px;
  height: 7px;
  border-left: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: translateY(-50%) rotate(-45deg);
}
html.is-phone .case-list li { font-size: 15px; }

/* the closing thought: set apart by a rule rather than by more italics */
.case-note {
  margin-top: 30px;
  padding-left: 22px;
  border-left: 2px solid var(--violet);
  max-width: 64ch;
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-2);
}
.case-text.is-centered .case-note {
  margin-left: auto;
  margin-right: auto;
  text-align: left;
}
html.is-phone .case-note { padding-left: 16px; font-size: 14.5px; }
/* a caption that runs the full measure on one line — the rule is dropped with
   it, because a centred full-width line with a bar on its left reads as a
   quote that lost its opening */
.case-note.is-wide {
  max-width: none;
  border: none;
  padding: 0;
  text-align: center;
  font-size: 14.5px;
}

/* a section set against the right edge. Every constrained element inside it
   is pushed over with `margin-left: auto`, because a max-width block ignores
   text-align — the box itself has to move, not just the lines in it. */
/* copy whose line breaks are set by hand does not want the 72ch cap */
.case-text.is-wide .case-body { max-width: none; }

/* a passage that states a rule rather than telling the story — kept small and
   on a narrower measure so it reads as an aside between two bigger sections */
/* `balance` evens the lines out instead of leaving a long line above a short
   orphan — the measure sets how many lines, the balancing makes them equal */
.case-text.is-small .case-body {
  max-width: 72ch;
  font-size: 14px;
  line-height: 1.65;
}
.case-text.is-small .case-note { font-size: 14px; line-height: 1.65; max-width: 64ch; }
.case-text.is-small .case-list { max-width: 72ch; }
/* centred asides keep the same measure as every other description; only the
   line balancing is theirs, so the last line is not left as a short tail */
.case-text.is-small.is-centered .case-body { text-wrap: balance; }
.case-text.is-small .case-list li { font-size: 14px; line-height: 1.6; }
.case-text.is-small .case-list li + li { margin-top: 8px; }
.case-text.is-small .case-body + .case-list { margin-top: 12px; }

.case-text.is-right { text-align: right; }
.case-text.is-right .case-body,
.case-text.is-right .case-lede,
.case-text.is-right .case-list { margin-left: auto; margin-right: 0; }
.case-text.is-right .case-list li { padding-left: 0; padding-right: 34px; }
.case-text.is-right .case-list.is-check li::before { left: auto; right: 6px; }
/* the rule moves to the side the text now sits against */
.case-text.is-right .case-note {
  margin-left: auto;
  text-align: right;
  border-left: none;
  border-right: 2px solid var(--violet);
  padding-left: 0;
  padding-right: 22px;
}
@media (max-width: 860px) {
  .case-text.is-right { text-align: left; }
  .case-text.is-right .case-body,
  .case-text.is-right .case-lede,
  .case-text.is-right .case-list { margin-left: 0; }
  .case-text.is-right .case-note {
    text-align: left; border-right: none;
    border-left: 2px solid var(--violet);
    padding-right: 0; padding-left: 16px;
  }
}

/* the one idea to carry away, in the accent colour */
.case-body strong {
  font-weight: 400;
  color: var(--accent);
}
/* second half of a two-part heading */
.case-text h2 em,
.case-split-text h2 em {
  font-style: normal;
  color: var(--violet);
}
.case-text h2 .sep,
.case-split-text h2 .sep { color: var(--text-3); }
html.is-phone .case-text { margin-bottom: 32px; }
html.is-phone .case-text h2,
html.is-phone .case-split-text h2 { font-size: clamp(23px, 7.5vw, 32px); }
html.is-phone .case-body { max-width: none; font-size: 15px; line-height: 1.65; }
html.is-phone .case-text.is-centered .case-body { max-width: none; }
html.is-phone .case-hero.is-in-body { margin-bottom: 30px; }

/* ---------- split block ----------
   The artwork here is a single UI element, not a screen, so it sits beside the
   heading at the heading's own height rather than taking half the page. The
   copy then runs the full width beneath both. */
.case-split {
  --split-title: clamp(38px, 6vw, 82px);
  margin: 0 0 52px;
}
.split-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 40px;
  flex-wrap: wrap;
}
.case-split.is-flipped .case-split-text  { order: 2; }
.case-split.is-flipped .case-split-media { order: 1; }

.case-split-media { margin: 0; line-height: 0; flex: none; }
/* matched to the cap height of the display title, not to its line box */
/* One number sets the artwork height, in multiples of the title size. 0.8 is
   the cap height of the heading — right for a bar or a strip sitting on the
   same line. An object like a badge wants more; the block says how much. */
.case-split-media img {
  display: block;
  height: calc(var(--split-title) * var(--media-scale, 0.8));
  width: auto;
  max-width: 100%;
  margin-top: calc(var(--split-title) * 0.06);
}
.case-split .case-body { max-width: none; margin-top: 16px; }


@media (max-width: 860px) {
  .split-head { gap: 22px; }
  .case-split.is-flipped .case-split-text,
  .case-split.is-flipped .case-split-media { order: 0; }
}
html.is-phone .case-split { margin-bottom: 34px; }


/* centred variant of a body passage */
.case-text.is-centered { text-align: center; }
.case-text.is-centered .case-body {
  margin-left: auto;
  margin-right: auto;
  max-width: 92%;
}

/* ---------- lineup: cut-out artwork standing on a pool of light ---------- */
.case-lineup {
  position: relative;
  width: var(--vw, 100vw);
  margin-left: calc(50% - var(--vw, 100vw) / 2);
  margin-bottom: 56px;
  /* room at the foot for the glow, which now hangs below the row instead of
     being clipped by the section edge */
  padding: 10px 0 40px;
  display: flex;
  justify-content: center;
}
/* the wash sits behind everything, spanning the full viewport width */
.lineup-glow {
  position: absolute;
  left: 0;
  right: 0;
  /* its bright centre should land on the shadows, not behind the artwork.
     Squashed vertically to about a third of its natural height so it reads as
     a pool of light on a surface rather than a tall haze behind the cards. */
  bottom: -15px;
  width: 100%;
  height: 34%;
  object-fit: fill;
  pointer-events: none;
  z-index: 0;
  opacity: 0.8;
  mix-blend-mode: screen;
}
.lineup-row {
  position: relative;
  z-index: 1;
  display: grid;
  /* the centre card is wider, so it also stands taller than the two beside it
     while every shadow still rests on the same line */
  grid-template-columns: 1fr 1.34fr 1fr;
  align-items: end;
  gap: clamp(10px, 2.2vw, 34px);
  width: min(100%, var(--max));
  padding: 0 2rem 34px;
}
/* the middle card sits in front where the group is tight, nudged left to
   balance the group optically — the artwork is not centred in its own frame */
.case-lineup:not(.is-even) .lineup-item:nth-child(2) {
  z-index: 2;
  transform: translateX(-10px);
}
.lineup-item {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.lineup-art {
  display: block;
  width: 100%;
  height: auto;
  transform-origin: center bottom;
  /* long and gentle: the card should feel like it is floating, not snapping.
     A very soft curve — most of the travel happens early, then it drifts the
     last few pixels over the remaining time. */
  transition: transform 1.6s cubic-bezier(0.22, 0.9, 0.18, 1);
}
/* the card lifts, its shadow softens and draws in — as if the light source
   stayed put while the card moved away from the surface */
.lineup-item:hover .lineup-art {
  transform: translateY(-16px);
  transition-duration: 1.15s;         /* rises a touch quicker than it settles */
}
.lineup-item:hover .lineup-shadow { opacity: 0.34; }
/* the cast shadow hangs a little below the artwork, not touching it */
.lineup-shadow {
  display: block;
  /* wider than the artwork above it — a low light source spreads the cast
     shadow well past the silhouette. Overflow is fine, the row no longer clips. */
  width: 120%;
  max-width: none;
  height: auto;
  margin-top: 4px;
  opacity: 0.55;
  pointer-events: none;
  transition: opacity 1.6s cubic-bezier(0.22, 0.9, 0.18, 1);
  /* the row sits above the glow already, but the shadow needs to read as
     cast onto the lit surface, so it is lifted onto its own layer */
  position: relative;
  z-index: 3;
}
/* each shadow nudged to sit where the light actually throws it, rather than
   centred under its own frame */
.case-lineup:not(.is-even) .lineup-item:nth-child(1) .lineup-shadow { transform: translateX(-18px); }
.case-lineup:not(.is-even) .lineup-item:nth-child(2) .lineup-shadow { transform: translateX(-33px); }
.case-lineup:not(.is-even) .lineup-item:nth-child(3) .lineup-shadow { transform: translateX(-18px); }

@media (max-width: 640px) {
  .lineup-row { gap: 6px; padding: 0 1rem 24px; }
  .lineup-shadow { margin-top: 0; }
}

/* ---------- plain row of artwork ---------- */
.case-row {
  display: grid;
  grid-template-columns: var(--tracks, repeat(var(--cols, 4), 1fr));
  align-items: end;
  gap: clamp(12px, 2.4vw, 34px);
  margin: 0 0 52px;
}
.case-row + .case-row { margin-top: -34px; }
.case-row.is-middle { align-items: center; }
/* a row of screens that open full-screen — the artwork lifts a touch so it is
   clear the frame is a target, without scaling it enough to soften the UI */
.case-row.is-gallery .row-item > img {
  transform: translateY(0);
  transition: transform 0.6s var(--ease-out), filter 0.6s ease;
}
.case-row.is-gallery .row-item > img:hover {
  transform: translateY(-6px);
  filter: brightness(1.06);
}
.row-item { margin: 0; }
/* Bare artwork in a row: without this the width is capped by max-width while
   the height keeps the value from the height attribute, and the image
   stretches vertically. */
.row-item > img {
  display: block;
  width: 100%;
  height: auto;
}
/* only the card face fills its box — the faction mark on the reverse has its
   own fixed size and must not be caught by this rule */
.row-item .flip-front img {
  display: block;
  width: 100%;
  height: auto;
  transform-origin: center bottom;
  transition: transform 1.6s cubic-bezier(0.22, 0.9, 0.18, 1);
}
.row-item:hover .flip-front img {
  transform: translateY(-12px);
  transition-duration: 1.15s;
}
@media (max-width: 640px) {
  .case-row { grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 34px; }
}

/* ---------- faction stacks under the commander lineup ---------- */
.case-columns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(var(--rows, 4), auto);
  grid-auto-flow: column;      /* fills down one faction before the next */
  /* every card sits on the baseline of its own grid row, so the three stacks
     line up horizontally as well as vertically */
  align-items: end;
  justify-items: center;
  gap: clamp(10px, 1.6vw, 20px) clamp(14px, 3vw, 44px);
  margin: 0 0 52px;
}
/* the hero cards read as a secondary tier, so they sit smaller than the
   column they occupy rather than filling it */
.case-columns .row-item { width: 70%; }
/* per-item size override for artwork that is not a card — the icon sheet is
   square where the cards are tall, so it needs to come down to match */
.case-columns .row-item[style*="--scale"] { width: calc(70% * var(--scale)); }
.cards-gap { display: block; }
@media (max-width: 640px) {
  .case-columns { gap: 10px; margin-bottom: 34px; }
}


/* ---------- cards turn over on click ---------- */
.flip {
  position: relative;
  width: 100%;
  transform-style: preserve-3d;
  transition: transform 0.85s cubic-bezier(0.22, 0.9, 0.18, 1);
  cursor: none;
}
/* No scaling here. Scaling the card scales its copy too, so cards of
   different widths ended up with different type sizes. The reverse instead
   gets a fixed size of its own, identical on every card. */
.flip.is-flipped { z-index: 30; }
.flip.is-flipped, .lineup-item .flip.is-flipped { transform: rotateY(180deg); }
/* The middle commander's column is 1.34x the width of the others, so its
   reverse would come out visibly larger. Scaling by 1.15/1.34 lands it at the
   same size and proportion as the two beside it.
   The card is mirrored at this point, so a positive X moves it left on screen. */
.case-lineup:not(.is-even) .lineup-item:nth-child(2) .flip.is-flipped {
  transform: rotateY(180deg) translateX(-10px);
}
.flip.is-flipped .flip-back { pointer-events: auto; }
.flip-face { backface-visibility: hidden; }
.flip-front img { display: block; width: 100%; height: auto; }
.flip-back {
  position: absolute;
  /* one size for every card, centred on the front it replaces — margins are
     not affected by the rotation, unlike a translate would be */
  width: 300px;
  height: 344px;
  left: 50%;
  top: 50%;
  margin-left: -150px;
  margin-top: -172px;
  transform: rotateY(180deg);
  display: flex;
  flex-direction: column;
  justify-content: space-between;   /* name at the top, faction at the foot */
  align-items: center;
  gap: 8px;
  padding: 26px 22px 20px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background:
    linear-gradient(150deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.02)),
    radial-gradient(120% 90% at 50% 0%, rgba(139, 92, 246, 0.22), transparent 70%),
    rgba(12, 12, 20, 0.94);
  text-align: center;
}
.flip-name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 19px;
  letter-spacing: 0.01em;
  line-height: 1.2;
  color: var(--accent);
}
/* rank as a small outlined tag, sitting on its own between the name and the
   copy rather than tucked under the name */
.flip-rank {
  font-family: var(--font-display);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
  border: 1px solid rgba(139, 92, 246, 0.45);
  border-radius: 999px;
  padding: 3px 9px;
  margin: 2px 0;
}
/* faction mark and label, pinned to the foot */
/* mark stacked above its label, both centred at the foot of the card */
.flip-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  width: 100%;
}
.flip-faction {
  font-family: var(--font-display);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-2);
}
.flip-stats { width: 100%; display: grid; gap: 5px; margin-top: 4px; }
.flip-stats > div {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 11.5px;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.flip-stats dt { color: var(--text-3); }
.flip-stats dd { color: var(--text); font-family: var(--font-display); }
.flip-note {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-2);
  /* narrower than the panel, and vertically centred in the gap between the
     name and the faction foot — nothing else on the card moves */
  max-width: 26ch;
  margin: auto 0;
}
/* the commander cards are wider to begin with, so their copy can be larger */

/* no data yet: a plain deck back rather than invented statistics */
.flip-mark {
  width: 34%;
  aspect-ratio: 1;
  border: 1px solid rgba(197, 255, 61, 0.5);
  border-radius: 50%;
  position: relative;
}
.flip-mark::after {
  content: '';
  position: absolute;
  inset: 26%;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.75;
}

/* the hover lift would fight the turn */
.lineup-item:hover .flip.is-flipped .lineup-art,
.row-item:hover .flip.is-flipped .flip-front img { transform: none; }
/* faction mark on a commander's reverse */
.flip-icon {
  display: block;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
}

/* even lineups — spells and anything else that is not the commander trio */
.case-lineup.is-even .lineup-row {
  grid-template-columns: repeat(var(--cols, 4), 1fr);
}
.case-lineup.is-even .lineup-shadow { transform: translateX(-14px); }
/* second spell reads a shade large */
.case-lineup.is-even .lineup-item:nth-child(2) .lineup-art {
  transform: scale(0.98);
  transform-origin: center bottom;
}
.case-lineup.is-even .lineup-item:nth-child(2):hover .lineup-art {
  transform: translateY(-16px) scale(0.98);
}
/* Four cards make a shorter section than three, so a glow sized as a
   percentage of it landed below the cards' base and left the shadows sitting
   on plain dark ground, where a dark shadow cannot be seen. Raised and
   deepened so the light reaches the shadows again. */
.case-lineup.is-even .lineup-glow {
  height: 48%;
  bottom: 10px;
}
/* Spells have no faction, so nothing is drawn in the foot — but the block
   still holds its height, keeping name and copy in the same place as on a
   Hero card. A rule over an empty area would read as a fault, so it goes. */
.flip-foot.is-empty {
  border-top: 0;
  min-height: 58px;
}
/* a row of five loose icons wants far more air between them than a row of
   screens does, and they should not run the full width of the page */
.case-row[style*="--cols:5"] {
  /* wider than before, so each icon comes up about a third in size, and
     centred both ways in the row. Loose icons need far more air around them
     than a screenshot does — without it they read as a cramped toolbar. */
  margin-top: 18px;
  margin-bottom: 96px;
  max-width: 990px;
  margin-left: auto;
  margin-right: auto;
  gap: clamp(18px, 3.4vw, 44px);
  align-items: center;
  justify-items: center;
}

/* ---------- before / after ---------- */
.case-compare {
  position: relative;
  margin: 0 0 52px;
  overflow: hidden;
  border-radius: 14px;
  line-height: 0;
  cursor: none;
  touch-action: pan-y;          /* vertical scrolling still works on touch */
  user-select: none;
}
.case-compare img {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  -webkit-user-drag: none;
}
/* the graded frame lies underneath; the raw render on top is clipped back */
.cmp-after { position: relative; }
.cmp-before {
  position: absolute;
  inset: 0;
  clip-path: inset(0 calc(100% - var(--split)) 0 0);
}
.cmp-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--split);
  width: 2px;
  margin-left: -1px;
  background: rgba(255, 255, 255, 0.85);
  pointer-events: none;
  box-shadow: 0 0 18px rgba(0, 0, 0, 0.55);
}
.cmp-handle i {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.9);
  background: rgba(10, 10, 16, 0.35);
  -webkit-backdrop-filter: blur(2px);
          backdrop-filter: blur(2px);
}
/* two chevrons, drawn from the borders of a rotated square */
.cmp-handle i::before,
.cmp-handle i::after {
  content: '';
  position: absolute;
  top: 50%;
  width: 8px;
  height: 8px;
  border: 2px solid #fff;
  border-width: 2px 2px 0 0;
}
.cmp-handle i::before { left: 9px;  transform: translateY(-50%) rotate(-135deg); }
.cmp-handle i::after  { right: 9px; transform: translateY(-50%) rotate(45deg); }

.cmp-label {
  position: absolute;
  bottom: 16px;
  z-index: 2;
  padding: 6px 12px;
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  background: rgba(10, 10, 16, 0.6);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  pointer-events: none;
  line-height: 1;
}
.cmp-label-before { left: 16px; }
.cmp-label-after  { right: 16px; }

html.is-phone .case-compare { border-radius: 10px; margin-bottom: 34px; }
html.is-phone .cmp-handle i { width: 36px; height: 36px; }
html.is-phone .cmp-label { bottom: 10px; font-size: 9.5px; padding: 5px 9px; }
html.is-phone .cmp-label-before { left: 10px; }
html.is-phone .cmp-label-after { right: 10px; }

html.is-phone .case-row[style*="--cols:5"] { margin-bottom: 56px; }
/* a one-word heading has no second half to colour, so it can be set violet
   whole where the section calls for it */
.case-text h2.is-violet,
.case-split-text h2.is-violet { color: var(--violet); }

/* ---------- oversized display heading with a subtitle ---------- */
.case-display {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(38px, 6vw, 82px);
  line-height: 0.95;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  margin-bottom: var(--head-gap);
}
/* Each letter is dealt onto the table: it arrives from above, tilted, and
   settles square. Transform and opacity only, so the browser can composite
   the whole thing without touching layout. Applies to every case heading. */
/* keeps a word whole: without it the line can break between any two letters */
.deal-word { display: inline-block; white-space: nowrap; }
.deal-ch {
  display: inline-block;
  opacity: 0;
  transform: translateY(-0.45em) rotate(-14deg) scale(0.86);
  transform-origin: 50% 120%;
  /* 80ms per letter made a long heading run for nearly two seconds — the last
     word was still arriving after the eye had finished reading the first. */
  transition:
    opacity 0.3s ease            calc(var(--i) * 34ms),
    transform 0.5s cubic-bezier(0.18, 0.9, 0.24, 1.12) calc(var(--i) * 34ms);
}
.reveal.in .deal-ch {
  opacity: 1;
  transform: none;
}
.case-subtitle {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(13px, 1.5vw, 18px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
  margin-bottom: 22px;
}
.case-text.has-display .case-body { margin-top: 4px; }
/* a lone violet label introducing the artwork directly beneath it —
   it belongs to what follows, so it sits close to it */
.case-text.is-label { margin-top: -60px; margin-bottom: 18px; }
.case-text.is-label .case-subtitle { margin-bottom: 0; }
/* A heading sits between two things and has to declare which one it owns.
   Without a clear break above it, the eye reads it as a caption for the
   artwork it follows. This gap is the section break. */
.case-text.is-chapter,
.case-split.is-chapter { margin-top: 104px; }
/* nothing to separate from at the very top of the body */
.case-text.is-chapter:first-child,
.case-split.is-chapter:first-child { margin-top: 0; }
html.is-phone .case-text.is-chapter,
html.is-phone .case-split.is-chapter { margin-top: 56px; }

/* ---------- closing block ---------- */
.case-outro {
  margin: 104px 0 130px;
  padding-top: 52px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  text-align: center;
}
.outro-logo {
  display: block;
  height: 62px;
  width: auto;
  margin: 0 auto 30px;
}
.outro-body {
  max-width: 62ch;
  margin: 0 auto;
}
/* the thank-you paragraph carries as much weight as the opening one, so it
   keeps the full text colour rather than the grey used for asides */
.outro-body + .outro-body {
  margin-top: 18px;
  font-size: 16px;
  line-height: 1.7;
  color: var(--text);
}
.mail-copy {
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
  background: none;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 7px 14px 6px;
  cursor: none;
  transition: color 0.3s ease, border-color 0.3s ease;
}
.mail-copy:hover { color: var(--text-1); border-color: rgba(255, 255, 255, 0.34); }
.mail-copy.is-done { color: var(--accent); border-color: var(--accent); }

/* credits: a quiet two-column list, roles on the left of their names, so the
   eye can find a person without reading the whole thing as prose */
.outro-credits { margin-top: 44px; }
.credits-label {
  display: block;
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
  margin-bottom: 18px;
}
.credits-list {
  display: inline-grid;
  grid-template-columns: auto auto;
  gap: 10px 22px;
  margin: 0;
  text-align: left;
}
.credit { display: contents; }
.credit dt {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
  justify-self: end;
  align-self: baseline;
  padding-top: 2px;
}
.credit dd {
  margin: 0;
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-2);
}
@media (max-width: 560px) {
  .credits-list { grid-template-columns: 1fr; gap: 4px; text-align: center; }
  .credit dt { justify-self: center; }
  .credit + .credit dt { margin-top: 14px; }
}

.outro-note {
  margin-top: 26px;
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
}
html.is-phone .case-outro { margin: 56px 0 72px; padding-top: 34px; }
html.is-phone .outro-logo { height: 46px; margin-bottom: 22px; }
html.is-phone .outro-body { font-size: 15px; }
html.is-phone .case-display { font-size: clamp(38px, 13vw, 64px); }
html.is-phone .case-subtitle { font-size: 11.5px; letter-spacing: 0.14em; }
@media (prefers-reduced-motion: reduce) {
  .deal-ch { opacity: 1; transform: none; transition: none; }
}

/* ---------- brand sheet ---------- */
/* the lock-ups need clear air above them — the copy that introduces the mark
   should not sit right on top of it */
.case-brand { margin: 40px 0 56px; }
html.is-phone .case-brand { margin-top: 22px; }
.brand-panels {
  display: grid;
  /* the count is not fixed — flat light, flat dark and the 3D treatment all
     sit in one row, and the layout follows however many are supplied */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: clamp(14px, 2.4vw, 28px);
  margin-bottom: 28px;
}
.brand-panel { margin: 0; }
/* No frame and no plate: each artwork already carries its own background and
   rounded corner, so anything drawn around it would only double up. */
.brand-plate {
  background: var(--bg, transparent);
  display: block;
  line-height: 0;
}
.brand-plate img {
  display: block;
  width: 100%;
  height: auto;
}
.brand-panel figcaption {
  margin-top: 12px;
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
}

.brand-palette-label {
  display: block;
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
  margin-bottom: 14px;
}
/* smaller chips: the palette is a footnote to the mark, not a spec sheet */
.brand-palette { --chip: 96px; text-align: center; }
.swatches {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, var(--chip)));
  gap: clamp(10px, 1.4vw, 18px);
  justify-content: center;
}
.swatch { display: flex; flex-direction: column; gap: 9px; }
.swatch-chip {
  display: block;
  aspect-ratio: 1;
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}
.swatch-role {
  font-size: 10px;
  line-height: 1.35;
  color: var(--text-3);
}
@media (max-width: 860px) {
  .brand-panels { grid-template-columns: 1fr; }
  .swatches { grid-template-columns: repeat(3, minmax(0, var(--chip))); }
}
html.is-phone .brand-palette { --chip: 72px; }
html.is-phone .case-brand { margin-bottom: 34px; }
/* the mark in its finished key-art context, beneath the flat lock-ups */
.brand-feature { margin: 0 0 32px; line-height: 0; }
.brand-feature img { display: block; width: 100%; height: auto; }
.brand-feature figcaption {
  margin-top: 12px;
  font-family: var(--font-display);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* section headings are shorter and smaller — a tighter stagger suits them */
.case-text h2:not(.case-display) .deal-ch,
.case-split-text h2 .deal-ch {
  transition:
    opacity 0.38s ease            calc(var(--i) * 45ms),
    transform 0.6s cubic-bezier(0.18, 0.9, 0.24, 1.1) calc(var(--i) * 45ms);
  transform: translateY(-0.3em) rotate(-10deg) scale(0.9);
}

/* inside a two-column block the heading only has half the width to live in */
.case-split-text .case-display { font-size: clamp(30px, 3.4vw, 48px); }

html.is-phone .case-head h1.case-display { font-size: clamp(34px, 11vw, 56px); }

/* ---------- device frame ----------
   A screen shown as a screen: the bezel is drawn on the figure rather than
   shipped inside the image, so it stays sharp at any width and the artwork
   underneath is still the plain export. */
/* the ratio reservation is dropped for framed figures — with padding on the
   box it would reserve 20px less than the picture needs and the artwork would
   sit past the bezel; the img's own width/height attributes still reserve it */
.case-hero.is-framed {
  border-radius: 26px;
  padding: 10px;
  background:
    linear-gradient(160deg, rgba(255, 255, 255, 0.13), rgba(255, 255, 255, 0.03) 42%, rgba(0, 0, 0, 0.3));
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.16),
    0 2px 1px rgba(255, 255, 255, 0.06) inset,
    0 34px 70px -28px rgba(0, 0, 0, 0.85);
}
.case-hero.is-framed img {
  border-radius: 17px;
  display: block;
  /* the glass edge: a hairline inside the screen, darker than the bezel */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35);
}
.case-hero.is-framed figcaption { padding: 0 6px; }
html.is-phone .case-hero.is-framed {
  border-radius: 18px;
  padding: 7px;
}
html.is-phone .case-hero.is-framed img { border-radius: 12px; }

/* ---------- light band ----------
   Artwork drawn for a light surface needs that surface to come with it. The
   band runs the full width of the viewport — the same negative margins the
   bleed figures use, so it is measured against the column, not against `100vw`
   which would count the scrollbar and overflow to the right. */
.case-hero.is-band {
  width: auto;
  max-width: none;
  margin-left: -2rem;
  margin-right: -2rem;
  padding: clamp(28px, 4vw, 64px) clamp(20px, 4vw, 72px);
  background: var(--band, #d9d9d9);
  /* the same corner the framed HUD above it carries, so the two slabs
     read as one pair rather than two unrelated shapes */
  border-radius: 26px;
}
.case-hero.is-band img {
  max-width: 1400px;
  margin: 0 auto;
}
.case-hero.is-band figcaption { max-width: 1400px; margin-left: auto; margin-right: auto; }
@media (max-width: 860px) {
  .case-hero.is-band { margin-left: -1.4rem; margin-right: -1.4rem; }
}

/* the closing sign-off is set exactly like a section subtitle — the display
   face, uppercase, tracked out and violet — so it reads as a label closing
   the case rather than as one more sentence of body copy */
.outro-body.is-sign {
  margin-top: 30px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(13px, 1.5vw, 18px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
}
.outro-body.is-sign strong { color: inherit; font-weight: inherit; }

/* ---------- contact: the statement ----------
   One centred column on a single panel, exactly as the concept: the glass
   recipe the rest of the site uses, the eyebrow set like a section label,
   the address one size below the heading so it never competes with it. */
.contact-statement {
  max-width: 1040px;
  margin: 0 auto;
  text-align: center;
  padding: clamp(40px, 5vw, 78px) clamp(22px, 4vw, 56px);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 20px;
  background:
    linear-gradient(150deg,
      rgba(255, 255, 255, 0.085) 0%,
      rgba(255, 255, 255, 0.032) 46%,
      rgba(255, 255, 255, 0.050) 100%),
    radial-gradient(120% 90% at 12% 0%,
      rgba(139, 92, 246, 0.18) 0%, rgba(139, 92, 246, 0) 62%);
}
/* the label is set exactly like a case subtitle — the same scale as
   "Level, energy, currency" — rather than like the small grey section counters */
.contact-statement .section-num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(13px, 1.5vw, 18px);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
  margin-bottom: 18px;
}
.contact-statement h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(30px, 5.2vw, 68px);
  letter-spacing: -0.035em;
  line-height: 0.98;
  text-transform: uppercase;
  margin: 0 0 22px;
  text-wrap: balance;
}
.contact-statement h2 em { font-style: normal; color: var(--accent); }
/* the measure is set so the pitch lands on three lines rather than a block */
.contact-statement p {
  font-size: 15px;
  line-height: 1.75;
  color: var(--text-2);
  max-width: 108ch;
  margin: 0 auto;
  text-wrap: balance;
}
.contact-statement strong { font-weight: 500; color: var(--text); }

/* the address as one pill: the whole row is the target, and the copy button
   rides inside it instead of hanging off the end of a line */
.contact-mail.is-pill {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  margin: 40px auto 0;
  padding: 14px 16px 14px 26px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.03);
  transition: border-color 0.4s ease, background 0.4s ease;
}
.contact-mail.is-pill:hover {
  border-color: rgba(197, 255, 61, 0.45);
  background: rgba(197, 255, 61, 0.05);
}
/* a step down from the heading — the address is the destination, not the
   headline, and at display size it fought the title above it */
.contact-mail.is-pill a { font-size: clamp(15px, 1.5vw, 20px); }

/* three outlined circles, evenly spaced under the address */
.socials-row.is-circles {
  justify-content: center;
  gap: 12px;
  margin-top: 34px;
}
.socials-row.is-circles a {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.02);
  transition: color 0.35s ease, border-color 0.35s ease,
              background 0.35s ease, transform 0.5s var(--ease-glide);
}
.socials-row.is-circles a:hover {
  border-color: rgba(197, 255, 61, 0.5);
  background: rgba(197, 255, 61, 0.08);
  transform: translateY(-3px);
}
.socials-row.is-circles a svg { width: 20px; height: 20px; }
.socials-row.is-circles .icon-behance { width: 25px; height: 16px; }
@media (prefers-reduced-motion: reduce) {
  .socials-row.is-circles a:hover { transform: none; }
}
@media (max-width: 860px) {
  .contact-statement { padding: 34px 20px 38px; border-radius: 16px; }
  .contact-statement p { max-width: none; }
}
html.is-phone .contact-mail.is-pill {
  padding: 12px 12px 12px 18px;
  gap: 10px;
}

/* ---------- phone notice ----------
   A full-screen sheet over the site, not a redirect: the page underneath is
   already rendered and scrolls the moment the notice is dismissed. */
html.is-gated body { overflow: hidden; }
.phone-gate {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(8, 8, 10, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  opacity: 0;
  transition: opacity 0.4s ease;
}
.phone-gate.is-in  { opacity: 1; }
.phone-gate.is-out { opacity: 0; }
.phone-gate-card {
  width: 100%;
  max-width: 420px;
  padding: 34px 26px 28px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 20px;
  text-align: center;
  transform: translateY(14px);
  transition: transform 0.55s var(--ease-glide);
  background:
    linear-gradient(150deg,
      rgba(255, 255, 255, 0.085) 0%,
      rgba(255, 255, 255, 0.032) 46%,
      rgba(255, 255, 255, 0.050) 100%),
    radial-gradient(120% 90% at 12% 0%,
      rgba(139, 92, 246, 0.22) 0%, rgba(139, 92, 246, 0) 62%),
    #0e0e12;
}
.phone-gate.is-in .phone-gate-card { transform: translateY(0); }
.phone-gate-art {
  width: 74px;
  height: auto;
  margin: 0 auto 22px;
  display: block;
  color: rgba(197, 255, 61, 0.7);
}
.phone-gate-card h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 21px;
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin-bottom: 12px;
}
.phone-gate-card p {
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--text-2);
}
.phone-gate-mail {
  display: inline-block;
  margin-top: 18px;
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 0.01em;
  color: var(--text);
  border-bottom: 1px solid rgba(197, 255, 61, 0.45);
}
.phone-gate-go {
  display: block;
  width: 100%;
  margin-top: 26px;
  padding: 15px 20px;
  border-radius: 999px;
  border: 1px solid rgba(197, 255, 61, 0.5);
  background: rgba(197, 255, 61, 0.12);
  color: var(--accent);
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.02em;
  cursor: pointer;
}
.phone-gate-go:active { background: rgba(197, 255, 61, 0.2); }
@media (prefers-reduced-motion: reduce) {
  .phone-gate, .phone-gate-card { transition: none; }
  .phone-gate-card { transform: none; }
}

/* ---------- group labels over a row of cards ----------
   `.case-text.is-label` pulls itself up by 60px because it was written for a
   lone violet label sitting flush over artwork — it belongs to the image
   beneath it, so it hugs it. A label that introduces a row of offer cards has
   a paragraph or another card row above it instead, and that negative pull
   drags it into the block above. These restore a real break above the label
   while leaving the 18px below it, so it still reads as belonging to the
   cards it names. */
.case-text + .case-text.is-label  { margin-top: 24px; }
.case-intro + .case-text.is-label { margin-top: 16px; }

html.is-phone .case-text + .case-text.is-label,
html.is-phone .case-intro + .case-text.is-label { margin-top: 12px; }

/* ================================================================
   CALLS TO ACTION
   The page used to offer nothing to press above the footer: a reader
   convinced at the hero, or at the prices, had to scroll to the end to
   act. These are the three moments where intent peaks — the hero, the
   Signal Session, and the line under the price cards.
   One filled button per row and everything else outlined, so the page
   never presents two equal choices.
   ================================================================ */
.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 28px;
}
.case-text.is-centered .cta-row { justify-content: center; }
.cta-row.hero-cta { margin-top: 30px; }

.cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 26px;
  border-radius: 10px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: none;                      /* the site runs its own cursor */
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease,
              transform 0.25s var(--ease-out), box-shadow 0.3s ease;
}

/* the one thing we want pressed */
.cta.is-primary {
  background: var(--accent);
  color: #07070b;
  border: 1px solid var(--accent);
}
.cta.is-primary:hover,
.cta.is-primary:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 12px 34px var(--accent-glow);
}

/* the escape hatch for someone not ready to book */
.cta.is-ghost {
  background: transparent;
  color: var(--text-2);
  border: 1px solid rgba(255, 255, 255, 0.16);
}
.cta.is-ghost:hover,
.cta.is-ghost:focus-visible {
  color: var(--text);
  border-color: rgba(255, 255, 255, 0.36);
  transform: translateY(-2px);
}

.cta-arrow { transition: transform 0.25s var(--ease-out); }
.cta.is-primary:hover .cta-arrow { transform: translateX(4px); }

.cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* on a phone the labels are long enough to wrap awkwardly side by side */
html.is-phone .cta-row { gap: 10px; }
html.is-phone .cta {
  width: 100%;
  justify-content: center;
  white-space: normal;
  text-align: center;
  padding: 15px 18px;
}

@media (prefers-reduced-motion: reduce) {
  .cta, .cta-arrow { transition: none; }
  .cta:hover, .cta:focus-visible { transform: none; }
}

/* ---------- the persistent header CTA ----------
   The one action that has to stay reachable wherever the reader stops. It
   sits at the far right of the header controls, after the language pill, and
   takes the pill shape from `.lang-btn` so the two read as one cluster rather
   than as a button glued next to a toggle. Smaller than a body CTA on
   purpose: it is chrome, not a section's own ask. */
.header-controls {
  display: flex;
  align-items: center;
  gap: 12px;
}
.header-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  background: var(--accent);
  color: #07070b;
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: none;
  transition: transform 0.25s var(--ease-out), box-shadow 0.3s ease, background 0.3s ease;
}
.header-cta:hover,
.header-cta:focus-visible {
  transform: translateY(-1px);
  box-shadow: 0 8px 24px var(--accent-glow);
}
.header-cta:hover .cta-arrow { transform: translateX(3px); }
.header-cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.header-cta .cta-arrow { font-size: 12px; }

/* one label at a time: the full name on a desktop, a short one where the
   header also has to carry the nav */
.header-cta-short { display: none; }
@media (max-width: 860px) {
  .header-cta-full  { display: none; }
  .header-cta-short { display: inline; }
  .header-cta { padding: 9px 14px; font-size: 10px; letter-spacing: 0.1em; gap: 6px; }
  .header-cta .cta-arrow { display: none; }
  .header-controls { gap: 8px; }
}
html.is-phone .header-cta-full  { display: none; }
html.is-phone .header-cta-short { display: inline; }
html.is-phone .header-cta {
  padding: 9px 14px;
  font-size: 10px;
  letter-spacing: 0.1em;
  gap: 6px;
}
html.is-phone .header-cta .cta-arrow { display: none; }

@media (prefers-reduced-motion: reduce) {
  .header-cta { transition: none; }
  .header-cta:hover, .header-cta:focus-visible { transform: none; }
}

/* ---------- a live page used as a card preview ---------- */
.work-card-live {
  position: absolute; inset: 0; width: 100%; height: 100%;
  border: 0; display: block; z-index: 0; background: transparent;
  pointer-events: none;   /* the card is the link; the frame must not eat clicks */
}
@media (prefers-reduced-motion: reduce) { .work-card-live { display: none; } }

/* a prototype hosted in the site: taller than a video, dark surface of its own */
.case-embed { background: #0b0607; }
.case-embed iframe { min-height: 520px; }
@media (max-width: 860px) {
  .case-embed { --embed-ratio: 3 / 4; }
  .case-embed iframe { min-height: 620px; }
}
