/* ==========================================================================
   Johvany C. Delarosa — one-page portfolio
   Direction: dark luxe / editorial restraint.
   Signature: "The Operation" — the real 11-channel funnel board.
   ========================================================================== */

/* ---------- Fonts (self-hosted, zero third-party requests) ---------- */
@font-face {
  font-family: 'Fraunces';
  src: url('../fonts/fraunces.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist';
  src: url('../fonts/geist.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist Mono';
  src: url('../fonts/geistmono.woff2') format('woff2');
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}

/* ---------- Metric-matched fallbacks ----------
   `font-display: swap` shows a system font first, then swaps — and if that
   font takes different space, every line re-flows and the page jumps. These
   three faces re-scale the local fallback so it occupies almost exactly the
   same space as the real one, so the swap is a change of shape, not layout.

   Ratios measured in-browser against the real files (100px sample):
     Fraunces  3301 wide / Georgia  3665 = 0.9007   asc .98 desc .26
     Geist     3644 wide / Arial    3646 = 0.9996   asc 1.01 desc .30
     GeistMono 3840 wide / Consolas 3519 = 1.0913   asc 1.01 desc .30
   Overrides are divided by size-adjust, since they apply to the scaled em. */
@font-face {
  font-family: 'Fraunces fallback';
  src: local('Georgia'), local('Times New Roman'), local('Times');
  size-adjust: 90.07%;
  ascent-override: 108.8%;
  descent-override: 28.87%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Geist fallback';
  src: local('Arial'), local('Helvetica Neue'), local('Helvetica'), local('Roboto');
  size-adjust: 99.96%;
  ascent-override: 101.04%;
  descent-override: 30.01%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Geist Mono fallback';
  src: local('Consolas'), local('SF Mono'), local('Menlo'), local('DejaVu Sans Mono');
  size-adjust: 109.13%;
  ascent-override: 92.55%;
  descent-override: 27.49%;
  line-gap-override: 0%;
}

/* ---------- Tokens ---------- */
:root {
  /* Dark is the default theme; light is opt-in via [data-theme='light']. */
  color-scheme: dark;

  /* Surfaces: near-black, warmed very slightly so it doesn't read as pure #000 */
  --ink-900: #0b0b0c;
  --ink-850: #101012;
  --ink-800: #141417;
  --ink-700: #1b1b1f;
  --ink-600: #232328;

  --line:        #2a2a30;
  --line-soft:   #202024;

  /* Warm off-white — limestone, not paper-white */
  --bone:        #ede8df;
  --bone-dim:    #a8a49c;
  --bone-faint:  #6f6c66;

  --champagne:      #c9a961;
  --champagne-lift: #e0c485;
  --champagne-dim:  #7d6a3e;

  /* Semantic tokens. Everything that used to be a hard-coded colour lives
     here, so a theme is a matter of re-declaring this list rather than
     hunting through rules. */
  --star:        #c9a961;   /* review stars */
  --ok:          #6fcf7f;   /* available dot, form success */
  --err:         #d4756b;   /* field errors */
  --glow:        rgba(201, 169, 97, 0.14);   /* hero halo */
  --accent-soft: rgba(201, 169, 97, 0.09);   /* featured surfaces */
  --accent-softer: rgba(201, 169, 97, 0.03);
  --accent-tint: rgba(201, 169, 97, 0.12);   /* chips, table header */
  --overlay:     rgba(11, 11, 12, 0.82);     /* labels over imagery */
  --bar-bg:      rgba(16, 16, 18, 0.92);     /* sticky bar, blurred */
  --backdrop:    rgba(0, 0, 0, 0.8);         /* lightbox */
  --shadow-lg:   0 10px 30px rgba(0, 0, 0, 0.45);
  --vignette-a:  rgba(11, 11, 12, 0.42);
  --vignette-b:  rgba(11, 11, 12, 0.5);
  --grain:       0.035;     /* noise opacity over large flat fields */
  --ghost:       0.035;     /* the big numeral behind each process step */
  --pulse:       rgba(111, 207, 127, 0.55);

  --font-display: 'Fraunces', 'Fraunces fallback', Georgia, 'Times New Roman', serif;
  --font-body: 'Geist', 'Geist fallback', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'Geist Mono', 'Geist Mono fallback', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  /* ---------- Type scale ----------
     One fluid ramp, roughly a major-third at the small end opening to a
     larger interval on wide screens. Each step carries its own line-height
     and tracking, because a size alone is not a typographic decision:
     large display text needs tighter leading and negative tracking, small
     mono labels need the opposite. --t-hero/--t-h2 are kept as aliases so
     existing rules keep working. */
  --t-h1:    clamp(2.75rem, 1.4rem + 5.6vw, 6rem);
  --t-h2:    clamp(2rem, 1.2rem + 3vw, 3.4rem);
  --t-h3:    clamp(1.25rem, 1.05rem + 0.7vw, 1.6rem);
  --t-h4:    clamp(1.05rem, 0.98rem + 0.35vw, 1.25rem);
  --t-lead:  clamp(1.05rem, 0.98rem + 0.4vw, 1.3rem);
  --t-body:  clamp(0.98rem, 0.94rem + 0.16vw, 1.06rem);
  --t-small: 0.875rem;
  --t-micro: 0.75rem;
  --t-hero:  var(--t-h1);

  /* Leading and tracking, paired to the steps above */
  --lh-display: 1.02;
  --lh-h3:      1.15;
  --lh-body:    1.65;
  --lh-tight:   1.35;
  --track-display: -0.015em;
  --track-h3:      -0.005em;
  --track-mono:    0.1em;

  --shell: 1220px;
  --gutter: clamp(1.25rem, 0.6rem + 3vw, 3.5rem);
  --section-y: clamp(4.5rem, 3rem + 7vw, 9rem);

  --radius: 4px;
  --radius-lg: 8px;

  --ease: cubic-bezier(0.2, 0.6, 0.25, 1);
  /* Decisive start, long settle — the curve that makes motion feel expensive
     rather than bouncy. Used for every entrance. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 240ms;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--ink-900);
  color: var(--bone);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.65;
  font-weight: 350;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, svg, video, iframe { display: block; max-width: 100%; }
/* Sprite holder for the brand mark. Taken out of flow rather than display:none,
   which keeps <use> references resolving everywhere. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
button, input, select, textarea { font: inherit; color: inherit; }
h1, h2, h3, h4, p, figure, blockquote, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }

/* Grain — kills banding on large near-black fields. Pure CSS, no asset. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: var(--grain);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- Shared primitives ---------- */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -100%;
  z-index: 200;
  background: var(--champagne);
  color: var(--ink-900);
  padding: 0.7rem 1.1rem;
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--t-small);
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: 1rem; }

:focus-visible {
  outline: 2px solid var(--champagne);
  outline-offset: 3px;
  border-radius: 2px;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--champagne);
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.eyebrow::before {
  content: '';
  width: 1.75rem;
  height: 1px;
  background: var(--champagne-dim);
  flex: none;
}

.display {
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  text-wrap: balance;
}
.display em {
  font-style: italic;
  color: var(--champagne);
  font-weight: 300;
}

.lead {
  font-size: var(--t-lead);
  color: var(--bone-dim);
  line-height: 1.6;
  max-width: 46ch;
  text-wrap: pretty;
}
/* Section sub-headings share one setting instead of repeating it per block. */
.ops__head h2,
.case__client h3,
.cs-prose h2 { line-height: var(--lh-h3); letter-spacing: var(--track-h3); }

.section { padding-block: var(--section-y); position: relative; }
.section--rule { border-top: 1px solid var(--line-soft); }

.section-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
.section-head__title { display: grid; gap: 1.1rem; }
.section-head h2 { font-size: var(--t-h2); }
@media (min-width: 900px) {
  .section-head { grid-template-columns: 1.05fr 0.95fr; align-items: end; }
}

/* ---------- Buttons ---------- */
.btn {
  --btn-bg: var(--champagne);
  --btn-fg: var(--ink-900);
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1.4rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bg);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--t-small);
  font-weight: 500;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.btn:hover { background: var(--champagne-lift); border-color: var(--champagne-lift); transform: translateY(-1px); }
.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--bone);
  border-color: var(--line);
}
.btn--ghost:hover {
  background: var(--ink-700);
  border-color: var(--champagne-dim);
  color: var(--bone);
}
.btn--sm { padding: 0.6rem 1rem; font-size: var(--t-micro); }

/* Text link with a sweeping rule */
.tlink {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-mono);
  font-size: var(--t-small);
  color: var(--bone);
  padding-bottom: 2px;
  background-image: linear-gradient(var(--champagne), var(--champagne));
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--dur) var(--ease), color var(--dur) var(--ease);
}
.tlink:hover { background-size: 100% 1px; color: var(--champagne); }

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in srgb, var(--ink-900) 82%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.site-header[data-stuck='true'] {
  border-bottom-color: var(--line-soft);
  background: color-mix(in srgb, var(--ink-900) 94%, transparent);
}
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 4.5rem;
}
/* The JD ligature, referenced from the inline sprite. The mark itself takes
   currentColor, so each placement only has to set a colour. */
.brandmark {
  display: block;
  height: 1.7rem;
  width: auto;
  color: inherit;
}
.brandmark__point { fill: var(--champagne); }

.wordmark {
  display: inline-flex;
  align-items: center;
  color: var(--bone);
  transition: color var(--dur) var(--ease);
}
.wordmark:hover { color: var(--champagne-lift); }

.nav__links { display: none; gap: 1.75rem; }
@media (min-width: 940px) { .nav__links { display: flex; } }
.nav__link {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone-dim);
  padding-block: 0.35rem;
  position: relative;
  transition: color var(--dur) var(--ease);
}
.nav__link::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 0; height: 1px;
  background: var(--champagne);
  transition: width var(--dur) var(--ease);
}
.nav__link:hover { color: var(--bone); }
.nav__link:hover::after,
.nav__link[aria-current='true']::after { width: 100%; }
.nav__link[aria-current='true'] { color: var(--champagne); }

.nav__cta { display: none; }
@media (min-width: 940px) { .nav__cta { display: inline-flex; } }

.nav__toggle {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0 0.6rem;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
}
@media (min-width: 940px) { .nav__toggle { display: none; } }
.nav__toggle span {
  height: 1px;
  background: var(--bone);
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.nav__toggle[aria-expanded='true'] span:first-child { transform: translateY(3px) rotate(45deg); }
.nav__toggle[aria-expanded='true'] span:last-child { transform: translateY(-3px) rotate(-45deg); }

.mobile-nav {
  display: grid;
  overflow: hidden;
  max-height: 0;
  border-top: 1px solid transparent;
  transition: max-height 320ms var(--ease), border-color var(--dur) var(--ease);
}
.mobile-nav[data-open='true'] { max-height: 34rem; border-top-color: var(--line-soft); }
.mobile-nav a {
  padding: 1rem var(--gutter);
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: var(--t-small);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  color: var(--bone-dim);
}
.mobile-nav a:last-child { color: var(--champagne); border-bottom: none; }

/* ---------- Hero ---------- */
.hero { position: relative; padding-block: clamp(3rem, 2rem + 6vw, 6.5rem) var(--section-y); overflow: hidden; }
.hero__glow {
  position: absolute;
  width: min(46rem, 115vw); height: min(46rem, 115vw);
  top: -18rem; right: -14rem;
  background: radial-gradient(circle, var(--glow), transparent 62%);
  pointer-events: none;
  filter: blur(10px);
  /* Drifts a little with the pointer — parallax depth, not decoration.
     Values are set from JS and clamped to a few dozen pixels. */
  transform: translate3d(var(--gx, 0px), var(--gy, 0px), 0);
  transition: transform 900ms cubic-bezier(0.16, 1, 0.3, 1);
}
.hero__grid { display: grid; gap: clamp(2.5rem, 6vw, 4.5rem); position: relative; }
@media (min-width: 960px) {
  .hero__grid { grid-template-columns: 1.15fr 0.85fr; align-items: center; }
}

.hero__status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.25rem;
  padding-bottom: 1.5rem;
  margin-bottom: 2rem;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.hero__status strong { color: var(--bone-dim); font-weight: 400; }
.dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 0 var(--pulse);
  animation: pulse 2.6s infinite;
  flex: none;
}
@keyframes pulse {
  70%  { box-shadow: 0 0 0 8px rgba(111, 207, 127, 0); }
  100% { box-shadow: 0 0 0 0 rgba(111, 207, 127, 0); }
}
.hero__status .sep { color: var(--line); }

.hero h1 { font-size: var(--t-hero); margin-bottom: 1.6rem; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; align-items: center; margin-top: 2.25rem; }

.hero__meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1.5rem;
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line-soft);
}
.hero__meta div { display: grid; gap: 0.3rem; }
.hero__meta strong {
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 400;
  color: var(--bone);
  line-height: 1;
}
.hero__meta span {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  color: var(--bone-faint);
  text-transform: uppercase;
  line-height: 1.5;
}

/* Portrait */
.portrait { position: relative; }
.portrait__frame {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--ink-800);
}
.portrait__frame img {
  width: 100%; height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center 18%;
  /* Studio backdrop is light grey; ease it toward the dark page. */
  filter: saturate(0.94) contrast(1.03) brightness(0.97);
}
/* Vignette marries the photo to the near-black canvas instead of
   leaving it floating as a pale rectangle. */
