@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Hanken+Grotesk:wght@400;700&family=Instrument+Serif:ital,wght@1,400&display=swap');

/* ---------- Tokens ---------- */
:root {
  --color-bg: #0A0A0A;
  --color-bg-alt: #161616;
  --color-ink: #F4F4F4;
  --color-ink-soft: #B4B4B6;
  --color-ink-faint: #737375;
  --color-accent: #6E85FF;
  --color-accent-soft: #9FB1FF;
  --color-border: #262626;
  --color-dark: #000000;
  --color-dark-ink: #FFFFFF;
  --color-dark-ink-soft: #A0A0A2;
  --color-dark-border: #232323;

  --font-display: 'Bebas Neue', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-sans: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-accent: 'Instrument Serif', Georgia, serif;
  --weight-regular: 400;
  --weight-bold: 700;
  --dot-color: rgba(255, 255, 255, 0.07);

  --text-hero: clamp(2.75rem, 1.5rem + 5.5vw, 6.75rem);
  --text-h1: clamp(2.25rem, 1.4rem + 3.5vw, 4.25rem);
  --text-h2: clamp(1.75rem, 1.3rem + 2vw, 2.75rem);
  --text-h3: clamp(1.25rem, 1.05rem + 0.8vw, 1.625rem);
  --text-lg: clamp(1.125rem, 1.05rem + 0.3vw, 1.375rem);
  --text-body: 1rem;
  --text-sm: 0.875rem;
  --text-xs: 0.75rem;

  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-sm: 1.25rem;
  --space-md: 2rem;
  --space-lg: 3.5rem;
  --space-xl: 5.5rem;
  --space-2xl: 8.5rem;
  --space-3xl: 12rem;

  --container-max: 90rem;
  --gutter: clamp(1.25rem, 3vw, 3rem);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 0.25s;
  --dur-base: 0.5s;
  --dur-slow: 0.9s;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--color-ink);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, picture, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

/* No OS cursor anywhere — replaced site-wide by the custom 30px circle
   (and, over a linked image, the client/View Work label) from
   initCustomCursor() in main.js. !important so it wins over any
   element-specific cursor:pointer. */
