/* Titan Designs — Leo Rogers
   Base design system */

:root {
  --bg: #22222B;
  --bg-raised: #2C2C38;
  --ink: #f5f5f3;
  --ink-dim: #b8b6b2;
  --ink-faint: #9D9B96;
  --accent: #c9a24b; /* warm brass, echoes the viking mark — AA-compliant on this background */
  --line: #3A3A46;
  --max: 1240px;
  --gutter: clamp(20px, 5vw, 64px);
  --serif: "Fraunces", Georgia, "Times New Roman", serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

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

a { color: inherit; }

.wrap {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* Self-contained divider line: matches body/content width regardless of
   the padding on whatever element it sits inside. */
.rule {
  max-width: calc(var(--max) - 2 * var(--gutter));
  margin: 0 auto;
  border-top: 1px solid var(--line);
}

/* ---------- Header ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 65;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 26px var(--gutter);
  border-bottom: 1px solid var(--line);
}

/* Blur/tint lives on a pseudo-element rather than .site-header itself —
   backdrop-filter on the header directly would make it the containing
   block for any position:fixed descendant (the mobile menu), trapping
   that full-screen panel inside the header's own small box instead of
   the viewport. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to bottom, rgba(34,34,43,0.96), rgba(34,34,43,0.75));
  backdrop-filter: blur(6px);
}

.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  text-decoration: none;
  font-family: var(--serif);
  letter-spacing: 0.04em;
  /* .site-header is a stacking context (position:sticky + z-index), so
     z-index values of ITS children only compete against each other, not
     the whole page. Without this, .brand (no position, so it paints in
     the plain in-flow layer) sits below any positioned descendant with a
     z-index — including .main-nav's fixed, full-screen mobile panel
     (z-index:60) — even though visually the header looks "on top" of
     everything else on the page. Giving .brand its own position + z-index
     (matching .nav-toggle's 61) keeps the logo painted above the mobile
     menu instead of underneath it. */
  position: relative;
  z-index: 61;
}

.brand img { height: 48px; width: auto; }

.brand span {
  font-size: 1.3rem;
  text-align: right;
}

.brand small {
  display: block;
  font-family: var(--sans);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  color: var(--ink-faint);
  font-weight: 600;
}

.main-nav { display: flex; gap: 32px; }

.main-nav a {
  text-decoration: none;
  font-size: 0.92rem;
  letter-spacing: 0.03em;
  color: var(--ink-dim);
  transition: color 0.15s ease;
}

.main-nav a:hover { color: var(--accent); }
.main-nav a[aria-current="page"] { color: var(--ink); }

.nav-toggle {
  display: none;
  position: relative;
  width: 26px;
  height: 20px;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  z-index: 61;
}

.nav-toggle span {
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--ink);
  border-radius: 1px;
  transition: transform 0.25s ease, opacity 0.2s ease, top 0.25s ease;
}

.nav-toggle span:nth-child(1) { top: 0; }
.nav-toggle span:nth-child(2) { top: 9px; }
.nav-toggle span:nth-child(3) { top: 18px; }

.nav-toggle.open span:nth-child(1) { top: 9px; transform: rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { top: 9px; transform: rotate(-45deg); }

.nav-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0s linear 0.3s;
  z-index: 55;
}

.nav-overlay.open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s ease;
}

@media (max-width: 720px) {
  .nav-toggle { display: block; }

  .nav-overlay { display: none; }

  .main-nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    margin: 0;
    background: var(--bg);
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 36px;
    padding: 128px var(--gutter) 60px;
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 0.32s ease, visibility 0s linear 0.32s;
    z-index: 60;
  }

  .main-nav.open {
    transform: translateX(0);
    visibility: visible;
    transition: transform 0.32s ease;
  }

  .main-nav a {
    font-size: 1.3rem;
    padding: 4px 0;
  }
}