.portrait__frame::after {
  content: '';
  position: absolute;
  inset: 0;
  bottom: 3.9rem;
  pointer-events: none;
  background:
    radial-gradient(120% 85% at 50% 35%, transparent 42%, var(--vignette-a) 100%),
    linear-gradient(180deg, transparent 62%, var(--vignette-b) 100%);
}
.portrait__plate {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.15rem;
  border-top: 1px solid var(--line);
  background: var(--ink-850);
}
.portrait__plate div { display: grid; gap: 0.15rem; }
.portrait__plate span {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.portrait__plate strong { font-family: var(--font-display); font-weight: 400; font-size: 1.05rem; }
.portrait__mono {
  height: 1.6rem;
  color: var(--champagne);
  opacity: 0.75;
  flex: none;
}

/* ==========================================================================
   SIGNATURE — "The Operation" funnel board
   Real content: the 11 channels x 4 funnel stages built for HPRED.
   Stage weight is encoded in champagne intensity, so the visual gradient
   itself reads as movement toward revenue.
   ========================================================================== */
.ops { border-top: 1px solid var(--line-soft); background: var(--ink-850); }
.ops__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-bottom: 2.5rem;
}
.ops__head h2 { font-size: var(--t-h3); font-family: var(--font-display); font-weight: 400; }
.ops__count {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--bone-faint);
}

.ops__board {
  display: grid;
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
@media (min-width: 700px)  { .ops__board { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .ops__board { grid-template-columns: repeat(4, 1fr); } }

.stage { background: var(--ink-900); padding: 1.5rem 1.35rem 1.75rem; display: grid; align-content: start; gap: 1.1rem; }
.stage__label {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--bone-dim);
}
/* Intensity ramp: awareness -> retention */
.stage__meter { height: 2px; background: var(--ink-600); overflow: hidden; }
.stage__meter i { display: block; height: 100%; background: var(--champagne); width: 0; transition: width 900ms var(--ease); }
.stage[data-fill='1'] .stage__meter i { background: color-mix(in srgb, var(--champagne) 35%, var(--ink-600)); }
.stage[data-fill='2'] .stage__meter i { background: color-mix(in srgb, var(--champagne) 60%, var(--ink-600)); }
.stage[data-fill='3'] .stage__meter i { background: color-mix(in srgb, var(--champagne) 82%, var(--ink-600)); }
.stage[data-fill='4'] .stage__meter i { background: var(--champagne); }
.ops__board.is-live .stage[data-fill='1'] .stage__meter i { width: 25%; }
.ops__board.is-live .stage[data-fill='2'] .stage__meter i { width: 50%; }
.ops__board.is-live .stage[data-fill='3'] .stage__meter i { width: 75%; }
.ops__board.is-live .stage[data-fill='4'] .stage__meter i { width: 100%; }

.stage__list { display: grid; gap: 0; }
.stage__list li {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding-block: 0.6rem;
  border-top: 1px solid var(--line-soft);
  font-size: var(--t-small);
  color: var(--bone-dim);
  line-height: 1.4;
}
.stage__list li::before {
  content: '';
  width: 4px; height: 4px;
  flex: none;
  border-radius: 50%;
  background: var(--champagne-dim);
  transform: translateY(-2px);
}
.ops__note {
  margin-top: 1.75rem;
  font-size: var(--t-small);
  color: var(--bone-faint);
  max-width: 62ch;
}
.ops__note b { color: var(--bone-dim); font-weight: 500; }

/* ---------- Proof ---------- */
.proof__grid { display: grid; gap: clamp(2rem, 5vw, 3.5rem); }
@media (min-width: 900px) { .proof__grid { grid-template-columns: 1.3fr 0.7fr; align-items: start; } }

.quote {
  border-left: 2px solid var(--champagne);
  padding-left: clamp(1.25rem, 3vw, 2.25rem);
}
.quote blockquote {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 1rem + 1.6vw, 2.05rem);
  font-weight: 300;
  line-height: 1.35;
  letter-spacing: -0.01em;
  text-wrap: pretty;
  color: var(--bone);
}
.quote figcaption {
  margin-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.stars { color: var(--star); letter-spacing: 0.1em; }
.chip {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
  color: var(--bone-dim);
}

.proof__stats { display: grid; gap: 0; }
@media (min-width: 900px) {
  /* The history column is much taller than this rail, so the figures and the
     profile link travel with it instead of scrolling away at the top. */
  .proof__grid > div:last-child { position: sticky; top: 6rem; }
}
.proof__stats div {
  display: grid;
  gap: 0.3rem;
  padding-block: 1.15rem;
  border-top: 1px solid var(--line-soft);
}
.proof__stats div:last-child { border-bottom: 1px solid var(--line-soft); }
.proof__stats strong {
  font-family: var(--font-display);
  font-size: 1.75rem;
  font-weight: 400;
  line-height: 1;
}
.proof__stats span {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--bone-faint);
}

/* ---------- Case studies ---------- */
.case {
  background: var(--ink-900);
  padding: clamp(1.75rem, 4vw, 2.75rem) 0;
  display: grid;
  gap: 1.5rem;
  transition: background var(--dur) var(--ease);
}
.case__inner { display: grid; gap: clamp(1.25rem, 3vw, 2.5rem); }
@media (min-width: 900px) {
  /* Three columns, two rows: the case link sits under the result rather than
     being pushed to the bottom left on a row of its own, which left a hole in
     the middle of the frame. */
  .case__inner {
    grid-template-columns: 0.9fr 1.4fr 0.9fr;
    grid-template-rows: auto 1fr;
    align-items: start;
  }
  .case__client { grid-column: 1; grid-row: 1 / span 2; }
  .case__body   { grid-column: 2; grid-row: 1 / span 2; }
  .case__result { grid-column: 3; grid-row: 1; }
  .case__page   { grid-column: 3; grid-row: 2; align-self: start; margin-top: 1.25rem; }
}
.case__client { display: grid; gap: 0.5rem; align-content: start; }
.case__client h3 { font-family: var(--font-display); font-weight: 400; font-size: var(--t-h3); }
.case__client span {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--champagne);
}
.case__body { display: grid; gap: 1rem; }
.case__body p { color: var(--bone-dim); max-width: 60ch; }
.case__tags { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.case__tags i {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.05em;
  color: var(--bone-faint);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  padding: 0.25rem 0.55rem;
}
.case__result { display: grid; gap: 0.4rem; align-content: start; }
.case__result dt {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.case__result dd {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 400;
  line-height: 1.2;
  color: var(--champagne);
}
.case__result small { display: block; font-family: var(--font-body); font-size: var(--t-small); color: var(--bone-faint); }

/* ---------- Work / filters ---------- */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 2.25rem;
  padding-bottom: 2.25rem;
  border-bottom: 1px solid var(--line-soft);
}
.filter {
  background: none;
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  padding: 0.45rem 0.95rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.05em;
  color: var(--bone-dim);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.filter:hover { border-color: var(--champagne-dim); color: var(--bone); }
.filter[aria-pressed='true'] {
  background: var(--champagne);
  border-color: var(--champagne);
  color: var(--ink-900);
  font-weight: 500;
}
.filter span { opacity: 0.55; margin-left: 0.35rem; }

.work-grid {
  display: grid;
  gap: clamp(1rem, 2.2vw, 1.6rem);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17.5rem), 1fr));
}

.card {
  display: grid;
  grid-template-rows: auto 1fr;
  text-align: left;
  background: var(--ink-800);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.card:hover { border-color: var(--champagne-dim); transform: translateY(-3px); }
.card__media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--ink-700); }
/* Both layers are positioned so DOM order decides paint order: the real
   image is second in the markup and therefore sits above the placeholder. */
.card__media img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Social graphics are square and put their headline at the top, so a
     centre crop decapitates them. Anchor to the top instead. */
  object-position: center top;
  transition: transform 600ms var(--ease), opacity var(--dur) var(--ease);
}
.card:hover .card__media img { transform: scale(1.04); }
/* blur-up: the LQIP shows until the real file has decoded */
.card__media img[data-loaded='false'] { opacity: 0; }
.card__lqip {
  filter: blur(14px) saturate(1.1);
  transform: scale(1.08);
}
.card:hover .card__lqip { transform: scale(1.08); }
.card__type {
  position: absolute;
  left: 0.7rem; top: 0.7rem;
  background: color-mix(in srgb, var(--ink-900) 84%, transparent);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.25rem 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--bone-dim);
}
.card__play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--ink-900) 30%, transparent);
}
.card__play i {
  width: 3.25rem; height: 3.25rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--ink-900) 70%, transparent);
  border: 1px solid var(--champagne);
  display: grid; place-items: center;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.card__play i::after {
  content: '';
  border-left: 11px solid var(--champagne);
  border-block: 7px solid transparent;
  margin-left: 3px;
}
.card:hover .card__play i { background: var(--champagne); transform: scale(1.06); }
.card:hover .card__play i::after { border-left-color: var(--ink-900); }

.card__body { display: grid; gap: 0.6rem; padding: 1.1rem 1.15rem 1.35rem; align-content: start; }
.card__cat {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--champagne);
}
.card__title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.08rem;
  line-height: 1.25;
  color: var(--bone);
}
.card__title span { color: var(--bone-faint); transition: color var(--dur) var(--ease), transform var(--dur) var(--ease); }
.card:hover .card__title span { color: var(--champagne); transform: translate(2px, -2px); }
.card__desc {
  font-size: var(--t-small);
  color: var(--bone-faint);
  line-height: 1.55;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Concept label: states plainly that a piece is spec work rather than
   leaving a prospect to wonder which items were real engagements. */
.chip-concept {
  font-style: normal;
  margin-left: 0.5rem;
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  color: var(--bone-faint);
  text-transform: uppercase;
}
.filter--client { margin-left: auto; border-color: var(--champagne-dim); color: var(--champagne); }
.filter--client[aria-pressed='true'] { background: var(--champagne); color: var(--ink-900); }

.card__slides {
  position: absolute;
  right: 0.7rem; top: 0.7rem;
  background: color-mix(in srgb, var(--ink-900) 84%, transparent);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.25rem 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--bone-dim);
}

/* Carousel controls inside the lightbox */
.lightbox__carousel { position: relative; }
.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 2.6rem; height: 2.6rem;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: color-mix(in srgb, var(--ink-900) 78%, transparent);
  backdrop-filter: blur(6px);
  color: var(--bone);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.lb-nav:hover { border-color: var(--champagne); color: var(--champagne); }
.lb-prev { left: 0.6rem; }
.lb-next { right: 0.6rem; }
.lb-count {
  position: absolute;
  left: 50%; bottom: 0.7rem;
  transform: translateX(-50%);
  background: color-mix(in srgb, var(--ink-900) 84%, transparent);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.2rem 0.7rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--bone-dim);
}

.work-more { display: grid; place-items: center; margin-top: 2.5rem; gap: 0.75rem; }
.work-count { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--bone-faint); letter-spacing: 0.08em; }
.work-empty { padding: 3rem 0; text-align: center; color: var(--bone-faint); font-family: var(--font-mono); font-size: var(--t-small); }

/* ---------- Reports (YouTube facades) ---------- */
.reports__grid {
  display: grid;
  gap: clamp(1rem, 2.2vw, 1.5rem);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
}
.report {
  display: grid;
  gap: 0;
  background: var(--ink-800);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.report:hover { border-color: var(--champagne-dim); transform: translateY(-3px); }
.report__media { position: relative; aspect-ratio: 16 / 9; background: var(--ink-700); }
.report__media img { width: 100%; height: 100%; object-fit: cover; }
.report__len {
  position: absolute;
  right: 0.6rem; bottom: 0.6rem;
  background: color-mix(in srgb, var(--ink-900) 86%, transparent);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.2rem 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: var(--bone-dim);
}
.report__body { padding: 1rem 1.1rem 1.25rem; display: grid; gap: 0.4rem; }
.report__body h3 { font-family: var(--font-body); font-weight: 450; font-size: var(--t-small); line-height: 1.45; color: var(--bone); }
.report__body span { font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bone-faint); }
.report iframe { width: 100%; height: 100%; border: 0; position: absolute; inset: 0; }

/* ---------- Services ---------- */
.svc-grid { display: grid; gap: 1px; background: var(--line-soft); border: 1px solid var(--line-soft); border-radius: var(--radius-lg); overflow: hidden; }
@media (min-width: 640px)  { .svc-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .svc-grid { grid-template-columns: repeat(4, 1fr); } }
.svc {
  background: var(--ink-900);
  padding: 1.6rem 1.4rem 1.8rem;
  display: grid;
  gap: 0.7rem;
  align-content: start;
  transition: background var(--dur) var(--ease);
}
.svc:hover { background: var(--ink-800); }
.svc h3 { font-family: var(--font-display); font-weight: 400; font-size: 1.15rem; }
.svc p { font-size: var(--t-small); color: var(--bone-faint); line-height: 1.55; }
.svc__mark { width: 1.4rem; height: 1px; background: var(--champagne); }