*, a, button, input, textarea, select { cursor: none !important; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, textarea { font: inherit; color: inherit; }
ul { list-style: none; padding: 0; }
h1, h2, h3, h4 { font-weight: var(--weight-bold); line-height: 1.05; letter-spacing: -0.01em; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

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

/* ---------- Layout ---------- */
.wrap {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
/* Explicit background (matching what it already inherited from body) so a
   bare .section stays opaque when used as a stack-cover above the fixed
   pinned hero — z-index alone doesn't hide content behind a transparent
   layer, only paint order. */
.section { padding-block: var(--space-2xl); background: var(--color-bg); }
.section--tight { padding-block: var(--space-xl); }
.section--dark {
  background: var(--color-dark);
  color: var(--color-dark-ink);
}
.section--alt { background: var(--color-bg-alt); }

/* Full section inversion: white surface within an otherwise dark site.
   Re-declares the shared role tokens so every nested component
   (buttons, eyebrows, borders, media placeholders) re-themes itself. */
.section--light {
  --color-bg: #FFFFFF;
  --color-bg-alt: #F2F2F2;
  --color-ink: #0A0A0A;
  --color-ink-soft: #4A4A4C;
  --color-ink-faint: #8A8A8C;
  --color-accent: #2E42E0;
  --color-accent-soft: #4E5FE8;
  --color-border: #E3E3E3;
  --dot-color: rgba(10, 10, 10, 0.06);
  background: var(--color-bg);
  color: var(--color-ink);
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent);
}
.eyebrow::before {
  content: '';
  width: 1.5em;
  height: 1px;
  background: currentColor;
}
.section--dark .eyebrow { color: var(--color-accent-soft); }

/* ---------- Typography ---------- */
.type-hero {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);
  text-transform: uppercase;
  font-size: var(--text-hero);
  line-height: 0.92;
  letter-spacing: 0.01em;
}
.type-h1 { font-family: var(--font-display); font-weight: var(--weight-regular); text-transform: uppercase; letter-spacing: 0.01em; font-size: var(--text-h1); }
.type-h2 { font-family: var(--font-display); font-weight: var(--weight-regular); text-transform: uppercase; letter-spacing: 0.01em; font-size: var(--text-h2); }
.type-h3 { font-family: var(--font-display); font-weight: var(--weight-regular); text-transform: uppercase; letter-spacing: 0.02em; font-size: var(--text-h3); }
.type-lg { font-size: var(--text-lg); font-weight: 400; line-height: 1.5; color: var(--color-ink-soft); }
.type-body { font-size: var(--text-body); color: var(--color-ink-soft); }
.measure { max-width: 38rem; }

/* Word-level emphasis inside display headlines: breaks both the
   font and the all-caps pattern, so use it on a phrase, not a whole line. */
.accent {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  font-size: 1.08em;
}

/* ---------- Buttons / links ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.95rem 1.75rem;
  border-radius: 100px;
  background: var(--color-ink);
  color: var(--color-bg);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: 0.01em;
  transition: background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.btn:hover { background: var(--color-accent); transform: translateY(-2px); }
.btn--ghost {
  background: transparent;
  color: var(--color-ink);
  border: 1px solid var(--color-border);
}
.btn--ghost:hover { background: var(--color-ink); color: var(--color-bg); border-color: var(--color-ink); }
.section--dark .btn--ghost { border-color: var(--color-dark-border); color: var(--color-dark-ink); }
.section--dark .btn--ghost:hover { background: var(--color-dark-ink); color: var(--color-dark); }

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  padding-bottom: 0.2rem;
  border-bottom: 1px solid currentColor;
}
.link-arrow svg { width: 14px; height: 14px; transition: transform var(--dur-fast) var(--ease-out); }
.link-arrow:hover svg { transform: translateX(4px); }

/* ---------- Header / Nav ---------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem var(--gutter);
  mix-blend-mode: difference;
}
.site-header * { color: #fff; }
.logo {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);
  text-transform: uppercase;
  font-size: 1.3rem;
  letter-spacing: 0.03em;
}
/* Combination-lock / split-flap hover effect — see initLogoLock() in main.js.
   Each character position is a fixed-width, overflow-hidden "slot" containing
   a vertical "track" of stacked frames; animating the track's translateY
   scrolls one frame into view at a time, like a rotating lock wheel. */
.logo-lock {
  display: inline-flex;
  align-items: flex-start;
  letter-spacing: normal; /* the dedicated space-slot supplies the gap instead */
  line-height: 1;
}
.logo-slot {
  display: inline-block;
  overflow: hidden;
  position: relative;
  height: 1em;
  line-height: 1;
  vertical-align: top;
  flex: none;
}
.logo-track {
  display: flex;
  flex-direction: column;
  will-change: transform;
}
.logo-frame {
  height: 1em;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.nav-primary {
  display: flex;
  gap: clamp(1.25rem, 2vw, 2.5rem);
}
.nav-primary a, .nav-cta {
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  position: relative;
}
.nav-primary a::after {
  content: '';
  position: absolute;
  left: 0; right: 100%;
  bottom: -4px;
  height: 1px;
  background: currentColor;
  transition: right var(--dur-fast) var(--ease-out);
}
.nav-primary a:hover::after, .nav-primary a[aria-current="page"]::after { right: 0; }
.nav-toggle { display: none; }

@media (max-width: 56rem) {
  .nav-primary { display: none; }
  .nav-toggle {
    display: inline-flex;
    flex-direction: column;
    gap: 5px;
    padding: 0.5rem;
  }
  .nav-toggle span { width: 22px; height: 1px; background: #fff; }
}

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: var(--color-dark);
  color: var(--color-dark-ink);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--gutter);
  transform: translateY(-100%);
  transition: transform var(--dur-base) var(--ease-in-out);
}
.mobile-menu.is-open { transform: translateY(0); }
.mobile-menu a {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  font-size: clamp(2.25rem, 9vw, 3.5rem);
  padding-block: 0.4rem;
  display: block;
}

/* ---------- Footer ----------
   Fixed and pinned behind every section (see initFooterReveal() in
   main.js) — the footer sits there the whole time, only becoming
   visible once .footer-reveal-spacer (a plain in-flow element sized to
   match the footer's own height) scrolls past at the very end of the
   page.

   z-index can't be static here. The pinned hero is position:fixed,
   opaque, and spans the full viewport height FOREVER — at every scroll
   position, not just at the top — so its box and the footer's box
   always spatially overlap in the bottom slice of the screen. If the
   footer permanently outranked the hero, it would bleed through that
   overlap even while the hero is meant to be showing, right at page
   load; if the hero permanently outranked the footer, the footer could
   never win at the bottom either, since the hero never goes away.
   initFooterReveal() toggles .is-revealed only once the reveal spacer
   has actually scrolled into view, so the footer stays hidden behind
   the hero everywhere except that final stretch. */
.site-footer {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 0;
  background: var(--color-dark);
  color: var(--color-dark-ink);
  padding-block: var(--space-xl) var(--space-md);
}
/* Above the hero (1), below real content (.stack-cover, 3) — only ever
   applied once the reveal spacer is actually on screen. */
.site-footer.is-revealed { z-index: 2; }
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: var(--space-md);
  padding-bottom: var(--space-lg);
  border-bottom: 1px solid var(--color-dark-border);
}
.footer-grid h4 {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-dark-ink-soft);
  margin-bottom: var(--space-sm);
  font-weight: var(--weight-bold);
}
.footer-grid a, .footer-grid p { font-size: var(--text-sm); color: var(--color-dark-ink); }
.footer-grid li + li { margin-top: 0.6rem; }
.footer-grid a { opacity: 0.85; transition: opacity var(--dur-fast) var(--ease-out); }
.footer-grid a:hover { opacity: 1; color: var(--color-accent-soft); }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: var(--space-md);
  font-size: var(--text-xs);
  color: var(--color-dark-ink-soft);
  flex-wrap: wrap;
  gap: 0.75rem;
}
.footer-badge-group { display: flex; align-items: center; gap: 0.85rem; }
/* No CSS clip here — the badge SVG's own transparent margin (verified
   pixel-by-pixel) handles the circular edge. A hard border-radius clip was
   tried and reverted: since the orbiting text projects outward past the
   circle path, any box-shaped clip tight enough to look "circular" ends up
   cutting into the text itself. */