/* ---------- Homepage hero stage: animated gradient + ink trail ----------
   Wraps only the homepage hero (index.html) in a .hero-stage container.
   Adds a low-saturation animated gradient background, in the site's own
   brass/charcoal/blue-grey palette, plus a mouse-reactive "ink" particle
   trail (see nav.js) on desktop/tablet widths. Mobile keeps only a static
   (non-animated, no ink) version of the same gradient colours - there's
   no cursor on a phone, and motion at that narrow an aspect ratio reads
   as clutter rather than polish. Everything here is scoped via
   .hero-stage (or new classes .hero-gradient/.blob/.ink-trail that don't
   exist elsewhere on the site) so none of it touches the bare .hero rule
   shared with services.html and work.html. */

.hero-stage {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.hero-stage .hero {
  position: relative;
  z-index: 1;
}

.hero-gradient {
  position: absolute;
  inset: -10% -5%;
  z-index: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  mix-blend-mode: screen;
  will-change: transform;
}

/* Ink trail: a canvas-based particle system (see nav.js) rendering dark
   (#22222B) "ink drops" that spawn along the cursor's path, inherit its
   current velocity, then keep drifting and fading under their own
   momentum - closer to real ink/smoke than a shape rigidly tracking the
   pointer. mix-blend-mode: multiply on the canvas itself keeps it
   dark-on-dark invisible against the plain background and only visible
   where it crosses the lighter gradient blobs. */
.ink-trail {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
  pointer-events: none;
  mix-blend-mode: multiply;
  transition: opacity 0.4s ease;
}

.blob-1 {
  width: 46vw; height: 46vw; max-width: 620px; max-height: 620px;
  left: -8%; top: -18%;
  background: radial-gradient(circle at 35% 35%, rgba(201,162,75,0.30), rgba(201,162,75,0) 70%);
  animation: drift1 11s ease-in-out infinite alternate;
}
.blob-2 {
  width: 38vw; height: 38vw; max-width: 520px; max-height: 520px;
  right: -6%; top: 4%;
  background: radial-gradient(circle at 60% 40%, rgba(122,140,168,0.22), rgba(122,140,168,0) 70%);
  animation: drift2 14s ease-in-out infinite alternate;
}
/* blob-3 sits at the same horizontal position (left: 22%) it always has,
   but at the top of the panel rather than the bottom. Bottom-anchored, it
   got hard-clipped by the .hero-stage's own bottom edge (which lands
   right around the button row), showing up as an abrupt, straight-edged
   cutoff of the mauve tone rather than a soft fade - the preview file
   masked this with an extra 1px line at the base of the demo panel, which
   isn't something we want to carry into the real layout. Moving it to
   the top instead lets it bleed softly off the top edge, just under the
   header, the same way blob-1 already does, so the colour still reads
   without any hard line. */
.blob-3 {
  width: 34vw; height: 34vw; max-width: 460px; max-height: 460px;
  left: 22%; top: -16%;
  background: radial-gradient(circle at 50% 50%, rgba(150,110,140,0.16), rgba(150,110,140,0) 70%);
  animation: drift3 9s ease-in-out infinite alternate;
}

@keyframes drift1 {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(7%, 9%) scale(1.1); }
}
@keyframes drift2 {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(-9%, 6%) scale(1.08); }
}
@keyframes drift3 {
  /* Vertical drift flipped from the original (-8%, drifting up) to
     +8% (drifting down) now that the blob is anchored at the top -
     drifting further upward would push more of it off-screen instead of
     keeping it comfortably inside the panel. */
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(5%, 8%) scale(1.12); }
}

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

/* Mobile: keep the gradient colours (Leo likes them) but freeze the
   drift animation and drop the mouse-reactive ink trail entirely - no
   cursor on a phone anyway. The blobs are resized/repositioned here
   rather than just frozen at their desktop proportions: at a ~390px
   width, 46vw etc. shrinks them down so far that the fixed blur would
   swallow the whole shape. Bigger, less-blurred versions keep the same
   colours clearly visible as a static wash without needing motion. */
@media (max-width: 720px) {
  .blob { animation: none !important; filter: blur(46px); }
  .blob-1 { width: 88vw; height: 88vw; left: -20%; top: -28%; }
  .blob-2 { width: 74vw; height: 74vw; right: -22%; top: -4%; }
  .blob-3 { width: 68vw; height: 68vw; left: 8%; top: -14%; }
  .ink-trail { display: none; }
}