/* ---------- Process ---------- */
.steps { display: grid; gap: 1px; background: var(--line-soft); border-block: 1px solid var(--line-soft); }
@media (min-width: 780px) { .steps { grid-template-columns: repeat(4, 1fr); } }
.step { background: var(--ink-900); padding: 1.75rem 1.4rem 2rem; display: grid; gap: 0.65rem; align-content: start; }
.step__n {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  color: var(--champagne);
}
.step h3 { font-family: var(--font-display); font-weight: 400; font-size: 1.2rem; }
.step p { font-size: var(--t-small); color: var(--bone-faint); line-height: 1.55; }

/* ---------- FAQ ---------- */
.faq { display: grid; border-top: 1px solid var(--line-soft); }
.faq details { border-bottom: 1px solid var(--line-soft); }
.faq summary {
  list-style: none;
  cursor: pointer;
  padding-block: 1.35rem;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.05rem, 0.98rem + 0.4vw, 1.25rem);
  color: var(--bone);
  transition: color var(--dur) var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--champagne); }
.faq summary::after {
  content: '+';
  font-family: var(--font-mono);
  color: var(--champagne);
  flex: none;
  transition: transform var(--dur) var(--ease);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq p { padding-bottom: 1.5rem; color: var(--bone-dim); max-width: 68ch; }

/* ---------- Contact ---------- */
.contact__grid { display: grid; gap: clamp(2.5rem, 6vw, 4.5rem); }
@media (min-width: 940px) { .contact__grid { grid-template-columns: 0.85fr 1.15fr; } }

.contact__meta { display: grid; gap: 0; margin-top: 2.5rem; }
.contact__meta div { display: grid; gap: 0.25rem; padding-block: 1.1rem; border-top: 1px solid var(--line-soft); }
.contact__meta div:last-child { border-bottom: 1px solid var(--line-soft); }
.contact__meta dt, .contact__meta span {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.contact__meta dd, .contact__meta strong { margin: 0; font-weight: 400; color: var(--bone); }
.contact__meta a { color: var(--bone); border-bottom: 1px solid var(--champagne-dim); transition: color var(--dur) var(--ease); }
.contact__meta a:hover { color: var(--champagne); }

.form { display: grid; gap: 1.1rem; }
.form__row { display: grid; gap: 1.1rem; }
@media (min-width: 620px) { .form__row { grid-template-columns: 1fr 1fr; } }
.field { display: grid; gap: 0.5rem; }
.field > span {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.field input, .field select, .field textarea {
  width: 100%;
  background: var(--ink-850);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.85rem 1rem;
  color: var(--bone);
  font-size: var(--t-body);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.field textarea { resize: vertical; min-height: 8rem; }
.field input::placeholder, .field textarea::placeholder { color: var(--bone-faint); opacity: 0.75; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--champagne-dim); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--champagne);
  background: var(--ink-800);
}
.field select { appearance: none; cursor: pointer; padding-right: 2.5rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--champagne) 50%), linear-gradient(135deg, var(--champagne) 50%, transparent 50%);
  background-position: calc(100% - 1.25rem) 1.35rem, calc(100% - 1rem) 1.35rem;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.field select option { background: var(--ink-800); color: var(--bone); }
.field--invalid input, .field--invalid select, .field--invalid textarea { border-color: var(--err); }
.field__error { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--err); }

.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

.form__foot { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; }
.form__note { font-size: var(--t-small); color: var(--bone-faint); }
.form__status { font-family: var(--font-mono); font-size: var(--t-small); }
.form__status[data-state='ok'] { color: var(--ok); }
.form__status[data-state='error'] { color: var(--err); }
.btn[aria-busy='true'] { opacity: 0.65; pointer-events: none; }

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--line-soft); padding-block: clamp(2.5rem, 5vw, 4rem) 2rem; }
.footer__top { display: grid; gap: 2rem; padding-bottom: 2.5rem; }
@media (min-width: 780px) { .footer__top { grid-template-columns: 1.2fr 0.8fr; align-items: start; } }
.footer__mark { color: var(--bone); margin: 0; }
.footer__mark .brandmark { height: 2rem; }
.footer__top p { color: var(--bone-faint); font-size: var(--t-small); max-width: 34ch; margin-top: 0.6rem; }
.footer__links { display: flex; flex-wrap: wrap; gap: 0.75rem 1.5rem; align-content: start; }
.footer__links a {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone-dim);
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.footer__links a:hover { color: var(--champagne); border-bottom-color: var(--champagne-dim); }
.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  align-items: center;
  padding-top: 1.75rem;
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--bone-faint);
  letter-spacing: 0.06em;
}
.to-top { background: none; border: none; cursor: pointer; color: var(--bone-faint); font-family: inherit; font-size: inherit; letter-spacing: inherit; transition: color var(--dur) var(--ease); }
.to-top:hover { color: var(--champagne); }

/* ---------- Lightbox ---------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  border: none;
  padding: 0;
  margin: 0;
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  background: color-mix(in srgb, var(--ink-900) 99%, transparent);
  color: var(--bone);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
  overflow-y: auto;
}
.lightbox[open] { opacity: 1; }
.lightbox::backdrop { background: var(--backdrop); }
.lightbox__inner {
  min-height: 100%;
  display: grid;
  align-content: center;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  max-width: 1100px;
  margin-inline: auto;
  padding: clamp(3.5rem, 8vw, 5rem) var(--gutter);
}
@media (min-width: 900px) { .lightbox__inner { grid-template-columns: 1.35fr 1fr; align-items: center; } }
.lightbox__media { border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; background: var(--ink-800); }
.lightbox__media img { width: 100%; height: auto; }
.lightbox__body { display: grid; gap: 1rem; align-content: center; }
.lightbox__body h3 { font-family: var(--font-display); font-weight: 400; font-size: clamp(1.5rem, 1.2rem + 1vw, 2.1rem); }
.lightbox__body p { color: var(--bone-dim); font-size: var(--t-small); }
.lightbox__body h4 {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--champagne);
  margin-top: 0.5rem;
}
.lightbox__body li { font-size: var(--t-small); color: var(--bone-dim); padding-block: 0.3rem; display: flex; gap: 0.6rem; }
.lightbox__body li::before { content: '–'; color: var(--champagne-dim); flex: none; }
.lightbox__close {
  position: fixed;
  top: 1.25rem; right: 1.25rem;
  width: 2.75rem; height: 2.75rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--ink-800);
  color: var(--bone);
  font-size: 1.15rem;
  cursor: pointer;
  z-index: 2;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.lightbox__close:hover { border-color: var(--champagne); color: var(--champagne); }

/* ---------- Reveal on scroll ---------- */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity 620ms var(--ease), transform 620ms var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }

/* Children of a revealed grid come in one after another rather than as a slab. */
.reveal[data-stagger] > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 520ms var(--ease), transform 520ms var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.reveal[data-stagger].is-in > * { opacity: 1; transform: none; }

/* ==========================================================================
   Page-load orchestration
   One sequence on arrival — headline lines rise out of their own mask,
   everything else follows on a fixed cadence. Runs once, then never again.
   ========================================================================== */
/* Padding buys room for descenders so the mask can't clip the "g" in
   "marketing"; the negative margin cancels it so layout is unchanged. */
.hero__line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
.hero__line > span { display: block; will-change: transform; }

.js-load .hero__line > span { transform: translateY(105%); }
.js-load .hero__lift { opacity: 0; transform: translateY(20px); }
.js-load .portrait__frame { opacity: 0; transform: translateY(24px) scale(0.985); }

.hero__line > span,
.hero__lift,
.portrait__frame {
  transition: transform 900ms var(--ease-out), opacity 700ms var(--ease-out);
}
.is-loaded .hero__line > span { transform: none; }
.is-loaded .hero__lift { opacity: 1; transform: none; }
.is-loaded .portrait__frame { opacity: 1; transform: none; }

/* Cadence */
.is-loaded .hero__line:nth-child(1) > span { transition-delay: 80ms; }
.is-loaded .hero__line:nth-child(2) > span { transition-delay: 190ms; }
.is-loaded .hero__lift[data-d='1'] { transition-delay: 40ms; }
.is-loaded .hero__lift[data-d='2'] { transition-delay: 330ms; }
.is-loaded .hero__lift[data-d='3'] { transition-delay: 420ms; }
.is-loaded .hero__lift[data-d='4'] { transition-delay: 510ms; }
.is-loaded .portrait__frame { transition-delay: 240ms; }

/* ---------- Scroll progress ---------- */
.progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--champagne-dim), var(--champagne));
  z-index: 150;
  pointer-events: none;
}

/* ---------- Work grid: stagger cards in after a filter change ---------- */
.card {
  animation: card-in 480ms var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}
.card.is-settled { animation: none; }
@keyframes card-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Lightbox entrance ---------- */
.lightbox__inner { transform: translateY(12px) scale(0.99); transition: transform 320ms var(--ease-out); }
.lightbox[open] .lightbox__inner { transform: none; }

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .reveal[data-stagger] > * { opacity: 1; transform: none; }
  .ops__board .stage__meter i { transition: none; }
  .card:hover { transform: none; }
  .card:hover .card__media img { transform: none; }
  .report:hover { transform: none; }
  .dot { animation: none; }

  /* Nothing may start hidden — the load sequence is skipped entirely. */
  .js-load .hero__line > span,
  .js-load .hero__lift,
  .js-load .portrait__frame { opacity: 1 !important; transform: none !important; }
  .card { animation: none; }
  .lightbox__inner { transform: none; }
  .hero__glow { transition: none; transform: none; }
  .progress { display: none; }
}

/* ---------- Print ---------- */
@media print {
  body { background: #fff; color: #000; }
  .site-header, .lightbox, .work-more, body::before, .hero__glow { display: none !important; }
}


/* ==========================================================================
   Johvany C. Delarosa — v2 upgrade layer
   Loaded after site.css. Everything here either adds a new component or
   deliberately sharpens an existing one. Same tokens, same restraint:
   dark luxe, champagne accent, motion that settles rather than bounces.
   ========================================================================== */

/* ---------- New motion tokens ---------- */
:root {
  --ease-soft: cubic-bezier(0.33, 1, 0.68, 1);
  --glass: rgba(237, 232, 223, 0.04);
  --halo: rgba(201, 169, 97, 0.16);
}

/* ==========================================================================
   HERO — rotator, portrait caption, wider stat row
   ========================================================================== */

/* The "currently running" line. A single slot with items cross-fading
   through it, so the row never changes height and never reflows. */
.hero__rotator {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem 0.9rem;
  margin-top: 1.75rem;
  font-family: var(--font-mono);
  font-size: var(--t-small);
}
.hero__rotator-label {
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bone-faint);
  flex: none;
}
.hero__rotator-label::after {
  content: '';
  display: inline-block;
  width: 1.4rem;
  height: 1px;
  margin-left: 0.6rem;
  vertical-align: middle;
  background: var(--champagne-dim);
}
.rotator {
  position: relative;
  display: inline-grid;
  min-height: 1.6em;
  color: var(--champagne);
}
/* Every item sits in the same grid cell; only opacity and a small lift
   differ, so the widest item silently reserves the width. */
.rotator__item {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(0.5em);
  transition: opacity 460ms var(--ease-out), transform 460ms var(--ease-out);
  pointer-events: none;
  white-space: nowrap;
}
.rotator__item.is-on {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.rotator__item.is-out {
  opacity: 0;
  transform: translateY(-0.5em);
}
/* Below roughly an iPhone SE the longest phrase would push the line wider
   than the gutter allows. Wrapping is safe here: every item shares one grid
   cell, so the tallest reserves the height and nothing reflows on change. */
@media (max-width: 420px) {
  .rotator__item { white-space: normal; }
}

.portrait__caption {
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone-faint);
  text-align: right;
}

/* Four stats need a tighter minimum than the original three. */
.hero__meta { grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr)); }
.hero__meta strong { font-size: clamp(1.6rem, 1.3rem + 1vw, 2rem); }

/* The hero no longer runs straight into a section heading — the marquee band
   follows it — so the full section rhythm below it reads as a gap. */
.hero { padding-bottom: clamp(3rem, 2rem + 4vw, 5rem); }

/* The portrait drifts a few pixels against the scroll — depth, not parallax
   theatre. The offset is written from JS into --py.
   This uses the independent `translate` property rather than `transform`,
   because the load sequence above already owns `transform` on this element
   and would otherwise cancel the drift the moment .is-loaded lands. */
@media (min-width: 960px) {
  .portrait__frame {
    translate: 0 var(--py, 0px);
    will-change: translate;
  }
}

/* The load cadence in site.css stops at data-d="4"; the hero now has five. */
.is-loaded .hero__lift[data-d='5'] { transition-delay: 600ms; }

/* ==========================================================================
   MARQUEE — the client band under the hero
   ========================================================================== */