.footer-badge { width: 78.2px; height: 78.2px; flex: none; opacity: 0.9; }

@media (max-width: 56rem) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

/* ---------- Loader ---------- */
.loader {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--color-dark);
  color: var(--color-dark-ink);
  display: flex;
  align-items: center;
  justify-content: center;
}
.loader-mark {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);
  text-transform: uppercase;
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  letter-spacing: 0.04em;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  opacity: 0;
}
.loader-rule {
  width: 64px;
  height: 1px;
  background: var(--color-accent-soft);
  transform: scaleX(0);
  transform-origin: left;
}

/* ---------- Reveal / media ---------- */
[data-reveal] { opacity: 0; }
.media {
  position: relative;
  overflow: hidden;
  border-radius: 2px;
  background: var(--color-bg-alt);
}
.media img { width: 100%; height: 100%; object-fit: cover; filter: blur(18px); transform: scale(1.05); transition: filter 0.9s var(--ease-out), transform 0.9s var(--ease-out); }
.media img.is-loaded { filter: blur(0); transform: scale(1); }
/* Escape hatch for images that must show in full (e.g. website screenshots) —
   overrides any aspect-ratio/object-fit cropping from a parent context. */
.media--full { aspect-ratio: auto !important; }
.media--full img { position: static; height: auto !important; object-fit: contain !important; }
.media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.media--full video { position: static; height: auto !important; object-fit: contain !important; }
.media-block {
  width: 100%;
  height: 100%;
  background: linear-gradient(155deg, var(--color-bg-alt), var(--color-border));
  position: relative;
}
.media-block::after {
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(circle at 1px 1px, var(--dot-color) 1px, transparent 0);
  background-size: 3px 3px;
}

/* ---------- Grid utilities ---------- */
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-md); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md); }
@media (max-width: 56rem) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
}

/* ---------- Hero ---------- */
.hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: 6rem;
  position: relative;
}
.hero-eyebrow { margin-bottom: var(--space-md); }
.hero-actions {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}
.hero-sub { margin-top: var(--space-sm); }
.scroll-cue {
  position: absolute;
  bottom: var(--space-md);
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
}
.scroll-cue::after {
  content: '';
  width: 1px;
  height: 34px;
  background: var(--color-ink-faint);
  animation: scrollcue 2.2s var(--ease-in-out) infinite;
}
@keyframes scrollcue {
  0% { transform: scaleY(0); transform-origin: top; }
  50% { transform: scaleY(1); transform-origin: top; }
  50.001% { transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}

/* ---------- Section heads ---------- */
.section-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-md);
  margin-bottom: var(--space-lg);
}