/* ---------- Hero ---------- */

.hero {
  padding: 96px var(--gutter) 65px;
  max-width: var(--max);
  margin: 0 auto;
}

@media (max-width: 720px) {
  .hero { padding: 56px var(--gutter) 40px; }
}

.hero .eyebrow {
  display: inline-block;
  color: var(--accent);
  font-size: 0.85rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 18px;
}

.hero h1 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  line-height: 1.12;
  margin: 0 0 24px;
  max-width: 66%;
}

.hero p.lede {
  font-size: 1.15rem;
  color: var(--ink-dim);
  max-width: 66%;
  margin: 0 0 36px;
}

/* Hero title/lede use roughly 2/3 of the body width on desktop/tablet,
   across every page that uses .hero, so longer headings and intros don't
   wrap into a tall, narrow column. Resets to full width on mobile. */
@media (max-width: 700px) {
  .hero h1,
  .hero p.lede {
    max-width: 100%;
  }
}

/* Work landing page only: the title/lede need more than the usual 66%
   so the last line of the lede ("...it was delivered.") doesn't orphan
   a single short word. Scoped to .work-hero rather than changing the
   shared .hero rule used by every other page. */
@media (min-width: 701px) {
  .work-hero h1,
  .work-hero p.lede {
    max-width: 85%;
  }
}

/* Matches the inline padding-bottom:32px this page used to carry. */
.work-hero { padding-bottom: 32px; }

/* Work landing, mobile only: the gap between the lede paragraph and the
   image grid below it is the hero's bottom padding plus the grid
   section's top padding (32px + 32px). Halve the combined total by
   trimming each side to 16px, without touching the shared .hero /
   section.tight mobile padding used on every other page. */
@media (max-width: 720px) {
  .work-hero { padding-bottom: 16px; }
  .work-grid-section.tight { padding-top: 16px; }
}