.marquee-band {
  border-block: 1px solid var(--line-soft);
  background: var(--ink-850);
  overflow: hidden;
}
.marquee {
  display: flex;
  width: 100%;
  padding-block: 1.1rem;
  /* Fades the ends into the surface so items enter and leave rather than
     being chopped off at the viewport edge. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex;
  align-items: center;
  gap: 2.5rem;
  flex: none;
  padding-right: 2.5rem;
  animation: marquee-scroll var(--marquee-dur, 44s) linear infinite;
  will-change: transform;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
.marquee__item {
  font-family: var(--font-display);
  font-size: clamp(1rem, 0.9rem + 0.5vw, 1.35rem);
  font-weight: 400;
  color: var(--bone-dim);
  white-space: nowrap;
  transition: color var(--dur) var(--ease);
}
.marquee__item:hover { color: var(--bone); }
.marquee__dot {
  color: var(--champagne);
  font-size: 0.6rem;
  opacity: 0.7;
  flex: none;
}

/* ==========================================================================
   CASE STUDIES — index number, role line, "what I did" list, accent edge
   ========================================================================== */
/* A champagne rule draws down beside the client name as the case enters.
   It sits against the client column rather than the section edge, so it
   lands inside the text measure instead of hugging the viewport. Drawn by
   default and collapsed only while a revealable case is still offscreen,
   so with JS off the rule is present rather than missing. */
.case { --case-edge: 1; }
.case__client { position: relative; padding-left: 1.15rem; }
.case__client::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.35rem;
  bottom: 0.35rem;
  width: 2px;
  background: linear-gradient(180deg, var(--champagne), var(--champagne-dim));
  transform: scaleY(var(--case-edge));
  transform-origin: 0 0;
  transition: transform 700ms var(--ease-out) 120ms;
  pointer-events: none;
}
.case__index {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  color: var(--bone-faint) !important;
  display: block;
  margin-bottom: 0.15rem;
}
.case__role {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bone-faint);
  margin-top: 0.25rem;
}

/* The detail list under each case paragraph. Hairline rules rather than
   bullets — it reads as a record, not a sales list. */
.case__did { display: grid; gap: 0; margin-top: 0.25rem; }
.case__did li {
  position: relative;
  padding: 0.5rem 0 0.5rem 1.1rem;
  border-top: 1px solid var(--line-soft);
  font-size: var(--t-small);
  color: var(--bone-faint);
  line-height: 1.5;
}
.case__did li:last-child { border-bottom: 1px solid var(--line-soft); }
.case__did li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 1.32em;
  width: 5px;
  height: 1px;
  background: var(--champagne-dim);
}

/* Slightly stronger hover than the original, and a real result block. */
.case:hover .case__result dd { color: var(--champagne-lift); }
.case__result dd { transition: color var(--dur) var(--ease); }

/* ==========================================================================
   SERVICES — subtle pointer-tracked halo and lift
   ========================================================================== */
.svc {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition: background var(--dur) var(--ease), translate 420ms var(--ease-out);
}
/* A soft champagne halo follows the cursor across the tile. Coordinates
   come from JS as percentages; with JS off it simply never appears. */
.svc::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background: radial-gradient(
    18rem 18rem at var(--mx, 50%) var(--my, 50%),
    var(--halo),
    transparent 70%
  );
  transition: opacity 380ms var(--ease);
  pointer-events: none;
}
.svc:hover::after,
.svc:focus-within::after { opacity: 1; }
/* `translate`, not `transform`: the stagger-reveal rule owns `transform` on
   these tiles and carries a per-child transition-delay, which would make the
   hover lift arrive up to half a second late on the last tiles. */
.svc:hover { translate: 0 -2px; }
.svc__mark { transition: width 420ms var(--ease-out), background var(--dur) var(--ease); }
.svc:hover .svc__mark { width: 2.6rem; background: var(--champagne-lift); }
.svc h3 { transition: color var(--dur) var(--ease); }
.svc:hover h3 { color: var(--champagne-lift); }

/* The closing tile. Spans whatever columns are left over so the grid never
   ends on empty cells showing the gap colour through. */
.svc--cta {
  background: linear-gradient(160deg, var(--ink-800), var(--ink-900) 70%);
  gap: 0.9rem;
}
.svc--cta h3 { color: var(--champagne); }
.svc--cta p { color: var(--bone-dim); }
.svc--cta .tlink { justify-self: start; margin-top: 0.2rem; }
@media (min-width: 640px)  { .svc--cta { grid-column: span 2; } }

/* ==========================================================================
   STACK — the tools grid
   ========================================================================== */
.stack-grid {
  display: grid;
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
@media (min-width: 620px)  { .stack-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .stack-grid { grid-template-columns: repeat(3, 1fr); } }

.stack__col {
  background: var(--ink-900);
  padding: 1.6rem 1.4rem 1.8rem;
  display: grid;
  gap: 1rem;
  align-content: start;
  transition: background var(--dur) var(--ease);
}
.stack__col:hover { background: var(--ink-850); }
.stack__label {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
}
.stack__list { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.stack__list li {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.03em;
  color: var(--bone-dim);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  padding: 0.3rem 0.6rem;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease), transform 260ms var(--ease-out);
}
.stack__list li:hover {
  border-color: var(--champagne-dim);
  color: var(--bone);
  transform: translateY(-2px);
}

/* ==========================================================================
   PROCESS — a champagne rule that draws itself across the four steps
   ========================================================================== */
.steps { position: relative; }
.steps::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  height: 2px;
  width: 100%;
  background: linear-gradient(90deg, var(--champagne), var(--champagne-dim));
  transform: scaleX(var(--steps-draw, 1));
  transform-origin: 0 50%;
  transition: transform 1100ms var(--ease-out);
}
.steps.reveal:not(.is-in) { --steps-draw: 0; }

.step { position: relative; transition: background var(--dur) var(--ease); }
.step:hover { background: var(--ink-850); }
/* The step number gets a quiet ghost digit behind it, so the sequence is
   legible at a glance without shouting. */
.step__n { position: relative; z-index: 1; }
.step h3 { position: relative; z-index: 1; }
.step p  { position: relative; z-index: 1; }
.step::before {
  content: attr(data-ghost);
  position: absolute;
  right: 1rem;
  top: 0.5rem;
  font-family: var(--font-display);
  font-size: 4.5rem;
  line-height: 1;
  color: var(--bone);
  opacity: var(--ghost);
  pointer-events: none;
  z-index: 0;
}

/* ==========================================================================
   MAGNETIC BUTTONS
   Translation values are written from JS and clamped to a few pixels, so a
   pointer-less visitor loses nothing at all.
   ========================================================================== */
/* Uses `translate` rather than `transform` so it composes with the -1px lift
   .btn already applies on hover instead of overwriting it. While the pointer
   is inside, the transition shortens so the element tracks the cursor; on
   leave it lengthens again and the button eases back to rest. */
[data-magnetic] {
  translate: var(--magx, 0px) var(--magy, 0px);
  transition: translate 420ms var(--ease-out), background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
[data-magnetic].is-pulled { transition: translate 120ms var(--ease-soft); }

/* ==========================================================================
   SECTION HEADINGS — a hairline that draws in under the eyebrow
   ========================================================================== */
/* A trailing hairline that mirrors the leading dash and draws outward as the
   section arrives. `.eyebrow` is a flex row, so this is a flex item, not a
   block underneath. Full width is the default so that with JS off — where
   `.reveal` is never applied — the rule is simply there, already drawn. */
.eyebrow::after {
  content: '';
  flex: none;
  height: 1px;
  width: 4.5rem;
  background: linear-gradient(90deg, var(--champagne-dim), transparent);
  transition: width 900ms var(--ease-out) 180ms;
}
.reveal:not(.is-in) .eyebrow::after { width: 0; }

/* ==========================================================================
   NEW SECTIONS join the scroll-reveal system
   ========================================================================== */
.stack-grid.reveal[data-stagger] > * { transition-delay: calc(var(--i, 0) * 60ms); }

/* ==========================================================================
   REDUCED MOTION — everything above degrades to static
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  /* No scroll, so the band becomes a static wrapped list. The track has to
     give up `flex: none` first, or it keeps sizing to its content and never
     wraps. JS also skips duplicating the items in this mode, so the list is
     each client exactly once. */
  .marquee__track {
    animation: none;
    transform: none;
    flex-wrap: wrap;
    flex: 1 1 auto;
    min-width: 0;
    justify-content: center;
    gap: 0.75rem 2rem;
    padding-right: 0;
  }
  .marquee {
    -webkit-mask-image: none;
            mask-image: none;
    padding-inline: var(--gutter);
  }
  .marquee__item { white-space: normal; }
  /* In the scrolling version the trailing star bridges the loop seam; in a
     static wrapped list it is just a dangling mark after the last name. */
  .marquee__track > .marquee__dot:last-child { display: none; }
  .rotator__item { transition: none; }
  .case__client::before { transform: scaleY(1); transition: none; }
  .steps::after { transform: scaleX(1); transition: none; }
  .eyebrow::after { width: 4.5rem; transition: none; }
  .svc:hover { translate: none; }
  .svc::after { display: none; }
  .stack__list li:hover { transform: none; }
  [data-magnetic] { translate: none !important; transition: none; }
  .portrait__frame { translate: none !important; }
  .is-loaded .hero__lift[data-d='5'] { transition-delay: 0ms; }
}

/* ==========================================================================
   PRINT
   ========================================================================== */
@media print {
  .marquee-band, .rotator, .portrait__caption { display: none !important; }
  .case__client::before, .steps::after { display: none !important; }
}


/* ==========================================================================
   v3 — conversion layer
   Sections organised around the buyer's decision: is this for me, what
   goes away, how do we start, why trust it. Same tokens and restraint.
   ========================================================================== */

.section--tight { padding-block: clamp(2.5rem, 2rem + 3vw, 4.5rem); }

/* ---------- Hero trust row ---------- */
.hero__trust {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin-top: 1.5rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  color: var(--bone-faint);
}
.hero__trust li { display: inline-flex; align-items: center; gap: 0.45rem; }
.hero__trust li + li::before {
  content: '';
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--champagne-dim);
  margin-right: 0.8rem;
}

/* ---------- Sound familiar ---------- */
.pain-grid {
  display: grid;
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
@media (min-width: 760px) { .pain-grid { grid-template-columns: repeat(2, 1fr); } }
.pain {
  background: var(--ink-900);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  display: grid;
  gap: 1.25rem;
  align-content: space-between;
  transition: background var(--dur) var(--ease);
}
.pain:hover { background: var(--ink-850); }
.pain__problem {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 1.05rem + 0.6vw, 1.5rem);
  line-height: 1.3;
  color: var(--bone);
}
.pain__fix {
  font-size: var(--t-small);
  color: var(--bone-dim);
  line-height: 1.6;
  padding-top: 1rem;
  border-top: 1px solid var(--line-soft);
}
.pain__fix span {
  display: block;
  margin-bottom: 0.35rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
}

/* ---------- Who I work with ---------- */
.fit-grid {
  display: grid;
  gap: 1px;
  margin-top: 1.5rem;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
@media (min-width: 760px) { .fit-grid { grid-template-columns: repeat(3, 1fr); } }
.fit {
  background: var(--ink-900);
  padding: 1.5rem 1.4rem 1.6rem;
  display: grid;
  gap: 0.6rem;
  align-content: start;
  transition: background var(--dur) var(--ease);
}
.fit:hover, .fit:focus-visible { background: var(--ink-850); }
.fit__label { font-family: var(--font-display); font-size: 1.2rem; color: var(--bone); }
.fit__text { font-size: var(--t-small); color: var(--bone-faint); line-height: 1.55; }
.fit__link {
  margin-top: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  color: var(--champagne);
  transition: transform 300ms var(--ease-out);
}
.fit:hover .fit__link { transform: translateX(4px); }

/* ---------- Case studies: before -> after and system flow ---------- */
.case__shift { display: grid; gap: 0.5rem; }
.case__shift li {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  gap: 0.75rem;
  font-size: var(--t-small);
  line-height: 1.45;
}
.case__shift s { color: var(--bone-faint); text-decoration-color: var(--line); }
.case__shift li > span { color: var(--champagne); font-family: var(--font-mono); }
.case__shift b { font-weight: 450; color: var(--bone); }
@media (max-width: 520px) {
  .case__shift li { grid-template-columns: 1fr; gap: 0.1rem; }
  .case__shift li > span { transform: rotate(90deg); justify-self: start; }
}

.case__map {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0;
  padding: 0.9rem 1rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius-lg);
  background: var(--glass);
}
.case__map li {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.03em;
  color: var(--bone-dim);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
  background: var(--ink-900);
}
.case__map li:last-child { border-color: var(--champagne-dim); color: var(--champagne); }
.case__map li + li { position: relative; margin-left: 1.5rem; }
/* A short champagne connector sits in the gap before each node. */
.case__map li + li::before {
  content: '';
  position: absolute;
  right: 100%;
  top: 50%;
  width: 1.5rem;
  height: 1px;
  background: var(--champagne-dim);
}
/* Nodes arrive one after another each time a case becomes the current slide.
   Gated on .is-live, which the slider script sets, so with JavaScript off the
   map is simply drawn rather than hidden. */