/* ---------- Work tiles ---------- */
.work-list { display: flex; flex-direction: column; }
.work-tile {
  display: grid;
  grid-template-columns: 2fr 3fr;
  gap: var(--space-md);
  align-items: center;
  padding-block: var(--space-md);
  border-top: 1px solid var(--color-border);
  transition: opacity var(--dur-fast) var(--ease-out);
}
.work-list:hover .work-tile { opacity: 0.45; }
.work-tile:hover { opacity: 1 !important; }
.work-list .work-tile:last-child { border-bottom: 1px solid var(--color-border); }
.work-tile-title { font-family: var(--font-display); font-weight: var(--weight-regular); text-transform: uppercase; letter-spacing: 0.01em; font-size: var(--text-h2); }
.work-tile-meta { display: flex; flex-direction: column; gap: 0.75rem; }
.work-tile-num { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-accent); }
.work-tile-tags { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-ink-faint); }
.work-tile-obj { color: var(--color-ink-soft); max-width: 26rem; }
.work-tile .media { aspect-ratio: 4 / 3; }
/* No lift-on-hover here — the curtain thumbnail (all three featured
   projects) is its own attention-grabbing transition; the bump read as an
   extra, unwanted jump on top of it. */

@media (max-width: 56rem) {
  .work-tile { grid-template-columns: 1fr; }
}

/* ---------- Client logo marquee (scrolling, infinite) ---------- */
.logo-marquee {
  overflow: hidden;
  width: 100%;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.logo-marquee-track {
  display: flex;
  align-items: center;
  gap: clamp(3rem, 6vw, 5.5rem);
  width: max-content;
  animation: logo-marquee-scroll 32s linear infinite;
}
.logo-marquee-track img {
  height: clamp(22px, 2.6vw, 34px);
  width: auto;
  flex: none;
  opacity: 0.8;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.logo-marquee:hover .logo-marquee-track img { opacity: 0.8; }
.logo-marquee-track img:hover { opacity: 1; }
@keyframes logo-marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .logo-marquee-track { animation: none; }
}

/* ---------- Process ---------- */
.process-list { display: flex; flex-direction: column; }
.process-item {
  display: grid;
  grid-template-columns: 5rem 1fr 2fr;
  gap: var(--space-md);
  padding-block: var(--space-md);
  border-top: 1px solid var(--color-dark-border);
}
.process-list .process-item:last-child { border-bottom: 1px solid var(--color-dark-border); }
.process-num { font-family: var(--font-mono); color: var(--color-accent-soft); font-size: var(--text-sm); }
.process-item h3 { font-size: var(--text-h3); }
.process-item p { color: var(--color-dark-ink-soft); max-width: 32rem; }
@media (max-width: 56rem) {
  .process-item { grid-template-columns: 1fr; gap: var(--space-xs); }
}

/* ---------- Services ---------- */
.service-item {
  padding-block: var(--space-md);
  border-top: 1px solid var(--color-border);
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: var(--space-md);
}
.service-list .service-item:last-child { border-bottom: 1px solid var(--color-border); }
.service-item p { max-width: 34rem; }
@media (max-width: 56rem) {
  .service-item { grid-template-columns: 1fr; gap: var(--space-xs); }
}

/* ---------- Testimonials ---------- */
.testimonial-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-xl) var(--space-lg); }
.testimonial { display: flex; flex-direction: column; }
.testimonial-photo {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--color-bg-alt);
  margin-bottom: 1.25rem;
}
.testimonial-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.testimonial blockquote {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 400;
  line-height: 1.35;
  margin-bottom: var(--space-sm);
}
.testimonial cite { font-style: normal; font-size: var(--text-sm); color: var(--color-ink-faint); }
.testimonial cite a { color: var(--color-ink); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--color-border); transition: text-decoration-color var(--dur-fast) var(--ease-out); }
.testimonial cite a:hover { text-decoration-color: currentColor; }
@media (max-width: 64rem) {
  .testimonial-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 40rem) {
  .testimonial-grid { grid-template-columns: 1fr; }
}