.btn-row { display: flex; gap: 16px; flex-wrap: wrap; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 26px;
  border-radius: 10px;
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.btn-primary { background: var(--accent); color: #1a1400; }
.btn-ghost { background: transparent; border: 1px solid var(--line); color: var(--ink); }

.btn-primary:hover,
.btn-ghost:hover {
  background: #fff;
  border-color: #fff;
  color: #14141a;
}

/* On mobile, a row of buttons fills the available width edge-to-edge
   (minus the gutter) and stays on one line rather than wrapping. */
@media (max-width: 720px) {
  .btn-row { flex-wrap: nowrap; }
  .btn-row .btn { flex: 1 1 0; justify-content: center; }
}

/* The homepage hero has two buttons sharing the row ("See the work" /
   "Start a project"), which is tight enough on narrow phones that the
   longer label wraps onto a second line and makes that button taller
   than its neighbour. Scoped to .hero-wide so the single-button rows
   elsewhere (e.g. Services) keep their normal, more generous sizing. */
@media (max-width: 720px) {
  .hero-wide .btn-row { gap: 12px; }
  .hero-wide .btn-row .btn {
    padding: 14px 10px;
    font-size: 0.85rem;
    white-space: nowrap;
  }
}

/* A lone ghost button (not part of a .btn-row) that should still go
   full-width on mobile, e.g. "Read more about me" on the homepage. */
@media (max-width: 720px) {
  .btn-block-mobile {
    width: 100%;
    justify-content: center;
  }
}

/* ---------- Text link hover states ---------- */

/* General links inside prose/content — case study titles, inline copy links */
.cs-body p a,
.about-copy p a,
.service-item p a,
.testimonial p a,
section p a {
  color: inherit;
  text-decoration: none;
  transition: color 0.15s ease;
}

.cs-body p a:hover,
.about-copy p a:hover,
.service-item p a:hover,
.testimonial p a:hover {
  color: var(--accent);
}

/* The Black Antelope link in the case-study meta is yellow by default
   (rather than inheriting the surrounding white text) specifically so
   it reads as a link at a glance, going white on hover like the site's
   arrow-style CTAs. */
.cs-meta strong a {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.15s ease;
}

.cs-meta strong a:hover {
  color: #fff;
}

.case-card:hover h3 {
  color: var(--accent);
}

/* Arrow-style CTA text links: yellow by default, white + arrow nudge on hover */
.see-all,
.cs-next a,
.more {
  color: var(--accent);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: color 0.15s ease;
}

.see-all:hover,
.cs-next a:hover,
.more:hover {
  color: #fff;
}

.arrow {
  display: inline-block;
  transition: transform 0.2s ease;
}

.see-all:hover .arrow,
.cs-next a:hover .arrow,
.more:hover .arrow {
  transform: translateX(5px);
}

/* ---------- Section scaffolding ---------- */

section { padding: 81px 0; }
section.tight { padding: 49px 0; }

/* Desktop spacing is tuned; mobile needs its own, tighter rhythm since
   sections stack vertically there and the same padding reads as far
   more empty space on a phone screen. */
@media (max-width: 720px) {
  section { padding: 48px 0; }
  section.tight { padding: 32px 0; }
}

/* Homepage only: tighten the specific gap between the last testimonial
   card and the dividing rule above the about-teaser, without touching
   the general mobile section padding used everywhere else (which would
   also change the gap on the OTHER side of that rule, down to the About
   kicker — that one should stay as it is). */
@media (max-width: 720px) {
  .feedback { padding-bottom: 8px; }
}

.section-head {
  max-width: var(--max);
  margin: 0 auto 40px;
  padding: 0 var(--gutter);
  display: flex;
  /* Baseline alignment (rather than flex-end, which aligns box edges)
     lines the "View all projects" text up with the actual visible base
     of the heading beside it — flex-end was off by a few px because the
     serif heading and the smaller sans-serif link have different font
     metrics, so their box edges don't land in the same place their text
     does. */
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}

.section-head h2 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  margin: 0;
}

.section-head .see-all {
  font-size: 0.92rem;
  white-space: nowrap;
}

/* When the title and "view all" link don't both fit on one line, they
   wrap onto separate rows — align-items:flex-end only controls
   cross-axis alignment WITHIN a line, so once wrapped, the gap between
   the two rows was left at the full flex `gap` (24px), making the link
   look disconnected from the title above it. Tighten just the vertical
   gap on mobile, where wrapping is most likely. */
@media (max-width: 720px) {
  .section-head { row-gap: 8px; }
}

.kicker {
  color: var(--accent);
  font-size: 0.82rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  display: block;
  margin-bottom: 10px;
}

/* ---------- Featured case study cards (home) ---------- */

.feature-list {
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  gap: 64px;
}

.feature-row {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 48px;
  align-items: center;
}

.feature-row:nth-child(even) { direction: rtl; }
.feature-row:nth-child(even) > * { direction: ltr; }

@media (max-width: 860px) {
  .feature-row { grid-template-columns: 1fr; direction: ltr !important; }
}

.feature-row img {
  border-radius: 6px;
  aspect-ratio: 5 / 4;
  object-fit: cover;
  width: 100%;
}

.feature-row .client {
  color: var(--ink-faint);
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 10px;
  display: block;
}

.feature-row h3 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.7rem;
  margin: 0 0 14px;
}

.feature-row p { color: var(--ink-dim); margin: 0 0 20px; }

.feature-row a.more {
  font-weight: 600;
  font-size: 0.92rem;
}

/* ---------- Case study grid (Work page) ---------- */

.case-grid {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 40px 32px;
}

@media (max-width: 760px) { .case-grid { grid-template-columns: 1fr; } }

.case-card { text-decoration: none; display: block; }

.case-card .thumb {
  aspect-ratio: 16/10;
  overflow: hidden;
  border-radius: 8px;
  margin-bottom: 18px;
  background: var(--bg-raised);
}

.case-card .thumb img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.4s ease;
}

.case-card:hover .thumb img { transform: scale(1.04); }

.case-card .sector {
  display: inline-block;
  color: var(--accent);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 8px;
}

.case-card h3 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.35rem;
  margin: 0 0 8px;
}

.case-card p {
  color: var(--ink-dim);
  font-size: 0.95rem;
  margin: 0 0 10px;
}

.case-card .via {
  font-size: 0.8rem;
  color: var(--ink-faint);
}