.cases-wrap.is-live .case__map li { opacity: 0; transform: translateY(6px); transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out); }
.cases-wrap.is-live .case.is-current .case__map li { opacity: 1; transform: none; }
.cases-wrap.is-live .case.is-current .case__map li:nth-child(2) { transition-delay: 120ms; }
.cases-wrap.is-live .case.is-current .case__map li:nth-child(3) { transition-delay: 240ms; }
.cases-wrap.is-live .case.is-current .case__map li:nth-child(4) { transition-delay: 360ms; }
.cases-wrap.is-live .case.is-current .case__map li:nth-child(5) { transition-delay: 480ms; }

.case__thumb {
  position: relative;
  display: block;
  max-width: 26rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.case__thumb img { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; transition: transform 600ms var(--ease-out); }
.case__thumb:hover img { transform: scale(1.04); }
.case__thumb > span {
  position: absolute;
  left: 0.75rem;
  bottom: 0.75rem;
  padding: 0.35rem 0.7rem;
  border-radius: var(--radius);
  background: var(--overlay);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--champagne);
}

/* ---------- Next steps beside the form ---------- */
.next-steps {
  margin-top: 2rem;
  padding: 1.25rem 1.35rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  background: var(--ink-850);
}
.next-steps__title {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
  margin-bottom: 0.75rem;
}
.next-steps ol { display: grid; gap: 0.7rem; counter-reset: step; }
/* Block, not grid: each <li> mixes a <b> with bare text, and in a grid every
   text run becomes its own anonymous item — which pushed the sentence into
   the 1.6rem numeral column, one word per line. */
.next-steps li {
  counter-increment: step;
  position: relative;
  padding-left: 2.2rem;
  min-height: 1.6rem;
  font-size: var(--t-small);
  color: var(--bone-faint);
  line-height: 1.5;
}
.next-steps li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0;
  display: grid;
  place-items: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  border: 1px solid var(--champagne-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--champagne);
}
.next-steps b { font-weight: 450; color: var(--bone); }

/* ---------- Sticky mobile CTA bar ---------- */
.cta-bar {
  position: fixed;
  left: 0.75rem;
  right: 0.75rem;
  bottom: max(0.75rem, env(safe-area-inset-bottom));
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.55rem 0.55rem 0.55rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bar-bg);
  -webkit-backdrop-filter: blur(12px);
          backdrop-filter: blur(12px);
  box-shadow: var(--shadow-lg);
  transform: translateY(160%);
  transition: transform 460ms var(--ease-out);
}
.cta-bar[hidden] { display: none; }
.cta-bar.is-shown { transform: none; }
.cta-bar__text {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--bone-dim);
  min-width: 0;
}
.cta-bar .btn { flex: none; border-radius: 999px; }
@media (min-width: 940px) { .cta-bar { display: none !important; } }
@media (max-width: 360px) { .cta-bar__text { display: none; } .cta-bar { justify-content: center; } }

/* The reveal system staggers these grids child-by-child, and its rule
   replaces each card's own `transition`. Restate every property so the
   entrance keeps its stagger while hover effects stay immediate. */
.pain-grid.reveal[data-stagger] > *,
.fit-grid.reveal[data-stagger] > * {
  transition:
    opacity 520ms var(--ease) calc(var(--i, 0) * 80ms),
    transform 520ms var(--ease) calc(var(--i, 0) * 80ms),
    background var(--dur) var(--ease) 0s,
    border-color var(--dur) var(--ease) 0s,
    translate 420ms var(--ease-out) 0s;
}

@media (prefers-reduced-motion: reduce) {
  .cases-wrap.is-live .case__map li { opacity: 1; transform: none; transition: none; }
  .fit:hover .fit__link { transform: none; }
  .case__thumb:hover img { transform: none; }
  .cta-bar { transition: none; }
}

@media print {
  .cta-bar { display: none !important; }
}

/* The contact intro column is taller now that it carries the next-steps
   panel; without this the form's grid rows stretch to match it and every
   field balloons. Keep the form at its natural height and let it stick. */
.form { align-content: start; align-self: start; }
@media (min-width: 940px) { .form { position: sticky; top: 6rem; } }
.field { align-content: start; }


/* ==========================================================================
   v4 — shorter, sharper, more convincing
   Mobile length roughly halved without deleting content, a lead-leak
   estimator, disclosures on case studies, and case-study page layout.
   ========================================================================== */

/* ---------- Contrast ----------
   The original faint text (#6f6c66 on #0b0b0c) measured ~3.8:1, under the
   4.5:1 WCAG AA minimum for body-size text. This keeps the same warm hue
   and lifts it to ~5.4:1. */
:root { --bone-faint: #8a867f; }

/* ---------- Case studies: full story behind a disclosure ---------- */
.case__more { border-top: 1px solid var(--line-soft); }
.case__more > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-block: 0.85rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--champagne);
  transition: color var(--dur) var(--ease);
}
.case__more > summary::-webkit-details-marker { display: none; }
.case__more > summary::after {
  content: '+';
  font-size: 1rem;
  line-height: 1;
  transition: transform var(--dur) var(--ease);
}
.case__more[open] > summary::after { transform: rotate(45deg); }
.case__more > summary:hover { color: var(--champagne-lift); }
.case__more[open] > summary { color: var(--bone-dim); }
.case__more > p { color: var(--bone-dim); max-width: 60ch; margin-bottom: 1rem; }
.case__more[open] > *:not(summary) { animation: more-in 420ms var(--ease-out); }
@keyframes more-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.case__page { margin-top: 1rem; justify-self: start; }

/* The written formula is the no-JS fallback; once the calculator is live it
   would only repeat what the sliders show. */
/* ---------- Stack: collapsible groups ---------- */
.stack__col > summary { list-style: none; cursor: default; }
.stack__col > summary::-webkit-details-marker { display: none; }

/* ---------- Case-study pages ---------- */
.cs-hero { padding-block: clamp(2.5rem, 2rem + 5vw, 5.5rem) clamp(2rem, 4vw, 3.5rem); border-bottom: 1px solid var(--line-soft); }
.cs-back {
  display: inline-flex;
  gap: 0.4rem;
  margin-bottom: 2rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  color: var(--bone-faint);
  transition: color var(--dur) var(--ease);
}
.cs-back:hover { color: var(--champagne); }
.cs-hero h1 { font-size: clamp(2.4rem, 1.4rem + 4.5vw, 4.75rem); margin-block: 1rem 1.25rem; }
.cs-meta {
  display: grid;
  gap: 1px;
  margin-top: 2.5rem;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
@media (min-width: 760px) { .cs-meta { grid-template-columns: repeat(4, 1fr); } }
.cs-meta div { background: var(--ink-900); padding: 1rem 1.2rem; display: grid; gap: 0.3rem; }
.cs-meta dt { font-family: var(--font-mono); font-size: var(--t-micro); letter-spacing: 0.12em; text-transform: uppercase; color: var(--bone-faint); }
.cs-meta dd { margin: 0; color: var(--bone); }

.cs-body { display: grid; gap: clamp(2.5rem, 5vw, 4rem); }
@media (min-width: 960px) { .cs-body { grid-template-columns: 1fr 18rem; align-items: start; } }
.cs-prose { display: grid; gap: 2.5rem; max-width: 70ch; }
.cs-prose h2 { font-family: var(--font-display); font-weight: 400; font-size: var(--t-h3); margin-bottom: 0.9rem; }
.cs-prose p { color: var(--bone-dim); }
.cs-prose p + p { margin-top: 0.9rem; }
.cs-prose .case__did { margin-top: 0.75rem; }
.cs-prose .case__did li { color: var(--bone-dim); }
.cs-aside {
  display: grid;
  gap: 1.25rem;
  padding: 1.4rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  background: var(--ink-850);
}
@media (min-width: 960px) { .cs-aside { position: sticky; top: 6rem; } }
.cs-aside h2 { font-family: var(--font-mono); font-size: var(--t-micro); font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase; color: var(--champagne); }
.cs-aside .btn { justify-self: start; }
.cs-next { display: grid; gap: 1px; background: var(--line-soft); border: 1px solid var(--line-soft); border-radius: var(--radius-lg); overflow: hidden; }
@media (min-width: 760px) { .cs-next { grid-template-columns: repeat(3, 1fr); } }

/* ==========================================================================
   Mobile compaction (below the nav breakpoint)
   ========================================================================== */
@media (max-width: 959px) {
  /* Hero: the portrait becomes a compact identity row above the headline
     instead of a full-height card after all the copy. */
  .hero__grid { gap: 0; }
  .portrait { order: -1; margin-bottom: 1.5rem; }
  .portrait__frame {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    border: 0;
    background: none;
    overflow: visible;
  }
  .portrait__frame img {
    width: 64px;
    height: 64px;
    aspect-ratio: 1;
    border-radius: 50%;
    border: 1px solid var(--line);
    object-position: center 22%;
    flex: none;
  }
  .portrait__frame::after { display: none; }
  .portrait__plate { padding: 0; border: 0; background: none; flex: 1; }
  .portrait__mono, .portrait__caption { display: none; }
  .hero__meta { grid-template-columns: repeat(2, 1fr); gap: 1.25rem; margin-top: 2rem; padding-top: 1.5rem; }
  .hero h1 { margin-bottom: 1.2rem; }
}

@media (max-width: 759px) {
  /* Section rhythm: the desktop spacing reads as dead scroll on a phone. */
  :root { --section-y: clamp(3.25rem, 2.5rem + 5vw, 4.5rem); }
  .section-head { gap: 0.9rem; margin-bottom: 1.75rem; }
  .section-head .lead { font-size: var(--t-body); }

  /* Case studies: tighter, and the empty result column stops stacking gaps. */
  .case { padding-block: 1.75rem; }
  .case__inner { gap: 1rem; }
  .case__client h3 { font-size: 1.35rem; }
  .case__result dd { font-size: 1.25rem; }
  .case__thumb { max-width: none; }

  /* Pain points: the fix is still there, just set tighter. */
  .pain { padding: 1.25rem; gap: 0.9rem; }
  .pain__problem { font-size: 1.1rem; }
  .pain__fix { padding-top: 0.75rem; }

  /* Operation board: two columns instead of four stacked cards. */
  .ops__board { grid-template-columns: repeat(2, 1fr) !important; }
  .stage { padding: 1rem 0.9rem 1.1rem; gap: 0.7rem; }
  .stage__list li { font-size: 0.82rem; padding-block: 0.35rem; }
  .ops__note { font-size: var(--t-small); }

  /* Reports: a swipeable row instead of six stacked cards. */
  .reports__grid {
    display: flex;
    gap: 0.9rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    padding-bottom: 0.5rem;
    scrollbar-width: thin;
  }
  .reports__grid > .report { flex: 0 0 78%; scroll-snap-align: start; }

  /* Services: description clamped to two lines. The full text is still in
     the DOM for search engines and screen readers. */
  .svc { padding: 1.1rem 1.1rem 1.2rem; gap: 0.45rem; }
  .svc p {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .svc--cta p { display: block; -webkit-line-clamp: unset; }

  /* Stack: groups collapse (enhance.js removes [open] on small screens). */
  .stack__col { padding: 0; gap: 0; }
  .stack__col > summary {
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 1.1rem;
  }
  .stack__col > summary::after { content: '+'; color: var(--champagne); transition: transform var(--dur) var(--ease); }
  .stack__col[open] > summary::after { transform: rotate(45deg); }
  .stack__col > .stack__list { padding: 0 1.1rem 1.1rem; }

  /* Process: two columns. */
  .steps { grid-template-columns: repeat(2, 1fr); }
  .step { padding: 1.2rem 1rem 1.3rem; }
  .step::before { font-size: 3rem; }

  /* Contact: reply time is repeated in "What happens after you send this". */
  .contact__meta div:nth-child(4) { display: none; }
  .contact__meta { margin-top: 1.5rem; }


  /* Work grid: descriptions live in the lightbox; the card keeps image,
     client and title so more pieces fit per screen. */
  .card__desc { display: none; }
  .filters { flex-wrap: nowrap; overflow-x: auto; margin-bottom: 1.5rem; padding-bottom: 1rem; scrollbar-width: none; }
  .filters::-webkit-scrollbar { display: none; }
  .filters > * { flex: none; }
}

@media (prefers-reduced-motion: reduce) {
  .case__more[open] > *:not(summary) { animation: none; }
}
@media print {
  .case__more > *:not(summary) { display: block !important; }
}

/* Visually hidden, still announced by screen readers. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---------- v4 second pass: length ---------- */

/* Desktop: inside the slider frame each case keeps its own three-column
   inner layout, so the wide frame is used rather than stacked. */
@media (min-width: 1100px) {
  .case__result { padding-top: 1rem; border-top: 1px solid var(--line-soft); }
}
@media (max-width: 959px) {
  /* One-line status under the avatar; location is in the contact block. */
  .hero__status .sep,
  .hero__status > span:last-child { display: none; }
  .hero__status { padding-bottom: 1rem; margin-bottom: 1.5rem; }
}

@media (max-width: 759px) {
  /* Before → after reads as one line each instead of a three-row stack. */
  .case__shift li { display: block; }
  .case__shift li > span { display: inline; transform: none; margin-inline: 0.4rem; }
  .case .case__tags { display: none; }
  .case__map { padding: 0.7rem; }

  /* Services: two across; titles plus a three-line summary. */
  .svc-grid { grid-template-columns: repeat(2, 1fr); }
  .svc { padding: 1rem 0.9rem 1.1rem; }
  .svc h3 { font-size: 0.98rem; line-height: 1.25; }
  .svc p { font-size: 0.8rem; -webkit-line-clamp: 3; }
  .svc--cta { grid-column: span 2; }

  /* Work: two across; the lightbox carries the detail. */
  .work-grid { grid-template-columns: repeat(2, 1fr); gap: 0.7rem; }
  .card__body { padding: 0.7rem 0.75rem 0.85rem; gap: 0.35rem; }
  .card__title { font-size: 0.9rem; }
  .card__title span { display: none; }
  .card__cat { font-size: 0.6rem; letter-spacing: 0.06em; }
  .card__type { display: none; }
}

/* ---------- v4 third pass ---------- */
/* Fifteen sections at up to 9rem top and bottom was ~4,300px of padding on
   desktop alone. Still generous, no longer a scroll tax. */
:root { --section-y: clamp(3.5rem, 2.25rem + 4.5vw, 6.5rem); }

@media (min-width: 900px) {
  .faq { grid-template-columns: 1fr 1fr; column-gap: 3rem; border-top: 0; }
  .faq details:nth-child(-n+2) { border-top: 1px solid var(--line-soft); }
}

@media (max-width: 759px) {
  /* The system diagrams live on each case page; the homepage keeps the
     before → after lines and the result. */
  .case .case__map { display: none; }
  .fit { padding: 1rem 1.1rem 1.1rem; gap: 0.35rem; }
  .fit__link { display: none; }
  .fit-grid { margin-top: 1rem; }
}

/* ---------- Case-study page fixes ---------- */
.cs-hero h1 { font-size: clamp(2.2rem, 1.3rem + 3.2vw, 3.8rem); max-width: 22ch; }
.cs-meta div { align-content: start; }
/* No menu toggle on these pages, so the CTA stays visible on phones. */
.cs-page .nav__cta { display: inline-flex; }
@media (max-width: 759px) {
  .cs-meta { grid-template-columns: repeat(2, 1fr); }
  .cs-page .eyebrow::after { display: none; }
}

/* ==========================================================================
   WhatsApp — floating button and chat panel
   WhatsApp green is used deliberately: it's the one colour on the page
   people recognise instantly as "message me".
   ========================================================================== */
:root {
  --wa: #25d366;
  --wa-deep: #128c7e;
  --wa-bottom: max(1.25rem, env(safe-area-inset-bottom));
}

.wa-fab {
  position: fixed;
  right: max(1.25rem, env(safe-area-inset-right));
  bottom: var(--wa-bottom);
  z-index: 130;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.6rem;
  height: 3.6rem;
  border-radius: 50%;
  background: var(--wa);
  color: #fff;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.08) inset;
  transition: transform 320ms var(--ease-out), translate 420ms var(--ease-out), background var(--dur) var(--ease);
}
.wa-fab:hover { background: #20bd5a; transform: translateY(-2px) scale(1.04); }
.wa-fab:focus-visible { outline: 2px solid var(--bone); outline-offset: 3px; }
.wa-fab svg { width: 1.8rem; height: 1.8rem; }

/* A soft ring that pulses a few times after load, then stops. */
.wa-fab::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--wa);
  opacity: 0;
  animation: wa-ring 2.4s var(--ease-out) 2.5s 3;
  pointer-events: none;
}
@keyframes wa-ring {
  0%   { transform: scale(1);   opacity: 0.7; }
  100% { transform: scale(1.7); opacity: 0; }
}

/* "Chat on WhatsApp" label slides out on hover (desktop only). */
.wa-fab__label {
  position: absolute;
  right: calc(100% + 0.75rem);
  top: 50%;
  white-space: nowrap;
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  background: var(--ink-800);
  border: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.04em;
  color: var(--bone);
  opacity: 0;
  transform: translate(8px, -50%);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
  pointer-events: none;
}
@media (pointer: fine) {
  .wa-fab:hover .wa-fab__label,
  .wa-fab:focus-visible .wa-fab__label { opacity: 1; transform: translate(0, -50%); }
}
.wa-open .wa-fab__label { display: none; }

/* Swap the glyph for a close cross while the panel is open. */
.wa-open .wa-fab svg { transform: rotate(90deg) scale(0); }
.wa-fab svg { transition: transform 260ms var(--ease-out); }
.wa-fab::after {
  content: '✕';
  position: absolute;
  font-size: 1.3rem;
  line-height: 1;
  transform: rotate(-90deg) scale(0);
  transition: transform 260ms var(--ease-out);
}
.wa-open .wa-fab::after { transform: none; }

/* On phones the "Start a project" bar sits along the bottom; lift the
   button above it while the bar is showing. */
@media (max-width: 939px) {
  /* translate, not bottom: moving a fixed element by layout counts as a
     layout shift, a transform does not. */
  .cta-bar-on .wa-fab { translate: 0 -4.1rem; }
}

/* ---------- Panel ---------- */
.wa-panel {
  position: fixed;
  right: max(1.25rem, env(safe-area-inset-right));
  bottom: calc(var(--wa-bottom) + 4.6rem);
  z-index: 131;
  width: min(22.5rem, calc(100vw - 2rem));
  max-height: min(34rem, calc(100vh - 7rem));
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  overflow: hidden;
  background: #0b141a;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
  transform-origin: calc(100% - 1.8rem) 100%;
  opacity: 0;
  transform: translateY(12px) scale(0.96);
  transition: opacity 240ms var(--ease-out), transform 260ms var(--ease-out), translate 420ms var(--ease-out);
}
.wa-panel[hidden] { display: none; }
.wa-panel.is-open { opacity: 1; transform: none; }
@media (max-width: 939px) {
  .cta-bar-on .wa-panel { translate: 0 -8.7rem; }
}
@media (max-width: 420px) {
  .wa-panel { right: 0.75rem; left: 0.75rem; width: auto; }
}

.wa-panel__head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem 0.9rem;
  background: var(--wa-deep);
  color: #fff;
}
.wa-panel__avatar { position: relative; flex: none; }
.wa-panel__avatar img {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  object-fit: cover;
  object-position: center 20%;
  background: #d9d9d9;
}
.wa-panel__avatar i {
  position: absolute;
  right: 0;
  bottom: 1px;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  background: #9aa4a8;
  border: 2px solid var(--wa-deep);
}
.wa-panel__avatar i.is-on { background: var(--wa); }
.wa-panel__who { display: grid; gap: 0.1rem; min-width: 0; flex: 1; }
.wa-panel__who strong { font-family: var(--font-body); font-weight: 500; font-size: 0.98rem; }
.wa-panel__who span { font-size: 0.72rem; opacity: 0.85; line-height: 1.35; }
.wa-panel__close {
  flex: none;
  width: 2rem;
  height: 2rem;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  cursor: pointer;
  transition: background var(--dur) var(--ease);
}
.wa-panel__close:hover { background: rgba(255, 255, 255, 0.22); }