/* ---------- Stats ---------- */
.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md); }
.stat-num { font-family: var(--font-display); font-weight: var(--weight-regular); letter-spacing: 0.01em; font-size: var(--text-h1); color: var(--color-accent-soft); }
.stat-label { color: var(--color-ink-soft); margin-top: 0.5rem; }
@media (max-width: 56rem) {
  .stat-row { grid-template-columns: 1fr; gap: var(--space-lg); }
}

/* ---------- CTA band ---------- */
/* Needs its own opaque background — it sits above the fixed pinned hero
   (via stack-cover) but z-index alone doesn't hide anything behind a
   transparent layer, so the hero's own text was bleeding through. */
.cta-band { text-align: center; padding-block: var(--space-2xl); background: var(--color-bg); }
.cta-band .type-h1 { max-width: 46rem; margin-inline: auto; }
.cta-band .hero-actions { justify-content: center; }

/* ---------- Case study ---------- */
.case-hero { padding-top: 8rem; }
.case-meta {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-md);
  padding-block: var(--space-lg);
  margin-top: var(--space-lg);
  border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}
.case-meta h4 {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
  font-weight: var(--weight-bold);
  margin-bottom: 0.5rem;
}
.case-block { display: grid; grid-template-columns: 1fr 2fr; gap: var(--space-md); }
/* Divider between separate brandmarks on the Selected Brandmarks page. */
.case-block--brand-start { padding-top: var(--space-xl); border-top: 1px solid var(--color-border); }

/* Logo reveal inside a gallery pair — keeps the mark fully visible (never
   cropped) and gives it generous breathing room within the grey frame,
   rather than filling the box edge to edge like a photo would. */
.case-logo-reveal img { object-fit: contain; padding: var(--space-xl); }
@media (max-width: 56rem) {
  .case-logo-reveal img { padding: var(--space-lg); }
}
.case-block h3 { position: sticky; top: 8rem; }
.case-full .media { aspect-ratio: 16 / 10; margin-block: var(--space-lg); }
.case-tiger-mark { display: flex; justify-content: center; margin-block: var(--space-2xl); }
.case-tiger-mark img { width: 100%; max-width: 14rem; height: auto; }
.case-pull {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: 400;
  line-height: 1.25;
  max-width: 44rem;
  margin: var(--space-xl) auto;
  text-align: center;
}
.case-nav {
  display: flex;
  justify-content: space-between;
  padding-block: var(--space-lg);
  border-top: 1px solid var(--color-border);
}

/* Multi-image galleries inside a case study body */
.case-gallery {
  display: grid;
  gap: var(--space-md);
  margin-block: var(--space-lg);
}
.case-gallery--2 { grid-template-columns: repeat(2, 1fr); }
.case-gallery--3 { grid-template-columns: repeat(3, 1fr); }
.case-gallery--4 { grid-template-columns: repeat(4, 1fr); }
.case-gallery .media { aspect-ratio: 4 / 3; }

/* Grid of logo mark variants — light card per mark, image shown in full
   (never cropped) since these are transparent-background vector marks. */
.case-logo-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-md);
  margin-block: var(--space-lg);
}
.case-logo-card {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  padding: var(--space-lg);
  background: var(--color-bg-alt);
  border-radius: 4px;
}
.case-logo-card img { width: 100%; height: 100%; object-fit: contain; }
@media (max-width: 56rem) {
  .case-gallery--4 { grid-template-columns: repeat(2, 1fr); }
  .case-logo-grid { grid-template-columns: repeat(2, 1fr); }
}

/* A single demo asset (e.g. a logo animation) shown at its own
   proportions rather than cropped to the standard media aspect-ratio. */
