:root {
  --bg: #FDF6EC;
  --ink: #1C1C1C;
  --accent: #277676;

  --step-0: 18px;
  --step-1: 22px;
  --step-2: 28px;
  --step-3: 36px;
  --step-4: 45px;

  --hero: 64px;
  --hero-min: 48px;
  --hero-mobile: 32px;

  --leading: 1.6;
  --measure: 68ch;
  --gap-section: 96px;
  --gap-section-mobile: 64px;

  --wordmark: "Cormorant Garamond", Georgia, serif;
}

@font-face {
  font-family: Poppins;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/poppins-400.woff2") format("woff2");
}

@font-face {
  font-family: Poppins;
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/poppins-600.woff2") format("woff2");
}

@font-face {
  font-family: "Cormorant Garamond";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/cormorant-600.woff2") format("woff2");
}

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

body, h1, h2, h3, p, ul {
  margin: 0;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-size: var(--step-0);
  line-height: var(--leading);
  font-family: Poppins, system-ui, sans-serif;
}

header,
main,
footer {
  max-width: var(--measure);
  margin-left: auto;
  margin-right: auto;
  padding-left: clamp(24px, 5vw, 48px);
  padding-right: clamp(24px, 5vw, 48px);
}

main section {
  margin-top: var(--gap-section);
}

header {
  text-align: center;
  padding-top: 96px;
}

h1 {
  font-family: var(--wordmark);
  font-size: clamp(var(--hero-min), 8vw, var(--hero));
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.05;
}

.tagline {
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 14px;
  font-weight: 400;
  color: color-mix(in srgb, var(--ink) 70%, var(--bg));
  margin-top: 20px;
}

.rule {
  width: 64px;
  margin: 32px auto 0;
  border: 0;
  border-top: 1px solid currentColor;
  opacity: 0.25;
}

h2 {
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 24px;
}

p {
  font-weight: 400;
}

main p {
  color: color-mix(in srgb, var(--ink) 72%, var(--bg));
  max-width: var(--measure);
  margin-top: 20px;
}

.lead {
  font-size: var(--step-1);
  line-height: 1.5;
}

.projects {
  list-style: none;
  padding: 0;
}

.projects .project + .project {
  margin-top: 32px;
}

.project-what {
  color: color-mix(in srgb, var(--ink) 90%, var(--bg));
}

.project-meta {
  font-size: 15px;
  margin-top: 6px;
}

.project-tag {
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 12px;
  color: color-mix(in srgb, var(--ink) 70%, var(--bg));
  margin-right: 10px;
}

.project-name {
  color: color-mix(in srgb, var(--ink) 70%, var(--bg));
}

a.project-name {
  color: var(--accent);
}

footer {
  margin-top: var(--gap-section);
  padding-bottom: 96px;
  text-align: center;
}

footer p {
  font-size: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ink) 70%, var(--bg));
}

a {
  color: var(--accent);
  text-decoration: underline;
}

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

/* Paper grain. An inline data URI, so it is still zero network requests and
   ~400 bytes. Alpha is baked into the SVG filter rather than declared in CSS,
   which keeps the transparency gate meaningful. Overrides the image ban in
   PRD line 17 — see DECISIONS. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.11'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

body > * {
  position: relative;
  z-index: 1;
}

/* Scroll-driven depth. Pure CSS — the no-script gate forbids JS and a parallax
   library would blow the transfer budget. Layers move at different rates so the
   page reads as depth rather than as one sliding block. Every rule sits behind
   @supports, so browsers without scroll-timeline get the static page, which is
   still the designed page. Overrides PRD line 17 (no animation) — see DECISIONS. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    h1 {
      animation: drift-far linear both;
      animation-timeline: scroll();
      animation-range: 0 80vh;
    }

    .tagline {
      animation: drift-mid linear both;
      animation-timeline: scroll();
      animation-range: 0 80vh;
    }

    .rule {
      animation: widen linear both;
      animation-timeline: scroll();
      animation-range: 0 40vh;
    }

    /* #intro is above the fold, so a view() rise is already complete at load —
       and fading in the first thing read is wrong anyway. It drifts instead,
       continuing the 100 -> 58 -> 28 depth ramp set by the wordmark and tagline. */
    #intro {
      animation: drift-near linear both;
      animation-timeline: scroll();
      animation-range: 0 80vh;
    }

    /* paragraphs inside the intro carry their own timelines, so the section
       reads as it unrolls rather than arriving as one block */
    #intro p {
      animation: rise-near linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 18%;
    }

    main section:not(#intro) {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 30%;
    }

    /* each entry runs its own timeline, so the stagger comes from position on
       the page rather than from hardcoded per-item delays */
    .project {
      animation: rise-near linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 22%;
    }

    footer {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 40%;
    }
  }
}

@keyframes drift-far {
  to { transform: translateY(100px); }
}

@keyframes drift-mid {
  to { transform: translateY(58px); }
}

@keyframes drift-near {
  to { transform: translateY(28px); }
}

@keyframes widen {
  from { transform: scaleX(0.35); opacity: 0.45; }
  to { transform: scaleX(1); opacity: 1; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(56px); }
  to { opacity: 1; transform: none; }
}

@keyframes rise-near {
  from { opacity: 0; transform: translateY(34px); }
  to { opacity: 1; transform: none; }
}

@media (max-width: 600px) {
  :root {
    --hero: var(--hero-mobile);
    --hero-min: var(--hero-mobile);
    --gap-section: var(--gap-section-mobile);
  }

  header {
    padding-top: 56px;
  }

  footer {
    padding-bottom: 56px;
  }
}