.wa-panel__body {
  flex: 1;
  overflow-y: auto;
  padding: 1rem 0.9rem 0.75rem;
  display: grid;
  align-content: start;
  gap: 0.85rem;
  /* WhatsApp's dark chat wallpaper, suggested rather than copied. */
  background:
    radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.025) 0 1px, transparent 1.5px) 0 0 / 18px 18px,
    #0b141a;
}
.wa-bubble {
  position: relative;
  justify-self: start;
  max-width: 88%;
  padding: 0.6rem 0.75rem 1.25rem;
  border-radius: 0 10px 10px 10px;
  background: #202c33;
  color: #e9edef;
  font-size: 0.86rem;
  line-height: 1.5;
  animation: wa-bubble 420ms var(--ease-out) 120ms backwards;
}
.wa-bubble::before {
  content: '';
  position: absolute;
  left: -7px;
  top: 0;
  border-top: 8px solid #202c33;
  border-left: 8px solid transparent;
}
.wa-bubble time {
  position: absolute;
  right: 0.6rem;
  bottom: 0.3rem;
  font-size: 0.65rem;
  color: #8696a0;
}
@keyframes wa-bubble {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.wa-quick { display: flex; flex-wrap: wrap; gap: 0.4rem; justify-content: flex-end; }
.wa-quick button {
  padding: 0.4rem 0.7rem;
  border: 1px solid rgba(37, 211, 102, 0.45);
  border-radius: 999px;
  background: rgba(37, 211, 102, 0.08);
  color: #d9fbe5;
  font-size: 0.76rem;
  line-height: 1.3;
  text-align: left;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.wa-quick button:hover { background: rgba(37, 211, 102, 0.18); border-color: var(--wa); }

.wa-panel__form {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  padding: 0.6rem 0.7rem;
  background: #202c33;
}
.wa-panel__form textarea {
  flex: 1;
  min-height: 2.5rem;
  max-height: 7.5rem;
  resize: none;
  padding: 0.6rem 0.85rem;
  border: 0;
  border-radius: 1.25rem;
  background: #2a3942;
  color: #e9edef;
  font-size: 0.9rem;
  line-height: 1.4;
}
.wa-panel__form textarea::placeholder { color: #8696a0; }
.wa-panel__form textarea:focus-visible { outline: 2px solid var(--wa); outline-offset: 0; }
.wa-send {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--wa);
  color: #0b141a;
  cursor: pointer;
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.wa-send:hover { background: #20bd5a; transform: scale(1.06); }
.wa-panel__foot {
  padding: 0.4rem 0.8rem 0.55rem;
  background: #202c33;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.04em;
  text-align: center;
  color: #8696a0;
}

@media (prefers-reduced-motion: reduce) {
  .wa-fab::before { animation: none; }
  .wa-fab, .wa-panel, .wa-fab svg, .wa-fab::after { transition: none; }
  .wa-bubble { animation: none; }
}
@media print {
  .wa-fab, .wa-panel { display: none !important; }
}

/* ==========================================================================
   v5 — comparison table, contact details, proof beside the ask
   ========================================================================== */

/* ---------- One operator vs agency vs in-house ---------- */
.vs {
  width: 100%;
  border-collapse: collapse;
  background: var(--ink-900);
  font-size: var(--t-small);
}
.vs th, .vs td {
  padding: 0.9rem 1.1rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
  line-height: 1.5;
}
.vs tbody th {
  font-family: var(--font-body);
  font-weight: 450;
  color: var(--bone);
  width: 11rem;
  background: var(--ink-850);
}
.vs td { color: var(--bone-faint); }
/* The middle column is mine: lifted, not shouting. */
.vs tbody tr:last-child th, .vs tbody tr:last-child td { border-bottom: 0; }
/* Below the table's natural width, each row becomes a small stacked card and
   the column headers are re-attached to each cell through data-label. */
@media (max-width: 860px) {
  .vs, .vs tbody, .vs tr, .vs td, .vs th { display: block; }
  .vs thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .vs tbody tr {
    margin-bottom: 0.75rem;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-lg);
    overflow: hidden;
  }
  .vs tbody th {
    width: auto;
    font-family: var(--font-mono);
    font-size: var(--t-micro);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--champagne);
  }
  .vs td { padding-top: 0.35rem; }
  .vs td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 0.15rem;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.06em;
    color: var(--bone-dim);
  }
  .vs tbody tr:last-child td:last-child { border-bottom: 0; }
}

/* ---------- Contact details in the footer ---------- */
.footer__contact { display: grid; gap: 0.55rem; align-content: start; }
.footer__contact li {
  display: grid;
  gap: 0.15rem;
  font-size: var(--t-small);
  color: var(--bone-dim);
}
.footer__contact span {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.footer__contact a { color: var(--bone); border-bottom: 1px solid var(--champagne-dim); transition: color var(--dur) var(--ease); }
.footer__contact a:hover { color: var(--champagne); }

/* ---------- Proof and terms around the submit button ---------- */
.form__proof {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.7rem;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--champagne-dim);
  border-radius: var(--radius);
  background: var(--ink-850);
  font-size: var(--t-small);
  color: var(--bone-dim);
}
.form__terms {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  color: var(--bone-faint);
}

/* ---------- Rendering cost of the long page ----------
   Far-below-fold sections are skipped until they approach the viewport.
   contain-intrinsic-size keeps the scrollbar honest before they render. */
@supports (content-visibility: auto) {
  #services, #process, #stack, #faq {
    content-visibility: auto;
    contain-intrinsic-size: auto 900px;
  }
}

/* Stacked comparison cards are the single longest block on a phone; this
   keeps every word but tightens the setting. */
@media (max-width: 860px) {
  .vs th, .vs td { padding: 0.55rem 0.9rem; line-height: 1.4; }
  .vs tbody th { padding-block: 0.6rem; }
  .vs td { font-size: 0.82rem; }
  .vs tbody tr { margin-bottom: 0.6rem; }
}

/* ==========================================================================
   v6 — profile at a glance (Clutch-style comparability)
   A buyer should be able to answer "what is this, on what terms, in what
   proportions" without reading prose.
   ========================================================================== */