/* ---------- Testimonials ---------- */

.testimonial-grid {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}

@media (max-width: 860px) { .testimonial-grid { grid-template-columns: 1fr; } }

.testimonial {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 28px;
}

.testimonial p.quote {
  font-family: var(--serif);
  font-size: 1.05rem;
  line-height: 1.5;
  margin: 0 0 20px;
}

.testimonial .who { font-size: 0.85rem; color: var(--ink-dim); }
.testimonial .who strong { color: var(--ink); display: block; }

/* ---------- Services ---------- */

.service-grid {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 32px;
}

@media (max-width: 760px) { .service-grid { grid-template-columns: 1fr; } }

.service-item {
  padding: 32px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.service-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  color: var(--accent);
  margin-bottom: 16px;
}

.service-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.service-item h3 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.3rem;
  margin: 0 0 12px;
}

.service-item p { color: var(--ink-dim); margin: 0; font-size: 0.98rem; }

.process-strip {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}

@media (max-width: 760px) { .process-strip { grid-template-columns: 1fr 1fr; } }

.process-strip .step span {
  display: block;
  font-family: var(--serif);
  color: var(--accent);
  font-size: 1.4rem;
  margin-bottom: 8px;
}

.process-strip .step strong { display: block; margin-bottom: 6px; }
.process-strip .step p { color: var(--ink-dim); font-size: 0.9rem; margin: 0; }

.process-strip .step .step-arrow {
  display: inline-block;
  color: var(--ink-faint);
  font-size: 1rem;
  margin-right: 8px;
}

/* ---------- About ---------- */

/* Grid, rather than a fixed DOM order, because the "Get in touch"
   button needs to sit beside the title on desktop/tablet but drop to
   the end of the text on mobile — the same markup, reordered per
   breakpoint via named areas rather than two copies of the button. */
.about-copy {
  max-width: 700px;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "title cta"
    "text  text"
    "facts facts";
  align-items: center;
  column-gap: 20px;
  row-gap: 28px;
}

.about-copy h1 { grid-area: title; font-family: var(--serif); font-weight: 500; font-size: 2.2rem; margin: 0; }
.about-cta { grid-area: cta; }
.about-text { grid-area: text; }
.about-text p { color: var(--ink-dim); margin: 0 0 20px; }
.about-text p:last-child { margin-bottom: 0; }

@media (max-width: 720px) {
  .about-copy {
    grid-template-columns: 1fr;
    grid-template-areas:
      "title"
      "text"
      "cta"
      "facts";
    row-gap: 24px;
  }
  .about-cta { width: 100%; justify-content: center; }
}

.fact-row {
  grid-area: facts;
  display: flex;
  flex-wrap: wrap;
  padding-top: 32px;
  border-top: 1px solid var(--line);
}

.fact-row .fact {
  flex: 1 1 0;
  min-width: 140px;
  padding: 0 32px;
  border-left: 1px solid var(--line);
}

.fact-row .fact:first-child {
  padding-left: 0;
  border-left: none;
}

.fact-row .fact strong {
  display: block;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 2.6rem;
  color: #fff;
  margin-bottom: 6px;
}

.fact-row .fact span {
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--ink-faint);
  letter-spacing: 0.04em;
}

/* min-width:140px on each of the 3 stats forces a combined width the
   narrowest phones (portrait iPhones) can't fit, pushing the third stat
   onto its own row. Let the columns shrink and scale the number/label
   down a little instead, so all three stay on one line. The labels then
   wrap onto 2-3 lines in a narrow column — without an explicit
   line-height they inherit the body's 1.6, which reads as huge gaps
   between the wrapped lines at this small a font size. */
@media (max-width: 480px) {
  .fact-row .fact { min-width: 0; padding: 0 10px; }
  .fact-row .fact:first-child { padding-left: 0; }
  .fact-row .fact strong { font-size: 1.6rem; }
  /* Line-height halved (1.4 → 0.7) to tighten the wrapped label text;
     .fact-row's default align-items:stretch makes the vertical divider
     on each .fact automatically shrink to match the reduced height, so
     no separate divider-height rule is needed. */
  .fact-row .fact span { font-size: 0.7rem; line-height: 0.7; }
  /* The third stat's label is far longer than the other two ("One-person
     studio, global reach, no PMs" vs "Years in design") — giving it a
     bigger share of the row (instead of splitting it three equal ways)
     is what gets it down to 2 wrapped lines instead of 3. */
  .fact-row .fact:last-child { flex: 1.7 1 0; }
}

