/* ============================================================
   Angel Castro — Senior Graphic Designer & Brand Designer
   Editorial / Swiss direction on warm paper
   ============================================================ */

:root {
  /* Surface */
  --paper: #f2f0ea;
  --paper-2: #e8e5dc;
  --ink: #111111;
  --ink-2: #1a1a1a;
  --text: #111111;
  --muted: #66645f;
  --muted-dark: #a5a29a;
  --line: rgba(17, 17, 17, 0.16);
  --line-dark: rgba(255, 255, 255, 0.14);

  /* Accent. --accent is a tint for marks and rules only: at 2.7:1 on paper it
     is not a legal text colour. --accent-text is the darkened cut for type,
     which clears 4.5:1 and so passes at any size. */
  --accent: #ff5c35;
  --accent-text: #c43a17;

  /* Display-only grey for the receding half of a two-tone headline. Lighter
     than --muted so the tonal step is obvious, still 3.6:1 on paper, which
     clears the large-text minimum. Do not use it below ~24px. */
  --ink-recede: #807d75;

  /* Type */
  --font-sans: "DM Sans", system-ui, -apple-system, sans-serif;
  --font-serif: "Instrument Serif", Georgia, serif;

  --text-eyebrow: 0.72rem;
  --text-body: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --text-h2: clamp(2.4rem, 5.5vw, 5rem);
  --text-hero: clamp(3.4rem, 9.5vw, 9rem);

  /* Layout */
  --max: 1440px;
  --pad: clamp(1.25rem, 4vw, 4rem);
  --space-section: clamp(5rem, 10vw, 9rem);

  /* Motion */
  --dur-fast: 160ms;
  --dur: 300ms;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

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

/* Native smooth scroll is the fallback. When Lenis is driving (it adds
   `.lenis` to <html>) it must be off, or the two fight over anchor jumps. */
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

html.lenis,
html.lenis body { height: auto; }
html.lenis-smooth { scroll-behavior: auto !important; }
html.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
html.lenis-stopped { overflow: clip; }
html.lenis-smooth iframe { pointer-events: none; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

body.dialog-open { overflow: hidden; }

a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
img { display: block; max-width: 100%; height: auto; }

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

.skip-link {
  position: fixed;
  top: 1rem;
  left: 1rem;
  z-index: 999;
  padding: 0.75rem 1rem;
  background: var(--ink);
  color: #fff;
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

/* ---------- Shared type ---------- */

.eyebrow,
.section-number {
  margin: 0;
  font-size: var(--text-eyebrow);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.section-number { color: var(--muted); }

.text-link {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid currentColor;
  font-weight: 600;
}
.text-link span,
.contact-link span,
.project-meta > span { transition: transform var(--dur-fast) var(--ease); }
.text-link:hover span,
.contact-link:hover span { transform: translate(0.25rem, -0.25rem); }

/* GSAP drives the project arrow when motion is on, so the CSS transition and
   hover transform are scoped to the non-motion path to avoid two owners
   writing the same property. */
html:not(.motion) .project-open:hover .project-meta > span {
  transform: translate(0.25rem, -0.25rem);
}
html.motion .project-meta > span { transition: none; }

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

.site-header,
main,
.site-footer {
  width: min(100%, var(--max));
  margin-inline: auto;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding: 1.15rem var(--pad);
  /* Deliberately opaque, not frosted. A backdrop-filter here re-blurs the
     full header width on every scroll frame, which is the single most
     expensive thing that can sit on a sticky element. */
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}

.logo { font-size: 0.95rem; font-weight: 700; letter-spacing: -0.02em; }

.site-nav { display: flex; align-items: center; gap: 1.9rem; font-size: 0.9rem; }
.menu-toggle { display: none; border: 0; background: transparent; cursor: pointer; }

.site-nav a { position: relative; }
.site-nav a::after,
.site-footer a::after {
  position: absolute;
  right: 0;
  bottom: -0.3rem;
  left: 0;
  height: 1px;
  content: "";
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-fast) var(--ease);
}
.site-nav a:hover::after,
.site-footer a:hover::after { transform: scaleX(1); transform-origin: left; }

.nav-cta {
  padding: 0.55rem 1rem;
  border: 1px solid var(--ink);
  border-radius: 999px;
  font-weight: 600;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.nav-cta::after { display: none; }
.nav-cta:hover { background: var(--ink); color: var(--paper); }

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

.hero {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: calc(100vh - 70px);
  padding: clamp(3.5rem, 9vw, 8rem) var(--pad) 3rem;
  border-bottom: 1px solid var(--line);
}

.hero-topline,
.hero-footer { display: flex; justify-content: space-between; gap: 2rem; }
.hero-footer { align-items: flex-end; }

.availability {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0;
  color: var(--muted);
  font-size: 0.8rem;
}
.availability::before {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  content: "";
}

/* Two-tone: the sans setup recedes so the serif line carries the idea. */
.hero h1 {
  max-width: 1150px;
  margin: 3rem 0;
  font-size: var(--text-hero);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: -0.065em;
  color: var(--ink-recede);
}
.hero-line--accent .hero-line__inner { color: var(--text); }

/* Each line is its own mask so the reveal can slide from below.
   The padding/negative-margin pair gives italic descenders room inside
   the mask without adding visual space between the lines. */
.hero-line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.2em;
  margin-bottom: -0.16em;
}
.hero-line__inner { display: block; }
.hero-line--accent .hero-line__inner {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.04em;
}

.hero-copy {
  max-width: 580px;
  margin: 0;
  color: var(--muted);
  font-size: clamp(1rem, 1.4vw, 1.2rem);
}

/* ---------- Metrics ---------- */

.metrics {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-bottom: 1px solid var(--line);
}
.metrics div {
  padding: 2rem var(--pad);
  border-right: 1px solid var(--line);
}
.metrics div:last-child { border-right: 0; }
.metrics strong,
.metrics span { display: block; }
.metrics strong {
  font-family: var(--font-serif);
  font-size: clamp(2rem, 3.6vw, 3.6rem);
  font-weight: 400;
  line-height: 1.05;
}
.metrics span { margin-top: 0.35rem; color: var(--muted); font-size: 0.8rem; }

/* ---------- Client logo band (dark) ---------- */

.clients {
  padding: clamp(2.5rem, 5vw, 4rem) var(--pad);
  background: var(--ink);
  color: #fff;
}
.clients .eyebrow { color: var(--muted-dark); margin-bottom: 2rem; }
.client-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 2rem clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
}
.client-grid img {
  width: 100%;
  max-width: 150px;
  height: auto;
  opacity: 0.75;
  transition: opacity var(--dur-fast);
}
.client-grid img:hover { opacity: 1; }

/* GSAP owns opacity here once motion is on — a CSS transition on the same
   property would lag behind its per-frame writes. */
html.motion .client-grid img { transition: none; }

/* ---------- Sections ---------- */

.section {
  padding: var(--space-section) var(--pad);
  border-bottom: 1px solid var(--line);
}

.section-heading {
  display: grid;
  grid-template-columns: minmax(60px, 0.35fr) 2fr;
  gap: 2rem;
  margin-bottom: clamp(3rem, 6vw, 5rem);
}
.section-heading h2 {
  max-width: 900px;
  margin: 0.9rem 0 0;
  font-size: var(--text-h2);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.05em;
}
.section-heading .lede {
  max-width: 620px;
  margin: 1.5rem 0 0;
  color: var(--muted);
}

/* ---------- Filter bar ---------- */

.filter-bar { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 2.5rem; }
.filter-button {
  padding: 0.6rem 1.05rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  font-size: 0.88rem;
  cursor: pointer;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.filter-button:hover { border-color: var(--ink); }
.filter-button.active { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* ---------- Project grid ---------- */

.project-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 3.5rem 1.5rem;
}
.project-card--large,
.project-card--wide { grid-column: 1 / -1; }
.project-card.is-hidden { display: none; }

.project-open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.project-visual {
  position: relative;
  overflow: hidden;
  background: var(--paper-2);
  aspect-ratio: 3 / 2;
}
.project-card--large .project-visual { aspect-ratio: 16 / 9; }
.project-card--wide .project-visual { aspect-ratio: 2 / 1; }

/* Taller than the frame so the image can drift on scroll without
   exposing an edge. GSAP owns this element's transform; the hover
   scale is driven there too, so nothing fights over it. */
.project-visual img {
  position: absolute;
  top: -10%;
  left: 0;
  width: 100%;
  height: 120%;
  object-fit: cover;
}

/* Without JS there is no parallax, so sit the image flush in its frame. */
html:not(.motion) .project-visual img {
  top: 0;
  height: 100%;
  transition: transform 600ms var(--ease);
}
html:not(.motion) .project-open:hover .project-visual img { transform: scale(1.03); }

/* Solid rather than frosted: these sit on top of images that parallax, so a
   backdrop-filter would re-blur a moving backdrop on every scroll frame. */
.project-tag {
  position: absolute;
  right: 1rem;
  bottom: 1rem;
  padding: 0.45rem 0.65rem;
  background: rgba(0, 0, 0, 0.82);
  color: #fff;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.project-meta {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 2rem;
  padding-top: 1.1rem;
}
.project-meta h3 { margin: 0; font-size: 1.15rem; font-weight: 600; letter-spacing: -0.015em; }
.project-meta p { margin: 0.35rem 0 0; color: var(--muted); font-size: 0.88rem; }
.project-client {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Recency is the first thing a recruiter looks for, so the year sits in the
   kicker rather than being tucked away in the case study. */
/* Small text, so it needs the darkened accent rather than the tint. */
.project-year {
  color: var(--accent-text);
  font-weight: 700;
}
.project-year::before {
  content: "· ";
  color: var(--muted);
}

/* ---------- Experience timeline ---------- */

.timeline {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}
.timeline li {
  display: grid;
  grid-template-columns: minmax(120px, 0.28fr) 1fr;
  gap: 2rem;
  align-items: start;
  padding: 2rem 0;
  border-bottom: 1px solid var(--line);
  transition: background var(--dur-fast);
}
.timeline li:hover { background: rgba(17, 17, 17, 0.03); }
.timeline-dates {
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
}
.timeline h3 {
  margin: 0;
  font-size: clamp(1.15rem, 1.9vw, 1.5rem);
  font-weight: 500;
  letter-spacing: -0.02em;
}
.timeline-org {
  margin: 0.3rem 0 0.6rem;
  font-family: var(--font-serif);
  font-size: clamp(1.3rem, 2.4vw, 2rem);
  font-style: italic;
  line-height: 1;
}
.timeline li > div > p:last-child {
  max-width: 620px;
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* ---------- Recognition & education ---------- */

.credentials {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  margin-top: clamp(3rem, 6vw, 5rem);
}
.credentials .eyebrow { color: var(--muted); margin-bottom: 1.25rem; }
.credentials ul { margin: 0; padding: 0; list-style: none; }
.credentials li {
  padding: 0.9rem 0;
  border-top: 1px solid var(--line);
}
.credentials li strong,
.credentials li span { display: block; }
.credentials li strong { font-weight: 600; }
.credentials li span { margin-top: 0.2rem; color: var(--muted); font-size: 0.9rem; }

/* ---------- Process ---------- */

.process-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
.process-grid article {
  position: relative;
  overflow: hidden;
  min-height: 250px;
  padding: 1.9rem;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.process-grid span { color: var(--muted); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em; }
.process-grid h3 { margin: 3.5rem 0 0.7rem; font-size: 1.7rem; font-weight: 500; letter-spacing: -0.03em; }
.process-grid p { margin: 0; color: var(--muted); font-size: 0.95rem; }

/* The ink panel that sweeps in on hover. GSAP owns its transform and sets the
   origin to whichever edge the cursor crossed, so there is deliberately no
   CSS transition on it. */
.process-fill {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: 50% 100%;
  pointer-events: none;
}

/* Content sits above the panel and inverts as it arrives. */
.process-grid article > :not(.process-fill) {
  position: relative;
  z-index: 1;
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.process-grid article.is-hovered h3 {
  color: var(--paper);
  transform: translateY(-4px);
}
.process-grid article.is-hovered span { color: var(--accent); }
.process-grid article.is-hovered p { color: var(--muted-dark); }

/* Without the motion layer there is no sweep, so give a plain, honest tint. */
html:not(.motion) .process-grid article { transition: background var(--dur-fast); }
html:not(.motion) .process-grid article:hover { background: var(--paper-2); }

/* ---------- Expertise ---------- */

.expertise-list { border-top: 1px solid var(--line); }
.expertise-item {
  display: grid;
  grid-template-columns: minmax(40px, 0.3fr) 1fr 1.5fr;
  gap: 2rem;
  align-items: start;
  padding: 2rem 0;
  border-bottom: 1px solid var(--line);
  transition: background var(--dur-fast);
}
.expertise-item:hover { background: rgba(17, 17, 17, 0.03); }
.expertise-item span { color: var(--muted); font-size: 0.8rem; font-weight: 700; letter-spacing: 0.1em; }
.expertise-item h3,
.expertise-item p { margin: 0; }
.expertise-item h3 {
  font-size: clamp(1.4rem, 2.3vw, 2.1rem);
  font-weight: 500;
  letter-spacing: -0.03em;
}
.expertise-item p { max-width: 540px; color: var(--muted); font-size: 0.95rem; }

/* ---------- Principles ---------- */

.principles-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
.principles-grid blockquote {
  margin: 0;
  padding: clamp(2rem, 4.5vw, 4.5rem);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-serif);
  font-size: clamp(1.9rem, 3.6vw, 3.4rem);
  font-style: italic;
  line-height: 1.05;
  transition: background var(--dur-fast);
}
.principles-grid blockquote:hover { background: rgba(17, 17, 17, 0.03); }
.principles-grid blockquote p { margin: 0; }

/* Hairline marks matching the rule weight used elsewhere on the page. */
.principle-mark {
  display: block;
  width: clamp(38px, 4vw, 52px);
  height: auto;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
  color: var(--muted);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: square;
  vector-effect: non-scaling-stroke;
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.principles-grid blockquote:hover .principle-mark {
  color: var(--accent);
  transform: translateY(-3px);
}

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

.testimonial-section {
  padding: clamp(5rem, 10vw, 9rem) var(--pad);
  background: var(--ink);
  color: #fff;
}
.testimonial-section .eyebrow { color: var(--muted-dark); }
.testimonial-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  margin-top: 3.5rem;
}
.testimonial-grid figure {
  margin: 0;
  padding-top: 2rem;
  border-top: 1px solid var(--line-dark);
}
.testimonial-grid blockquote {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1.35rem, 1.9vw, 1.75rem);
  font-style: italic;
  line-height: 1.25;
}
.testimonial-grid figcaption { margin-top: 1.75rem; font-size: 0.85rem; }
.testimonial-grid figcaption strong { display: block; font-weight: 600; }
.testimonial-grid figcaption span { color: var(--muted-dark); }

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

.about-intro {
  display: grid;
  grid-template-columns: minmax(60px, 0.35fr) 2fr;
  gap: 2rem;
  margin-bottom: 2.5rem;
}
.about-grid {
  display: grid;
  grid-template-columns: 1.35fr 0.9fr;
  gap: clamp(3rem, 7vw, 7rem);
}
.about-grid h2 {
  margin: 0;
  font-size: clamp(2.6rem, 6vw, 6rem);
  font-weight: 500;
  line-height: 0.98;
  letter-spacing: -0.06em;
  color: var(--ink-recede);
}
/* The serif words are the point of the sentence, so they hold full ink. */
.about-grid h2 em {
  font-family: var(--font-serif);
  font-weight: 400;
  color: var(--text);
}
.about-copy { align-self: end; }
.about-copy p { margin: 0 0 1.2rem; color: var(--muted); }
.about-links { display: flex; flex-wrap: wrap; gap: 1.5rem; margin-top: 2rem; }

.about-facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  margin-top: clamp(3.5rem, 7vw, 6rem);
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}
.about-facts span {
  display: block;
  margin-bottom: 0.4rem;
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.about-facts p { margin: 0; font-size: 0.95rem; }

.skills-cloud {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin-top: 2.5rem;
}
.skills-cloud li {
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.82rem;
  list-style: none;
}
.skills-cloud { padding: 0; }

.experience-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.85rem;
}

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

.contact-section {
  padding: clamp(5rem, 11vw, 10rem) var(--pad);
  background: var(--ink);
  color: #fff;
  text-align: center;
}
.contact-section .eyebrow { color: var(--muted-dark); }
.contact-section h2 {
  max-width: 1000px;
  margin: 1.75rem auto;
  font-family: var(--font-serif);
  font-size: clamp(3rem, 8vw, 8rem);
  font-weight: 400;
  font-style: italic;
  line-height: 0.92;
  letter-spacing: -0.04em;
}
.contact-link {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  border-bottom: 1px solid;
  font-size: clamp(1.05rem, 2vw, 1.5rem);
}
.contact-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
  justify-content: center;
  margin-top: 3rem;
  color: var(--muted-dark);
  font-size: 0.9rem;
}
.contact-meta a { border-bottom: 1px solid transparent; transition: border-color var(--dur-fast); }
.contact-meta a:hover { border-color: currentColor; }

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

.site-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding: 1.5rem var(--pad);
  background: var(--ink);
  border-top: 1px solid var(--line-dark);
  color: #fff;
  font-size: 0.8rem;
}
.site-footer p { margin: 0; }
.site-footer div { display: flex; gap: 1.5rem; }

/* ---------- Case study dialog ---------- */

.case-study {
  width: min(1200px, calc(100% - 2rem));
  max-height: calc(100vh - 2rem);
  padding: 0;
  border: 0;
  background: var(--paper);
  color: var(--text);
  box-shadow: 0 2rem 8rem rgba(0, 0, 0, 0.35);
}
.case-study::backdrop { background: rgba(0, 0, 0, 0.72); backdrop-filter: blur(6px); }

.case-close {
  position: sticky;
  top: 1rem;
  z-index: 3;
  float: right;
  margin: 1rem;
  padding: 0.65rem 1rem;
  border: 0;
  border-radius: 999px;
  background: #fff;
  cursor: pointer;
  box-shadow: 0 0.3rem 1.5rem rgba(0, 0, 0, 0.16);
}

.case-hero { aspect-ratio: 16 / 9; background: var(--paper-2); }
.case-hero img { width: 100%; height: 100%; object-fit: cover; }

.case-content { padding: clamp(2rem, 5vw, 5rem); }
.case-content h2 {
  margin: 0.75rem 0;
  font-size: clamp(2.4rem, 5.5vw, 5.5rem);
  font-weight: 500;
  line-height: 0.95;
  letter-spacing: -0.055em;
}
.case-summary {
  max-width: 800px;
  color: var(--muted);
  font-size: clamp(1.1rem, 1.9vw, 1.6rem);
  line-height: 1.35;
}

/* Live-site link, shown only on projects that have one. */
.case-link {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1.75rem;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid currentColor;
  font-size: 0.95rem;
  font-weight: 600;
}
.case-link[hidden] { display: none; }
.case-link span[aria-hidden] { transition: transform var(--dur-fast) var(--ease); }
.case-link:hover span[aria-hidden] { transform: translate(0.25rem, -0.25rem); }

.case-facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  margin: 3.5rem 0;
  padding: 2rem 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.case-facts span {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.case-facts p { margin: 0.6rem 0 0; color: var(--muted); font-size: 0.95rem; }

.case-story {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3.5rem;
  margin: 4rem 0;
}
.case-story h3 {
  margin: 0.9rem 0 0;
  font-size: clamp(1.7rem, 3vw, 2.8rem);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.035em;
}
.case-story p { margin: 0.9rem 0 0; color: var(--muted); }

.case-gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
.case-gallery figure { margin: 0; grid-column: span 1; }
.case-gallery figure:first-child { grid-column: 1 / -1; }
.case-gallery img { width: 100%; background: var(--paper-2); }
.case-gallery figcaption { margin-top: 0.6rem; color: var(--muted); font-size: 0.8rem; }

.case-note { margin-top: 2.5rem; color: var(--muted); font-size: 0.8rem; }

/* ---------- Case study: open animation ---------- */

/* Driven by CSS rather than GSAP because script.js opens the dialog before
   the deferred motion layer exists — a deep link would otherwise pop in. */
.case-study[open] {
  animation: case-in 0.5s var(--ease) both;
}
.case-study[open]::backdrop {
  animation: case-backdrop-in 0.4s ease both;
}

@keyframes case-in {
  from { opacity: 0; transform: translateY(28px) scale(0.97); }
  to { opacity: 1; transform: none; }
}
@keyframes case-backdrop-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Exit. Declared after the [open] rules on purpose: `.case-study[open]` and
   `.case-study.is-closing` have identical specificity, so source order is
   what lets the exit override the entrance. */
/* An ease-in, not the site's ease-out. Entrances decelerate into place;
   exits should accelerate away. Reusing --ease here dumped most of the fade
   into the first quarter of the animation and read as a snap. */
.case-study.is-closing {
  animation: case-out 0.32s cubic-bezier(0.5, 0, 0.75, 0) both;
}
.case-study.is-closing::backdrop {
  animation: case-backdrop-out 0.32s cubic-bezier(0.5, 0, 0.75, 0) both;
}

@keyframes case-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(18px) scale(0.97); }
}
@keyframes case-backdrop-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* Content fades through when moving between projects. */
.case-hero,
.case-content > *:not(.case-nav) {
  transition: opacity 0.28s var(--ease), transform 0.28s var(--ease);
}
.case-study.is-swapping .case-hero,
.case-study.is-swapping .case-content > *:not(.case-nav) {
  opacity: 0;
  transform: translateY(10px);
}

/* ---------- Case study: project navigation ---------- */

.case-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-top: clamp(3rem, 6vw, 5rem);
  border-top: 1px solid var(--line);
}
.case-nav-btn {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.75rem 0;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: opacity var(--dur-fast);
}
.case-nav-btn--next { text-align: right; align-items: flex-end; }
.case-nav-btn:hover { opacity: 0.6; }
.case-nav-btn[disabled] { opacity: 0.25; cursor: default; }