.case-demo {
  max-width: 26rem;
  margin: var(--space-lg) auto;
  padding: var(--space-lg);
  background: var(--color-bg-alt);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.case-demo img { width: 100%; height: auto; display: block; filter: none; transform: none; }

/* ---------- Brand story title card ---------- */
.case-story {
  position: relative;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  padding-inline: var(--gutter);
  text-align: center;
  padding-block: var(--space-2xl);
  overflow: hidden;
}
.case-story .eyebrow { position: relative; z-index: 1; justify-content: center; }
.case-story h2 {
  position: relative;
  z-index: 1;
  max-width: 100%;
  margin: 1.5rem auto 0;
  font-family: var(--font-accent);
  font-weight: 400;
  font-style: italic;
  text-transform: none;
  letter-spacing: 0;
  font-size: calc(var(--text-hero) * 1.08);
  line-height: 0.98;
}
/* The line divider, used as a slow-moving backdrop behind the title.
   .case-story is centered on the viewport (via the ancestor .wrap), so
   left:50% + translateX(-50%) lands on the true viewport centre even
   though this box is positioned absolutely inside a narrower parent. */
.case-story .case-divider {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100vw;
  margin: 0;
  transform: translate(-50%, -50%);
  z-index: 0;
  pointer-events: none;
}

/* ---------- (x) + (x) = (y) rationale ----------
   Flexbox, not a fixed column grid — some case studies have 3 terms
   (x + x = y), others 4 (x + x + x = y). A grid template sized for exactly
   3 items would wrap the 4th term into a second row using mismatched
   column widths (an operator column stretching to fit an image, an image
   column squeezed to fit an operator). Flex-wrap sidesteps that: every
   item gets the same capped width regardless of how many terms there are. */
.case-rationale {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin-block: var(--space-2xl);
}
.case-rationale-item { text-align: center; flex: 1 1 12rem; max-width: 16rem; }
.case-rationale-item .media { aspect-ratio: 1 / 1; border-radius: 4px; }
.case-rationale-item h4 {
  margin-top: 1rem;
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  color: var(--color-ink-faint);
}
.case-rationale-op {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: var(--text-h1);
  color: var(--color-ink-faint);
  text-align: center;
}

/* ---------- Illustration grid ----------
   5 columns. The first (hero) item spans 2 cols x 2 rows at its original
   size; auto-placement fills the remaining 3x2 block beside it (2 rows of 3),
   then everything after flows 5-per-row. Marks are shown in full (never
   cropped into circles) — the illustrations are hand-drawn artwork, not
   avatar-style thumbnails. */
.case-illustrations {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-xs);
  margin-block: var(--space-2xl);
}
.case-illustrations-item {
  aspect-ratio: 1 / 1;
  background: var(--color-bg-alt);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-sm);
}
.case-illustrations-item--hero { grid-column: span 2; grid-row: span 2; }
.case-illustrations-item img { width: 100%; height: 100%; object-fit: contain; display: block; }
@media (max-width: 40rem) {
  .case-illustrations { grid-template-columns: repeat(3, 1fr); }
  .case-illustrations-item--hero { grid-column: span 2; grid-row: span 2; }
}

/* ---------- Decorative line divider (full-bleed, scroll-drawn) ---------- */
.case-divider {
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  margin-block: var(--space-xl);
  overflow: hidden;
}
.case-divider img {
  width: 100%;
  display: block;
  clip-path: inset(0 100% 0 0);
}