/* ---------- Contact ---------- */

.contact-grid {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 48px;
  align-items: center;
}

@media (max-width: 800px) {
  .contact-grid { grid-template-columns: 1fr; gap: 28px; }
}

.contact-main h1 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  line-height: 1.12;
  margin: 0 0 20px;
}

.contact-main p { color: var(--ink-dim); font-size: 1.15rem; margin: 0; max-width: 46ch; }

.contact-side {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
}

@media (max-width: 800px) {
  .contact-side { gap: 16px; }
}

@media (max-width: 800px) {
  /* Halves the true total gap between the hero image and "Let's talk"
     (this 64px plus .cs-media-hero's own 28px mobile bottom margin =
     92px combined) down to 46px, by trimming only this page-specific
     value; .cs-media-hero's shared margin is left untouched. */
  .contact-top { padding-top: 18px !important; padding-bottom: 48px; }
}

.contact-email {
  display: inline-block;
  font-family: var(--serif);
  font-size: clamp(1.4rem, 4vw, 2rem);
  color: var(--accent);
  text-decoration: none;
  transition: color 0.15s ease;
}

.contact-email:hover { color: #fff; }

/* Mobile: give the mail link the same button treatment used for every
   other call-to-action on the site, rather than styled text — it reads
   more like the primary action it is, and sits consistently alongside
   the other full-width mobile buttons. Desktop/tablet keeps the larger
   serif link, which already has plenty of presence in the two-column
   layout. */
@media (max-width: 720px) {
  .contact-email {
    display: flex;
    width: 100%;
    justify-content: center;
    align-items: center;
    font-family: var(--sans);
    font-size: 0.95rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    padding: 14px 20px;
    border-radius: 10px;
    /* Solid yellow fill by default on mobile, matching .btn-primary,
       rather than the stroke/outline style used on desktop. */
    border: 1px solid var(--accent);
    background: var(--accent);
    color: #1a1400;
  }

  .contact-email:hover {
    background: #fff;
    border-color: #fff;
    color: #14141a;
  }
}

.contact-links {
  display: flex;
  align-items: center;
  gap: 20px;
  color: var(--ink-dim);
  font-size: 0.95rem;
}

/* Icon-style links — LinkedIn in the contact column and the footer:
   white by default, accent yellow on hover */
.icon-link {
  display: inline-flex;
  align-items: center;
  color: #fff;
  text-decoration: none;
  transition: color 0.15s ease;
}

.icon-link:hover { color: var(--accent); }

.icon-link svg { width: 18px; height: 18px; fill: currentColor; display: block; }

/* ---------- Case study page ---------- */

.cs-hero {
  max-width: var(--max);
  margin: 0 auto;
  padding: 64px var(--gutter) 40px;
}

@media (max-width: 720px) {
  .cs-hero { padding: 40px var(--gutter) 28px; }
}

/* Mobile only: show the hero image immediately after the header, ahead
   of the title/subheading/button/description and the structured
   attributes below them. Desktop/tablet keeps the normal source order
   (image last); .cs-top-wrap only becomes a flex column at this
   breakpoint, so nothing here affects wider screens. */
@media (max-width: 720px) {
  .cs-top-wrap {
    display: flex;
    flex-direction: column;
  }

  .cs-top-wrap .cs-media-hero {
    order: -1;
  }
}

/* Title (+ optional "View website" button) sit in their own row so the
   button can align beside the title, and label + "View website" wraps
   under the title on mobile rather than fighting it for space. */
.cs-hero-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px 32px;
  flex-wrap: wrap;
}

.cs-hero-top .btn {
  flex-shrink: 0;
  padding: 10px 22px;
  font-size: 0.85rem;
  white-space: nowrap;
}