.profile-facts { margin-top: 1.25rem; }
@media (min-width: 620px) and (max-width: 959px) { .profile-facts { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px) { .profile-facts { grid-template-columns: repeat(4, 1fr); } }
.profile-facts a { color: var(--champagne); }
.profile-facts a:hover { color: var(--champagne-lift); }

/* ---------- Focus breakdowns ---------- */
.focus-grid { display: grid; gap: clamp(1.5rem, 4vw, 3rem); margin-top: clamp(2rem, 4vw, 3rem); }
@media (min-width: 760px) { .focus-grid { grid-template-columns: 1fr 1fr; } }

.focus__title {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
  margin-bottom: 1rem;
}
.focus__list { display: grid; gap: 0.85rem; }
/* Each row: label, figure, and a decorative bar underneath. The figure is
   real text, so the numbers survive with CSS or images disabled. */
.focus__list > div {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 0.25rem 1rem;
}
.focus__list dt { font-size: var(--t-small); color: var(--bone); }
.focus__list dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-small);
  color: var(--champagne);
  font-variant-numeric: tabular-nums;
}
.focus__list i {
  grid-column: 1 / -1;
  height: 3px;
  border-radius: 2px;
  background: var(--ink-600);
  overflow: hidden;
  position: relative;
}
.focus__list i::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--pct, 0) * 1%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--champagne-dim), var(--champagne));
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 900ms var(--ease-out);
}
/* Bars draw only once their block scrolls in, staggered down the list. */
.focus.is-in .focus__list i::after,
.focus:not(.reveal) .focus__list i::after { transform: none; }
.focus.is-in .focus__list > div:nth-child(2) i::after { transition-delay: 90ms; }
.focus.is-in .focus__list > div:nth-child(3) i::after { transition-delay: 180ms; }
.focus.is-in .focus__list > div:nth-child(4) i::after { transition-delay: 270ms; }
.focus.is-in .focus__list > div:nth-child(5) i::after { transition-delay: 360ms; }

.focus__note {
  margin-top: 1.5rem;
  font-size: var(--t-small);
  color: var(--bone-faint);
  max-width: 62ch;
}

/* ---------- "Verified on Upwork" chip ---------- */
.verified {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--champagne-dim);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: var(--champagne);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.verified:hover { background: var(--accent-tint); color: var(--champagne-lift); }
.verified svg { flex: none; }

@media (max-width: 759px) {
  .profile-facts div { padding: 0.7rem 0.9rem; }
  .focus-grid { gap: 1.5rem; margin-top: 1.5rem; }
  .focus__list { gap: 0.65rem; }
  .focus__note { margin-top: 1rem; }
}

@media (prefers-reduced-motion: reduce) {
  .focus__list i::after { transform: none; transition: none; }
}

/* The Results line closing each case page. */
.cs-result {
  padding: 1rem 1.15rem;
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--champagne);
  border-radius: var(--radius);
  background: var(--ink-850);
  color: var(--bone-dim);
}
.cs-result b { font-family: var(--font-display); font-weight: 400; font-size: 1.2rem; color: var(--champagne); }

/* Keep the new profile block from undoing the mobile-length work. */
@media (max-width: 759px) {
  #profile { padding-block: 2.25rem; }
  .profile-facts div { padding: 0.55rem 0.75rem; gap: 0.15rem; }
  .profile-facts dd { font-size: 0.85rem; line-height: 1.35; }
  .profile-facts dt { font-size: 0.62rem; }
  .focus__title { margin-bottom: 0.7rem; }
  .focus__list { gap: 0.5rem; }
  .focus__list dt, .focus__list dd { font-size: 0.8rem; }
  .focus__note { font-size: var(--t-micro); }
}

/* Six fact fields divide evenly into three columns; four left two empty cells
   showing through at the end of the row. */
@media (min-width: 760px) { .cs-meta { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 960px) { .profile-facts { grid-template-columns: repeat(4, 1fr); } }

/* ==========================================================================
   Light theme — navy, grey, black, white
   Applied by [data-theme="light"] on <html>, set before first paint by the
   inline script in the <head>. Declared last so it wins over every earlier
   :root block. Contrast measured against the real values:
     text #091a33 on #fff 17.4:1 · secondary #35485f 9.4:1 · muted #55677e 5.8:1
     navy #10294f 14.5:1 · white on navy button 14.5:1 · borders #72859e 3.8:1
   ========================================================================== */
:root[data-theme='light'] {
  color-scheme: light;

  /* Surfaces: white page over cool blue-grey risers. Deliberately bluer than
     a neutral grey so the panels sit under the navy rather than beside it. */
  --ink-900: #ffffff;
  --ink-850: #f1f5fa;
  --ink-800: #e9f0f8;
  --ink-700: #dfe8f3;
  --ink-600: #cfdae8;

  /* Interactive borders meet the 3:1 needed for UI components; the soft one
     is for decorative hairlines only. */
  --line:      #72859e;
  --line-soft: #d7e1ee;

  /* Ink: navy-black rather than pure black, so it sits with the accent */
  --bone:       #091a33;
  --bone-dim:   #35485f;
  --bone-faint: #55677e;

  /* Navy carries what champagne carries in the dark theme */
  --champagne:      #10294f;
  --champagne-lift: #081c3a;
  --champagne-dim:  #8199bd;

  --star: #75590f;              /* gold would wash out on white */
  --ok:   #106030;
  --err:  #b3261e;

  --glow:          rgba(16, 41, 79, 0.10);
  --accent-soft:   rgba(16, 41, 79, 0.07);
  --accent-softer: rgba(16, 41, 79, 0.02);
  --accent-tint:   rgba(16, 41, 79, 0.10);
  --halo:          rgba(16, 41, 79, 0.10);
  --glass:         rgba(9, 26, 51, 0.03);
  --overlay:       rgba(255, 255, 255, 0.9);
  --bar-bg:        rgba(255, 255, 255, 0.93);
  --backdrop:      rgba(9, 26, 51, 0.55);
  --shadow-lg:     0 10px 30px rgba(9, 26, 51, 0.14);
  /* A white vignette would grey the portrait; keep it almost clear. */
  --vignette-a:    rgba(255, 255, 255, 0.10);
  --vignette-b:    rgba(255, 255, 255, 0.35);
  --grain:         0.02;   /* noise reads much louder on white */
  --ghost:         0.07;   /* …and the ghost numeral much fainter */
  --pulse:         rgba(16, 96, 48, 0.45);
}

/* ---------- Light-theme corrections where a dark assumption is baked in --- */

/* The overlay chips flip to white, so their text must flip to ink. */
:root[data-theme='light'] .case__thumb > span { color: var(--champagne); }

/* .btn and .site-header already resolve from tokens
   (--btn-fg is --ink-900, which is white here), so they need no overrides.
   .wa-send stays dark-on-green in both themes, like WhatsApp itself. */

/* The portrait was graded for a near-black canvas. */
:root[data-theme='light'] .portrait__frame img { filter: saturate(1) contrast(1) brightness(1.01); }

/* Marquee edges fade to the band colour, not to black. */
:root[data-theme='light'] .marquee__item { color: var(--bone-dim); }

/* The WhatsApp panel mirrors WhatsApp's own light theme rather than staying
   a dark slab on a white page. */
:root[data-theme='light'] .wa-panel { background: #efeae2; border-color: rgba(9, 26, 51, 0.12); }
:root[data-theme='light'] .wa-panel__body {
  background:
    radial-gradient(circle at 20% 20%, rgba(9, 26, 51, 0.04) 0 1px, transparent 1.5px) 0 0 / 18px 18px,
    #efeae2;
}
:root[data-theme='light'] .wa-bubble { background: #fff; color: #111b21; }
:root[data-theme='light'] .wa-bubble::before { border-top-color: #fff; }
:root[data-theme='light'] .wa-bubble time { color: #667781; }
:root[data-theme='light'] .wa-panel__form { background: #f0f2f5; }
:root[data-theme='light'] .wa-panel__form textarea { background: #fff; color: #111b21; }
:root[data-theme='light'] .wa-panel__form textarea::placeholder { color: #667781; }
:root[data-theme='light'] .wa-panel__foot { background: #f0f2f5; color: #667781; }
:root[data-theme='light'] .wa-quick button { color: #0b3d2c; background: rgba(37, 211, 102, 0.14); border-color: rgba(18, 140, 126, 0.5); }
:root[data-theme='light'] .wa-fab { box-shadow: 0 10px 28px rgba(9, 26, 51, 0.28); }
:root[data-theme='light'] .wa-fab:focus-visible { outline-color: var(--champagne); }

/* ==========================================================================
   Theme toggle
   ========================================================================== */
.theme-toggle {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 2.35rem;
  height: 2.35rem;
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  background: none;
  color: var(--bone-dim);
  cursor: pointer;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.theme-toggle:hover { color: var(--champagne); border-color: var(--champagne-dim); background: var(--accent-tint); }
.theme-toggle svg { width: 1.05rem; height: 1.05rem; }
/* The icon shows the action, not the current state: a sun while you are in
   the dark theme (tap for light), a moon while you are in the light one. */
.theme-toggle .i-moon { display: none; }
:root[data-theme='light'] .theme-toggle .i-moon { display: block; }
:root[data-theme='light'] .theme-toggle .i-sun { display: none; }
/* Sits left of the menu button on small screens, left of the CTA on large. */
.nav .theme-toggle { margin-left: auto; }
@media (min-width: 940px) { .nav .theme-toggle { margin-left: 0; } }

/* Colour changes are instant by default; a short crossfade stops the jolt.
   Only the properties that actually change, so nothing else is slowed. */
@media (prefers-reduced-motion: no-preference) {
  html.theme-anim,
  html.theme-anim body,
  html.theme-anim .site-header,
  html.theme-anim .cta-bar,
  html.theme-anim .wa-panel,
  html.theme-anim section,
  html.theme-anim .card,
  html.theme-anim .svc,
  html.theme-anim .pain,
  html.theme-anim .fit,
  html.theme-anim .stage,
  html.theme-anim .vs th,
  html.theme-anim .vs td {
    transition: background-color 320ms var(--ease), color 320ms var(--ease), border-color 320ms var(--ease);
  }
}

/* ==========================================================================
   v8 — verified work history
   ========================================================================== */

/* Verified work history, taken from the Upwork profile. */
.track {
  margin-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--line-soft);
  padding-top: clamp(1.5rem, 3vw, 2rem);
}
/* It lives inside the testimonial column, so it lines up with the quote. */
.testimonials .track { margin-left: calc(clamp(1.25rem, 3vw, 2.25rem) + 2px); }
.track__title {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
  margin-bottom: 1rem;
}
.track__list { display: grid; gap: 1.5rem; }
.track__list > li {
  display: grid;
  gap: 0.45rem;
  padding-left: clamp(0.9rem, 2vw, 1.25rem);
  border-left: 2px solid var(--line-soft);
  max-width: 54ch;
}
/* The history entries now read like the featured review above them: the words
   in the display face, the data in mono underneath. */
.track__job {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.05rem;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--bone);
}
.track__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--bone-faint);
}
.track__quote {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: 1.1rem;
  line-height: 1.45;
  letter-spacing: -0.005em;
  color: var(--bone-dim);
}
/* The third contract is the one quoted in full above, so it points there
   rather than printing the same thirty words twice in one column. */
.track__ref {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  color: var(--bone-faint);
}
/* The chips match the ones under the featured review: mono, small, uppercase. */
.track__tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.7rem;
  margin-top: 0.2rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bone-faint);
}
.track__endorsed {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--bone-faint);
}
.track__note { margin-top: 1rem; font-size: var(--t-micro); color: var(--bone-faint); }

/* ==========================================================================
   v10 — guides
   The article body reuses .cs-prose from the case pages; this adds only what
   long-form reading needs: a contents list, numbered steps, and a pull note.
   ========================================================================== */

/* Homepage teaser */
.guides__intro { margin: 0.75rem 0 1.25rem; color: var(--bone-dim); max-width: 60ch; }

/* Article */
.guide { max-width: 68ch; }
.guide > section { margin-bottom: 2.5rem; }
.guide h2 { scroll-margin-top: 6rem; }   /* the sticky header must not cover it */
.guide p { color: var(--bone-dim); }
.guide p + p { margin-top: 0.9rem; }
.guide b { color: var(--bone); font-weight: 500; }
.guide a { color: var(--champagne); border-bottom: 1px solid var(--champagne-dim); }
.guide a:hover { color: var(--champagne-lift); }
.guide .case__did { margin-top: 0.9rem; }
.guide .case__did li { color: var(--bone-dim); }

.guide__toc {
  margin-bottom: 2.5rem;
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  background: var(--ink-850);
}
.guide__toc-title {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
  margin-bottom: 0.6rem;
}
.guide__toc ol { display: grid; gap: 0.4rem; counter-reset: toc; }
.guide__toc li { counter-increment: toc; font-size: var(--t-small); }
.guide__toc li::before {
  content: counter(toc) '. ';
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--bone-faint);
}
.guide__toc a { color: var(--bone-dim); border-bottom: 0; }
.guide__toc a:hover { color: var(--champagne); }

.guide__steps { display: grid; gap: 0.75rem; margin-top: 0.9rem; counter-reset: gstep; }
.guide__steps > li {
  counter-increment: gstep;
  position: relative;
  padding-left: 2.2rem;
  min-height: 1.6rem;
  font-size: var(--t-small);
  color: var(--bone-dim);
  line-height: 1.55;
}
.guide__steps > li::before {
  content: counter(gstep);
  position: absolute;
  left: 0;
  top: 0;
  display: grid;
  place-items: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  border: 1px solid var(--champagne-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--champagne);
}

.guide__note {
  margin-top: 1.1rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--champagne);
  border-radius: var(--radius);
  background: var(--ink-850);
  font-size: var(--t-small);
  color: var(--bone-dim);
}

@media (max-width: 759px) {
  .guide__toc { padding: 0.9rem 1rem; margin-bottom: 1.75rem; }
  .guide > section { margin-bottom: 2rem; }
}

/* The guides teaser holds two cards, so it must not inherit the three column
   fit-grid, which would leave an empty panel at the end of the row. */
@media (min-width: 760px) {
  #guides .fit-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ==========================================================================
   v11 — depth behind the work cards, and page motion
   ========================================================================== */

/* ---------- The popup, now a mini case study ---------- */
.lb-detail {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line-soft);
}
.lb-detail h4 { margin-top: 1.25rem; }
.lb-detail h4:first-child { margin-top: 0; }
.lb-steps { display: grid; gap: 0.6rem; margin-top: 0.6rem; counter-reset: lbstep; }
.lb-steps > li {
  counter-increment: lbstep;
  position: relative;
  padding-left: 2rem;
  font-size: var(--t-small);
  color: var(--bone-dim);
  line-height: 1.55;
}
.lb-steps > li::before {
  content: counter(lbstep);
  position: absolute;
  left: 0;
  top: 0;
  display: grid;
  place-items: center;
  width: 1.45rem;
  height: 1.45rem;
  border-radius: 50%;
  border: 1px solid var(--champagne-dim);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  color: var(--champagne);
}
.lb-example {
  margin-top: 0.6rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--champagne);
  border-radius: var(--radius);
  background: var(--ink-850);
  font-size: var(--t-small);
  color: var(--bone-dim);
}
.lb-example p + p { margin-top: 0.6rem; }
.lb-example code {
  font-family: var(--font-mono);
  font-size: 0.82em;
  color: var(--champagne);
}
.lb-more { margin-top: 1.25rem; }

/* The popup opens with a little more life than a straight fade. */
.lightbox[open] .lightbox__media img { animation: lb-zoom 520ms var(--ease-out) backwards; }
.lightbox[open] .lightbox__body > * { animation: lb-rise 420ms var(--ease-out) backwards; }
.lightbox[open] .lightbox__body > *:nth-child(2) { animation-delay: 40ms; }
.lightbox[open] .lightbox__body > *:nth-child(3) { animation-delay: 80ms; }
.lightbox[open] .lightbox__body > *:nth-child(n+4) { animation-delay: 120ms; }
@keyframes lb-zoom { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: none; } }
@keyframes lb-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ---------- Capability pages ---------- */
.cap__note {
  padding: 0.9rem 1.1rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius-lg);
  background: var(--glass);
  font-size: var(--t-small);
  color: var(--bone-dim);
  margin-bottom: 2rem;
}
.cap { scroll-margin-top: 6rem; }
.cap h2 { margin-bottom: 0.75rem; }
.cap h3 {
  margin-top: 1.5rem;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
}
.cap__brief { color: var(--bone-dim); }
.cap__signals {
  margin-top: 1.25rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line-soft);
  font-size: var(--t-small);
  color: var(--bone-faint);
}
.cap__signals b { color: var(--bone-dim); font-weight: 450; }