/* ---------- Colour palette (scroll-grow reveal, once) ---------- */
.case-palette {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  height: 100vh;
  height: 100svh;
  margin-block: var(--space-2xl);
}
.case-swatch {
  flex: 1;
  height: 100%;
  border-radius: 4px 4px 0 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.case-swatch-main { height: 100%; flex-shrink: 0; position: relative; }
.case-swatch-info { position: absolute; left: 1.5rem; right: 1.5rem; bottom: 1.5rem; }
.case-swatch-name {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: var(--text-h3);
}
.case-swatch-hex {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-top: 0.35rem;
  opacity: 0.75;
}

/* ---------- Colour palette (hue-shift reveal) ----------
   Bands sit at fixed, equal-width positions from the start (never move)
   and hue-shift in place, one at a time, as the section scrolls — see
   initHueShiftPalette() in main.js. Full-bleed (breaks out of .wrap)
   since it's a pinned, viewport-filling takeover. */
.case-hue-wrap {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  margin-top: var(--space-2xl);
  margin-bottom: var(--space-2xl);
  height: 400vh;
  position: relative;
}
.case-hue-pin { position: sticky; top: 0; height: 100vh; overflow: hidden; }
.chp-band { position: absolute; top: 0; height: 100%; display: flex; align-items: center; justify-content: flex-start; }
.chp-label { text-align: left; padding: var(--space-lg) var(--space-md); transition: opacity 0.3s ease, color 0.3s ease; }
.chp-name {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: clamp(0.85rem, 1.4vw, 1.15rem);
  line-height: 1.1;
}
.chp-details {
  margin-top: 0.75rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.02em;
}
.chp-details p { margin-top: 0.3rem; }
.chp-details span { opacity: 0.6; margin-right: 0.4em; text-transform: uppercase; }
.chp-pantone-note {
  position: absolute;
  bottom: var(--space-md);
  left: var(--space-md);
  font-size: 0.6rem;
  opacity: 0.5;
  color: #fff;
  mix-blend-mode: difference;
}

/* ---------- Typography specimen ---------- */
.case-type {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  gap: var(--space-lg);
  margin-block: var(--space-2xl);
  padding: var(--space-xl) var(--space-lg) calc(var(--space-xl) * 1.1);
  background: var(--color-bg-alt);
  border-radius: 4px;
  overflow: hidden;
}
.case-type-content { flex: 1 1 auto; min-width: 0; }
/* A big specimen glyph filling the empty space to the right of the text
   block — font-family is set inline per project to match that project's
   own specimen typeface. */
.case-type-aa {
  flex: none;
  display: flex;
  align-items: center;
  margin: 0;
  padding-inline: var(--space-sm);
  font-size: clamp(8rem, 28vw, 24rem);
  line-height: 1;
  color: var(--color-ink);
  opacity: 0.08;
}
@media (max-width: 56rem) {
  .case-type { flex-direction: column; }
  .case-type-aa { display: none; }
}
.case-type-meta {
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  color: var(--color-accent);
  margin-bottom: 1.75rem;
}
.case-type-sample {
  font-family: 'Lora', serif;
  font-size: clamp(1.5rem, 3.6vw, 2.75rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  max-width: 22ch;
  margin-bottom: var(--space-lg);
}
.case-type-alphabet {
  font-family: 'Lora', serif;
  font-size: clamp(0.8rem, 1.35vw, 1rem);
  line-height: 1.9;
  letter-spacing: 0.02em;
  color: var(--color-ink-soft);
  margin-bottom: var(--space-md);
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-border);
  word-spacing: 0.2em;
}
.case-type-quote {
  font-family: 'Lora', serif;
  font-style: italic;
  font-size: var(--text-lg);
  line-height: 1.5;
  color: var(--color-ink-soft);
  max-width: 36rem;
}

.text-faint { color: var(--color-ink-faint); }

/* ---------- Pinned hero: fixed black panel, light content rises over it ---------- */
.case-hero-pin {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 100svh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  z-index: 1;
  background: var(--color-bg);
  color: var(--color-ink);
}
.case-hero-spacer { height: 100svh; }

/* ---- Kinetic character effects (see initKineticCTA() in main.js) ----
   Used by the home page's "from chaos to clarity" CTA heading — each
   character gets its own span so it can blur/fade independently. */
.hk-word { display: inline-block; will-change: transform, filter, opacity; }
.hk-char { display: inline-block; transform-origin: center center; will-change: transform, filter, opacity; }
/* z-index:3 — must outrank .site-footer (2), which must in turn outrank
   the pinned hero (1); see the comment on .site-footer for why. */
.stack-cover { position: relative; z-index: 3; }

/* ---------- Cheers parallax (no pinning — scrolls with the page) ---------- */
.case-cheers-wrap { padding-block: var(--space-2xl); }
.case-cheers {
  position: relative;
  height: clamp(300px, 34vw, 420px);
  display: flex;
  align-items: center;
  justify-content: center;
}
.case-cheers-left,
.case-cheers-right,
.case-cheers-backdrop {
  position: absolute;
  top: 50%;
  width: clamp(112px, 15.4vw, 210px); /* 30% smaller than the previous sizing */
  height: auto;
  will-change: transform;
}
/* Resting gap is sized relative to the backdrop's own (clamped) width, not vw,
   so it stays proportional even once the backdrop hits its 380px max on wide
   screens. Vertical centering (yPercent) is applied in JS via gsap.set instead
   of a CSS transform — GSAP caches an element's transform the first time it
   tweens x on it, and if that first read happens before the lazy-loaded image
   has its final height, a CSS translateY(-50%) gets locked in against a stale
   size and never corrects itself once the image loads. */
.case-cheers-left { right: 50%; z-index: 1; } /* glasses touch at 0px gap */
.case-cheers-right { left: 50%; z-index: 1; }
.case-cheers-backdrop {
  left: 50%;
  z-index: 0;
  width: clamp(200px, 30vw, 380px);
  opacity: 0.85;
  transform: translate(-50%, -50%);
}

@media (max-width: 56rem) {
  .case-meta { grid-template-columns: repeat(2, 1fr); }
  .case-block { grid-template-columns: 1fr; }
  .case-block h3 { position: static; }
  .case-gallery--2, .case-gallery--3 { grid-template-columns: 1fr; }
  .case-rationale-item { flex-basis: 100%; }
  .case-rationale-item .media { max-width: 16rem; margin-inline: auto; }
  .case-illustrations-item, .case-illustrations-item--hero { width: 3.5rem; height: 3.5rem; }
  .case-swatch-name { font-size: var(--text-h3); }
  .case-swatch-info { left: 1rem; right: 1rem; bottom: 1rem; }
}

/* ---------- Selected Work (lighter tile wall) ---------- */
.selected-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-md) var(--space-md);
}
.selected-tile { display: block; }
.selected-tile .media { aspect-ratio: 4 / 3; margin-bottom: var(--space-sm); transition: transform var(--dur-slow) var(--ease-out); }
.selected-tile:hover .media { transform: translateY(-4px); }
.selected-tile h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  font-size: var(--text-h3);
}
.selected-tile p {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
  margin-top: 0.35rem;
}
@media (max-width: 64rem) {
  .selected-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 40rem) {
  .selected-grid { grid-template-columns: 1fr; }
}