@media (max-width: 720px) {
  .cs-hero-top .btn { width: 100%; justify-content: center; }
  /* Push the button 15px further from the title (row-gap was 16px, so
     31px total) — mobile-only, since the title wraps to full width
     above it there and the two felt too tight together. */
  .cs-hero-top { row-gap: 31px; }
}

.cs-hero .client-tag {
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.85rem;
  margin-bottom: 14px;
  display: block;
}

.cs-hero h1 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.12;
  margin: 0;
  max-width: 100%;
}

.cs-hero p.dek { color: var(--ink-dim); font-size: 1.15rem; max-width: 66%; margin: 24px 0 0; }

/* Case-study titles/deks use roughly 2/3 of the body width on
   desktop/tablet, so longer titles (e.g. multi-word institution names)
   don't wrap into several short lines. Resets to full width on mobile.
   The width cap lives directly on the h1, which is now a direct flex
   item of .cs-hero-top (the client-tag label was moved out of that row
   entirely, above .cs-hero-top) — so the percentage resolves against
   .cs-hero-top's own definite width rather than against an intermediate
   auto-sized wrapper, avoiding the circular-sizing bug that used to
   either balloon titles to the full row width (pushing the button onto
   its own line) or shrink them oddly (wrapping even short titles). */
.cs-hero h1 {
  min-width: 0;
  max-width: 66%;
}

@media (max-width: 720px) {
  .cs-hero h1,
  .cs-hero p.dek {
    max-width: 100%;
  }
}

/* The meta block is framed by a rule above and below the attributes,
   rather than a single rule at the bottom only. */
.cs-meta {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.cs-meta .rule:first-child { margin-bottom: 40px; }

.cs-meta-attrs {
  display: flex;
  align-items: flex-start;
  gap: 24px 40px;
  flex-wrap: wrap;
  padding-bottom: 40px;
}

@media (max-width: 720px) {
  .cs-meta .rule:first-child { margin-bottom: 28px; }
  .cs-meta-attrs { padding-bottom: 28px; gap: 20px 32px; }
}

.cs-meta div span { display: block; font-size: 0.78rem; color: var(--ink-faint); text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 4px; }
.cs-meta div strong { font-weight: 600; }

.cs-body {
  max-width: 780px;
  margin: 0 auto;
  /* Top padding is tuned together with .cs-media-hero's bottom margin
     below it — the two combined are the hero-image-to-first-paragraph
     gap (45px on desktop, trimmed 25px down from the previous 70px,
     which itself was 50px down from the original 120px). */
  padding: 15px var(--gutter) 50px;
}

@media (max-width: 720px) {
  /* Bottom value halved (40px → 20px) to tighten the gap between the
     body content and the "What clients say" heading below it on
     mobile; top value trimmed the same 25px as desktop, keeping the
     hero-image-to-first-paragraph gap combined at 39px here. */
  .cs-body { padding: 11px var(--gutter) 20px; }
}

/* Heading-to-paragraph spacing is back to its original, tighter values
   (constant at every screen size, as before) — that gap was never meant
   to grow. The large 50px/40px breathing room is instead built into
   .cs-media's OWN top-and-bottom margin below, so it wins the margin
   collapse against whichever smaller margin (a paragraph's or a
   heading's) sits next to an image, in either direction, without
   touching the heading/paragraph-only case. */
.cs-body p { color: var(--ink-dim); margin: 0 0 22px; font-size: 1.05rem; }
.cs-body h2 { font-family: var(--serif); font-weight: 500; font-size: 1.5rem; margin: 44px 0 20px; }

.cs-media {
  max-width: var(--max);
  margin: 50px auto;
}

@media (max-width: 720px) {
  .cs-media { margin: 40px auto; }
}

.cs-media-hero {
  padding: 0 var(--gutter);
  margin: 48px auto 30px;
}

@media (max-width: 720px) {
  .cs-media-hero { margin: 28px auto 28px; }
}

/* Homepage about-teaser: the intro paragraph is narrow (46ch) by default
   so it doesn't stretch too wide on small/medium screens, but on
   desktop/tablet that same fixed character-width leaves it looking
   cramped next to all the space around it. Above 720px, let it use
   roughly 2/3 of the section's horizontal space instead, so it reads as
   a normal short paragraph (3-4 lines) rather than a tall, narrow column. */
.about-teaser-text { max-width: 46ch; }

@media (min-width: 721px) {
  .about-teaser-text { max-width: 66%; }
}

.cs-media img { border-radius: 8px; width: 100%; }

.cs-note {
  max-width: 780px;
  margin: 40px auto 56px;
  padding: 20px 24px;
  border-left: 3px solid var(--accent);
  background: var(--bg-raised);
  color: var(--ink-dim);
  font-size: 0.95rem;
  border-radius: 0 6px 6px 0;
}

/* Shared "What clients say" panel appended to every case study,
   between the body content and the "next project" link. Full max-width
   (not the narrower .cs-body column) to match the 3-up grid used
   elsewhere, e.g. the homepage. */
.cs-testimonials {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  text-align: center;
}

.cs-testimonials h2 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2rem, 6vw, 3rem);
  margin: 0 0 64px;
}