.case-nav-label {
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.case-nav-title {
  font-size: clamp(1.05rem, 2vw, 1.5rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

/* ---------- Motion initial states ----------
   Only applied when `.motion` is on <html>, which the head script adds for
   JS-capable visitors who have not asked for reduced motion. motion.js
   animates these in; if it cannot run it drops the class and everything
   returns to its natural, visible state. */

html.motion .hero-topline > *,
html.motion .hero-copy,
html.motion .hero-footer .text-link,
html.motion .metrics div,
html.motion .clients > .eyebrow,
html.motion .client-grid img,
/* Only the leaf elements are hidden — never the wrapper div, whose children
   are animated individually and would otherwise be trapped behind it. */
html.motion .section-heading > .section-number,
html.motion .section-heading > div > *,
html.motion .filter-bar,
html.motion .project-card,
html.motion .process-grid article,
html.motion .expertise-item,
html.motion .principles-grid blockquote,
html.motion .testimonial-grid figure,
html.motion .about-intro > *,
html.motion .about-grid > *,
html.motion .about-facts > div,
html.motion .timeline li,
html.motion .credentials > div,
html.motion .skills-cloud li,
html.motion .experience-strip,
html.motion .contact-section > * {
  opacity: 0;
}

html.motion .hero-line__inner { transform: translateY(105%); }

/* The header retracts on scroll-down, so hint it only where that happens. */
html.motion .site-header { will-change: transform; }

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
  .about-grid { grid-template-columns: 1fr; }
  .testimonial-grid { grid-template-columns: 1fr; }
  .process-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 800px) {
  .site-header { flex-wrap: wrap; align-items: center; }
  .menu-toggle { display: block; }
  .site-nav {
    position: absolute;
    top: 100%;
    right: 0;
    left: 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0 var(--pad) 1.5rem;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
  }
  .site-nav.is-open { display: flex; }
  .site-nav a { padding: 0.9rem 0; border-bottom: 1px solid var(--line); }
  .nav-cta { margin-top: 1rem; text-align: center; }

  .hero { min-height: 0; }
  .hero-topline,
  .hero-footer { flex-direction: column; align-items: flex-start; }
  .hero-footer .text-link { margin-top: 1.75rem; }

  .metrics { grid-template-columns: repeat(2, 1fr); }
  .metrics div:nth-child(2n) { border-right: 0; }
  .metrics div:nth-child(-n + 2) { border-bottom: 1px solid var(--line); }

  .section-heading,
  .about-intro { grid-template-columns: 1fr; gap: 1rem; }

  .project-grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .project-visual,
  .project-card--large .project-visual,
  .project-card--wide .project-visual { aspect-ratio: 3 / 2; }

  .expertise-item { grid-template-columns: 40px 1fr; }
  .expertise-item p { grid-column: 2; }
  .timeline li { grid-template-columns: 1fr; gap: 0.6rem; }
  .credentials { grid-template-columns: 1fr; }
  .principles-grid { grid-template-columns: 1fr; }

  .about-facts { grid-template-columns: 1fr; gap: 1.5rem; }
  .case-facts,
  .case-story,
  .case-gallery { grid-template-columns: 1fr; }
  .site-footer { flex-direction: column; }
}

@media (max-width: 520px) {
  .process-grid { grid-template-columns: 1fr; }
  .process-grid h3 { margin-top: 2rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
  .project-open:hover .project-visual img { transform: none; }
  .project-visual img { top: 0; height: 100%; }
  .site-header { will-change: auto; }
}