/* ---------- Logo wall ---------- */
/* Flexbox rather than grid — with a fixed column count, an incomplete last
   row left empty grid cells that read as a stray grey box (the container's
   own background showing through where no card existed) with no way to
   centre the leftover items. Flex-wrap + justify-content:center centres
   the last row's cards naturally, and dropping the background/border
   divider trick (gap + background-color) removes the lines between cards. */
.logo-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-xs);
}
.logo-card {
  flex: 0 0 calc(20% - var(--space-xs));
  max-width: calc(20% - var(--space-xs));
  aspect-ratio: 1 / 1;
  background: var(--color-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
}
/* Marks are capped at 115px so they read as a consistent wall rather than
   stretching to fill each grid cell — object-fit:contain alone would still
   let a mark grow as large as the cell. Individual marks override this cap
   inline where a mark reads too small/large next to its neighbours. */
.logo-card img { width: auto; height: auto; max-width: 115px; max-height: 115px; object-fit: contain; }
@media (max-width: 64rem) {
  .logo-card { flex-basis: calc(25% - var(--space-xs)); max-width: calc(25% - var(--space-xs)); }
}
@media (max-width: 40rem) {
  .logo-card { flex-basis: calc(50% - var(--space-xs)); max-width: calc(50% - var(--space-xs)); }
}

/* ---------- Forms ---------- */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-sm) var(--space-md); }
.form-field { display: flex; flex-direction: column; gap: 0.5rem; }
.form-field--full { grid-column: 1 / -1; }
.form-field label { font-size: var(--text-sm); font-weight: var(--weight-bold); }
.form-field .hint { font-size: var(--text-xs); color: var(--color-ink-faint); }
.form-field input,
.form-field select,
.form-field textarea {
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  border-radius: 4px;
  padding: 0.85rem 1rem;
  font-size: var(--text-body);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.form-field input:focus,
.form-field select:focus,
.form-field textarea:focus { border-color: var(--color-accent); }
.form-field textarea { resize: vertical; min-height: 9rem; }
.form-error {
  font-size: var(--text-xs);
  color: var(--color-accent);
  min-height: 1em;
}
.form-field.has-error input,
.form-field.has-error textarea { border-color: var(--color-accent); }
.form-status {
  margin-top: var(--space-sm);
  font-size: var(--text-sm);
  display: none;
}
.form-status.is-visible { display: block; }
@media (max-width: 56rem) {
  .form-grid { grid-template-columns: 1fr; }
}

/* ---------- Contact info list ---------- */
.info-list { display: flex; flex-direction: column; gap: var(--space-lg); }
.info-list h4 {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
  font-weight: var(--weight-bold);
  margin-bottom: 0.5rem;
}
.info-list p, .info-list a { font-size: var(--text-lg); font-family: var(--font-display); font-weight: var(--weight-regular); letter-spacing: 0.01em; }