/* A table inside prose needs to be able to scroll on a phone. */
.tablewrap { overflow-x: auto; margin-top: 0.6rem; }
.tablewrap .vs { min-width: 28rem; }

/* ---------- The flow diagram, drawn on scroll ---------- */
.flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0;
  margin-top: 2rem;
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  background: var(--ink-850);
  counter-reset: flowstep;
}
.flow > li {
  position: relative;
  display: flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.04em;
  color: var(--bone-dim);
}
.flow > li > span {
  display: inline-block;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--ink-900);
  white-space: nowrap;
}
.flow > li:last-child > span { border-color: var(--champagne-dim); color: var(--champagne); }
/* the connector between two steps */
.flow > li + li { margin-left: 1.6rem; }
.flow > li + li::before {
  content: '';
  position: absolute;
  right: 100%;
  top: 50%;
  width: 1.6rem;
  height: 1px;
  background: var(--champagne-dim);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* Nodes and connectors arrive in sequence once the diagram scrolls in. */
.flow.will-reveal > li > span { opacity: 0; transform: translateY(6px); }
.flow.is-in > li > span {
  opacity: 1;
  transform: none;
  transition: opacity 380ms var(--ease-out), transform 380ms var(--ease-out);
}
.flow.is-in > li + li::before { transform: scaleX(1); transition: transform 320ms var(--ease-out); }
.flow.is-in > li:nth-child(2) > span,
.flow.is-in > li:nth-child(2)::before { transition-delay: 160ms; }
.flow.is-in > li:nth-child(3) > span,
.flow.is-in > li:nth-child(3)::before { transition-delay: 320ms; }
.flow.is-in > li:nth-child(4) > span,
.flow.is-in > li:nth-child(4)::before { transition-delay: 480ms; }
.flow.is-in > li:nth-child(5) > span,
.flow.is-in > li:nth-child(5)::before { transition-delay: 640ms; }

/* ---------- Before and after wipe ---------- */
.wipe { margin-top: 0.6rem; }
.wipe__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.75rem;
  font-size: var(--t-small);
}
.wipe__before { color: var(--bone-faint); text-decoration: line-through; text-decoration-color: var(--line); }
.wipe__arrow { color: var(--champagne); font-family: var(--font-mono); }
.wipe__after { color: var(--bone); }
.wipe.will-reveal .wipe__after { opacity: 0; clip-path: inset(0 100% 0 0); }
.wipe.is-in .wipe__after {
  opacity: 1;
  clip-path: inset(0 0 0 0);
  transition: clip-path 700ms var(--ease-out) 200ms, opacity 300ms var(--ease) 200ms;
}
@media (max-width: 560px) {
  .wipe__row { grid-template-columns: 1fr; gap: 0.2rem; }
  .wipe__arrow { transform: rotate(90deg); justify-self: start; }
}

/* ---------- Section reveals on the sub pages ---------- */
.will-reveal { opacity: 0; transform: translateY(16px); }
.will-reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 600ms var(--ease), transform 600ms var(--ease);
}
/* The flow and wipe animate their own children, so the container itself
   must not also slide, or the two movements fight each other. */
.flow.will-reveal, .wipe.will-reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .lightbox[open] .lightbox__media img,
  .lightbox[open] .lightbox__body > * { animation: none; }
  .will-reveal, .will-reveal.is-in { opacity: 1; transform: none; transition: none; }
  .flow > li > span { opacity: 1; transform: none; }
  .flow > li + li::before { transform: scaleX(1); }
  .wipe__after { opacity: 1; clip-path: none; }
}

/* Service tile headings that link to their capability page. */
.svc__link { color: inherit; }
.svc__link:hover { color: var(--champagne-lift); }

/* ==========================================================================
   v12 — the concept popup becomes a written piece, not an image with notes
   ========================================================================== */

/* One column, one readable measure. The sample image is dropped for these
   pieces: a picture of a concept proves nothing the writing does not. */
@media (min-width: 900px) {
  .lightbox--doc .lightbox__inner { grid-template-columns: minmax(0, 1fr); align-items: start; }
}
.lightbox--doc .lightbox__inner { max-width: 54rem; align-content: start; }

/* The close button is fixed at the top right of the viewport. Below about
   900px the first line of the panel ran underneath it, so the panel starts
   lower than the button ends. */
@media (max-width: 899px) {
  .lightbox__inner { padding-top: 5.5rem; }
}
.lightbox--doc .lightbox__body { align-content: start; gap: 0.75rem; }

.lb-lead {
  font-size: var(--t-body);
  color: var(--bone);
  max-width: 46rem;
}

/* Each block of the write-up, separated by a rule rather than by guesswork. */
.lb-sec {
  padding-top: 1.35rem;
  margin-top: 0.5rem;
  border-top: 1px solid var(--line-soft);
}
.lb-sec:first-child { border-top: none; padding-top: 0; }
.lb-sec > h4 { margin-top: 0; margin-bottom: 0.6rem; }
.lb-sec > p { max-width: 46rem; }

/* The scene: the concrete version of the brief, set apart so it reads as the
   illustration it is. */
.lb-scene {
  margin-top: 0.7rem;
  padding-left: 1rem;
  border-left: 2px solid var(--champagne-dim);
  font-size: var(--t-small);
  color: var(--bone-dim);
  font-style: normal;
}

.lb-detail .lb-sec ul { display: grid; gap: 0.1rem; }
.lb-wrong li::before { content: '\00d7'; color: var(--champagne-dim); }

.lb-signals {
  margin-top: 1.35rem;
  padding: 0.85rem 1.05rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  font-size: var(--t-small);
  color: var(--bone-faint);
}
.lb-signals b { color: var(--bone-dim); font-weight: 450; }

/* Two columns of prose would be unreadable, so only the two short lists pair
   up. Everything else keeps the full measure. */
@media (min-width: 1100px) {
  .lightbox--doc .lb-detail {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 2.5rem;
    align-items: start;
  }
  .lightbox--doc .lb-detail > * { grid-column: 1 / -1; }
  .lightbox--doc .lb-detail > .lb-sec--half { grid-column: span 1; }
}

/* ---------- The same additions on the capability pages ---------- */
.cap__scene {
  padding-left: 1rem;
  border-left: 2px solid var(--champagne-dim);
  color: var(--bone-dim);
  font-size: var(--t-small);
}
.cap__after { color: var(--bone-dim); }
.cap__wrong { display: grid; gap: 0.15rem; margin-top: 0.4rem; }
.cap__wrong li {
  display: flex;
  gap: 0.6rem;
  font-size: var(--t-small);
  color: var(--bone-dim);
  padding-block: 0.3rem;
}
.cap__wrong li::before { content: '\00d7'; color: var(--champagne-dim); flex: none; }

/* ==========================================================================
   v15 — the client cases as an auto-advancing slider
   Built on scroll-snap, so without JavaScript it is still a swipeable row.
   The script only adds the controls and the timer.
   ========================================================================== */

.cases-wrap { position: relative; }

/* The track. One case fills the frame; the rest wait either side. */
.cases {
  display: flex;
  gap: 0;
  align-items: stretch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
  background: var(--line-soft);
  border-block: 1px solid var(--line-soft);
}
.cases::-webkit-scrollbar { display: none; }

.cases > .case {
  flex: 0 0 100%;
  min-width: 0;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

/* The slide that is showing gets the lift; the others sit flat, so the
   background does not flicker as the track moves. */
.cases > .case:hover { background: var(--ink-900); }
.cases-wrap:hover .case.is-current { background: var(--ink-850); }

@media (min-width: 1100px) {
  /* Replaces the old 2-up grid: one case at a time, framed like a card. */
  .cases {
    max-width: calc(var(--shell) - var(--gutter) * 2);
    margin-inline: auto;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-lg);
    overflow: hidden;
    overflow-x: auto;
  }
  .cases > .case { padding: 0; }
  .cases > .case > .shell { max-width: none; padding: clamp(1.75rem, 2.5vw, 2.5rem); }
}

/* ---------- Controls ---------- */
.cases__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 1.5rem;
}
.cases__btn {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--bone-dim);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.cases__btn:hover { border-color: var(--champagne); color: var(--champagne); }
.cases__btn:focus-visible { outline: 2px solid var(--champagne); outline-offset: 2px; }
.cases__btn svg { width: 1.05rem; height: 1.05rem; }

.cases__dots { display: flex; align-items: center; gap: 0.45rem; }
.cases__dot {
  width: 0.5rem;
  height: 0.5rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), width var(--dur) var(--ease);
}
.cases__dot[aria-current='true'] {
  width: 1.4rem;
  border-radius: 999px;
  background: var(--champagne);
  border-color: var(--champagne);
}
.cases__dot:focus-visible { outline: 2px solid var(--champagne); outline-offset: 3px; }

/* The count, so a visitor knows how many there are without counting dots. */
.cases__count {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  color: var(--bone-faint);
  min-width: 4.5ch;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* The progress line under the frame: how long until the next slide. */
.cases__timer {
  height: 2px;
  margin-top: 1.25rem;
  background: var(--line-soft);
  overflow: hidden;
}
.cases__timer i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--champagne-dim);
  transform-origin: 0 50%;
  transform: scaleX(0);
}
.cases__timer.is-running i { animation: casesTick var(--cases-interval, 5s) linear forwards; }
@keyframes casesTick { from { transform: scaleX(0); } to { transform: scaleX(1); } }

@media (max-width: 599px) {
  .cases__nav { gap: 0.5rem; }
  .cases__btn { width: 2.25rem; height: 2.25rem; }
}

/* Auto-advance is movement that starts on its own, so it stops entirely when
   the visitor has asked for less motion. The buttons still work. */
@media (prefers-reduced-motion: reduce) {
  .cases { scroll-behavior: auto; }
  .cases__timer { display: none; }
  .cases__dot { transition: none; }
}