@media (max-width: 720px) {
  /* Tighten the heading-to-first-testimonial gap by 20px on mobile. */
  .cs-testimonials h2 { margin-bottom: 44px; }
}

.cs-testimonials .testimonial-grid { text-align: left; }

.cs-next {
  padding: 0 var(--gutter) 56px;
  text-align: center;
}

/* 90px above the rule, closing out the case study; the 56px below it
   (rule to "Next project" label) is unchanged. */
.cs-next .rule { margin: 90px auto 56px; }

@media (max-width: 720px) {
  /* Halve the last-testimonial-to-divider gap on mobile; the 56px below
     the rule is left untouched. */
  .cs-next .rule { margin-top: 45px; }
}

.cs-next a {
  font-family: var(--serif);
  font-size: 1.6rem;
}

.cs-next span { display: block; color: var(--ink-faint); font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 10px; }

/* ---------- Footer ---------- */

footer {
  border-top: 1px solid var(--line);
  padding: 40px var(--gutter);
  color: var(--ink-faint);
  font-size: 0.85rem;
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

.footer-inner a {
  color: #fff;
  text-decoration: none;
  transition: color 0.15s ease;
}

.footer-inner a:hover { color: var(--accent); }

/* Case-study image zoom + lightbox
   Applies only to body images inside .cs-body (the hero image is never
   zoomable). A small button is added in JS (see nav.js) over the
   bottom-right corner of each zoomable image; activating it opens the
   image at a larger size in a full-screen overlay. */
.cs-body .cs-media {
  position: relative;
}

.cs-zoom-btn {
  position: absolute;
  right: 14px;
  bottom: 14px;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(34, 34, 43, 0.72);
  color: var(--ink);
  cursor: zoom-in;
  backdrop-filter: blur(2px);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.15s ease, transform 0.15s ease, background 0.15s ease;
}

.cs-zoom-btn svg { width: 18px; height: 18px; }

.cs-media:hover .cs-zoom-btn,
.cs-zoom-btn:focus-visible {
  opacity: 1;
  transform: translateY(0);
}

.cs-zoom-btn:hover { background: var(--accent); color: #1a1400; }

@media (max-width: 720px) {
  /* No hover on touch devices, so keep the button visible outright. */
  .cs-zoom-btn { opacity: 1; transform: none; }
}

.lightbox-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(15, 15, 19, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px var(--gutter);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.2s ease;
}

.lightbox-overlay.open {
  opacity: 1;
  visibility: visible;
}

.lightbox-overlay img {
  max-width: 100%;
  max-height: 100%;
  border-radius: 8px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.lightbox-close {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.15s ease;
}

.lightbox-close svg { width: 20px; height: 20px; }

.lightbox-close:hover { background: var(--accent); color: #1a1400; }

.lightbox-overlay .spinner {
  position: absolute;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.2);
  border-top-color: var(--accent);
  animation: lightbox-spin 0.8s linear infinite;
  display: none;
}

.lightbox-overlay.loading .spinner { display: block; }
.lightbox-overlay.loading img { opacity: 0; }

@keyframes lightbox-spin {
  to { transform: rotate(360deg); }
}
