/* ============================================
   THE PATH — round 2 design system
   Warm dark, one ink, one ember accent.
   Accent lives ONLY on the Path + interactive states.
   ============================================ */

/* ============================================
   VARIABLES
   ============================================ */

:root {
  /* Palette — 1 background + 1 ink + 1 accent, max.
     Two fields, same tokens: dark sections use dark/paper as bg/ink,
     light sections swap the roles (2026-07-05 amendment §1). */
  --color-dark: #14110D;
  --color-paper: #EFE7DC;
  --color-ember: #E0714A;

  --color-bg: var(--color-dark);
  --color-ink: var(--color-paper);
  --color-accent: var(--color-ember);

  /* Typography */
  --font-display: 'League Spartan', sans-serif;
  --font-body: 'IBM Plex Sans', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;

  /* Compressed scale: huge display, one body, one mono */
  --text-mono: 0.8125rem;
  --text-body: 1rem;

  /* Rail grid — the page's single text axis */
  --rail-w: 130px;
  --gutter-w: 110px;
  --rail-mobile: 3rem;

  /* Layout */
  --container-max: 1200px;
  --pad: 1.5rem;

  /* One shared corner radius — every rounded block consumes this
     (logo block, buttons, project visuals). No per-element radii. */
  --radius: 3px;

  /* Z-index scale */
  --z-under: 0;
  --z-base: 1;
  --z-path: 2;
  --z-sticky: 100;
  --z-overlay: 500;

  /* Motion: 150–250ms micro, ease-out */
  --t-fast: 160ms ease-out;
  --t-med: 220ms ease-out;
}

/* Derived steps re-resolve per field (custom properties compute where
   they are declared, so the formulas must exist in both scopes). */
:root,
.section--light,
.footer--light {
  /* Ink opacity steps (no separate gray ramp) */
  --ink-75: color-mix(in srgb, var(--color-ink) 75%, transparent);
  --ink-55: color-mix(in srgb, var(--color-ink) 55%, transparent);
  --ink-38: color-mix(in srgb, var(--color-ink) 38%, transparent);
  --ink-16: color-mix(in srgb, var(--color-ink) 16%, transparent);
  --ink-8: color-mix(in srgb, var(--color-ink) 8%, transparent);

  /* Accent steps — Path + interactive states only */
  --accent-55: color-mix(in srgb, var(--color-accent) 55%, transparent);
  --accent-25: color-mix(in srgb, var(--color-accent) 25%, transparent);
}

/* ============================================
   LIGHT FIELD — warm paper, roles swapped
   Authored, section-scale inversions. No toggle.
   The ember deepens toward the ink so it reads
   on paper (amendment: accent must read on both).
   ============================================ */

.section--light,
.footer--light {
  --color-bg: var(--color-paper);
  --color-ink: var(--color-dark);
  /* 68% ember / 32% ink clears 4.5:1 on paper for mono-size hover text */
  --color-accent: color-mix(in srgb, var(--color-ember) 68%, var(--color-dark));

  background-color: var(--color-bg);
  color: var(--color-ink);
}

/* ============================================
   RESET
   ============================================ */

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

html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-body);
  line-height: 1.65;
  color: var(--color-ink);
  background-color: var(--color-bg);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, video, svg {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: var(--color-ink);
  text-decoration: none;
  transition: color var(--t-fast);
}

ul, ol {
  list-style: none;
}

button {
  cursor: pointer;
  border: none;
  background: none;
  font-family: inherit;
  color: inherit;
}

::selection {
  background-color: var(--color-accent);
  color: var(--color-bg);
}

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

/* ============================================
   TYPOGRAPHY HELPERS
   ============================================ */

.text-mono {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  font-variant-numeric: tabular-nums;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================
   THE PATH — SVG spine (geometry built in JS)
   ============================================ */

/* The path rides ABOVE section backgrounds (light fields would hide it)
   but stays out of the way: it only ever draws in the empty rail gutter. */
.path-svg {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: var(--z-path);
  overflow: visible;
}

/* Main is an opaque layer: it slides up over the sticky footer (reveal)
   and light sections paint their own field on top of it. */
.header, main {
  position: relative;
  z-index: var(--z-base);
}

main {
  background-color: var(--color-bg);
}

.path-line {
  fill: none;
  stroke: var(--accent-55);
  stroke-width: 2;
  stroke-linecap: round;
}

/* Bright tip that rides the drawing edge — "focus" brightening */
.path-glow {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2;
  stroke-linecap: round;
  opacity: 0;
  transition: opacity 300ms ease-out;
}

.path-stub {
  fill: none;
  stroke: var(--accent-55);
  stroke-width: 2;
  stroke-linecap: round;
  transition: stroke-dashoffset 420ms ease-out;
}

.path-dot {
  fill: var(--color-bg);
  stroke: var(--color-accent);
  stroke-width: 2;
  opacity: 0;
  transition: opacity 240ms ease-out, fill 240ms ease-out;
}

.path-dot.is-lit {
  opacity: 1;
}

/* Current / terminal states: filled ember */
.path-dot--current.is-lit {
  fill: var(--color-accent);
}

/* ============================================
   HEADER
   ============================================ */

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-sticky);
}

/* Frosted bar lives on a pseudo, NOT on .header itself: backdrop-filter makes
   its element a containing block for fixed descendants, which would trap the
   fixed mobile menu inside the bar instead of the viewport. The pseudo keeps
   the glass while .header stays a plain (fixed) stacking context. */
.header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: color-mix(in srgb, var(--color-bg) 84%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--ink-8);
}

.header__container {
  display: flex;
  align-items: center;
  gap: 1rem;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0.875rem var(--pad);
}

.header__logo {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  white-space: nowrap;
  margin-right: auto;
}

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

.header__logo-mark {
  display: inline-flex;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: var(--radius);
  overflow: hidden; /* clips the solid block to the shared radius */
}

.header__logo-mark svg {
  width: 100%;
  height: 100%;
}

.header__logo-text {
  display: none;
  padding-top: 0.2em; /* League Spartan optical baseline */
}

@media (min-width: 480px) {
  .header__logo-text { display: inline; }
}

.header__nav {
  display: none;
  gap: 2rem;
}

@media (min-width: 768px) {
  .header__nav { display: flex; }
}

.header__nav a {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-55);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
}

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

/* Scrollspy: the section you are in — ember plus an underline
   (non-color cue for WCAG 1.4.1); border space reserved on the base
   styles so the toggle never shifts layout */
.header__nav a.is-current,
.header__mobile-link.is-current {
  color: var(--color-accent);
  border-bottom-color: var(--accent-55);
}

.header__lang {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-55);
  min-height: 44px;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

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

/* Hamburger — sits ABOVE the open panel (its own stacking level) so the
   close control (the X) is always reachable over the full-screen menu. */
.header__hamburger {
  position: relative;
  z-index: calc(var(--z-overlay) + 1);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 10px;
}

.header__hamburger span {
  display: block;
  width: 22px;
  height: 2px;
  background-color: var(--color-ink);
  transition: transform var(--t-med), opacity var(--t-med);
}

.header__hamburger.is-active span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.header__hamburger.is-active span:nth-child(2) {
  opacity: 0;
}

.header__hamburger.is-active span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

@media (min-width: 768px) {
  .header__hamburger { display: none; }
}

/* Mobile menu — opaque warm-dark full-screen surface, anchored to the top.
   Never transparent over content; scrolls if it ever exceeds the viewport.
   Subtle 200ms fade on entry/exit (allow-discrete toggles display around it);
   reduced motion zeroes the transition (see the reduce block) → instant. */
.header__mobile-menu {
  display: none;
  opacity: 0;
  position: fixed;
  inset: 0;
  background-color: var(--color-dark);
  z-index: var(--z-overlay);
  padding: 5.5rem var(--pad) 2rem;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
  overflow-y: auto;
  transition: opacity var(--t-med), display var(--t-med) allow-discrete;
}

.header__mobile-menu.is-open {
  display: flex;
  opacity: 1;
}

@starting-style {
  .header__mobile-menu.is-open {
    opacity: 0;
  }
}

.header__mobile-nav {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
}

/* Nav items — one consistent scale; the language toggle is a peer item */
.header__mobile-link {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  color: var(--ink-55);
  min-height: 44px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
}

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

/* ============================================
   LAYOUT — container + rail grid
   ============================================ */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--pad);
}

.section {
  padding: 5.5rem 0;
}

@media (min-width: 768px) {
  .section { padding: 8rem 0; }
}

/* Rail grid: mobile = single column, content pushed right of the path rail.
   Desktop = dates | path gutter | content. One text axis all the way down. */
.section__grid {
  display: grid;
  grid-template-columns: 1fr;
}

.section__label {
  grid-column: 1;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  font-weight: 400;
  color: var(--ink-38);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  padding-left: var(--rail-mobile);
  margin-bottom: 2rem;
}

.section__content {
  grid-column: 1;
  padding-left: var(--rail-mobile);
}

@media (min-width: 768px) {
  .section__grid {
    grid-template-columns: var(--rail-w) var(--gutter-w) 1fr;
  }

  .section__label {
    grid-column: 1;
    grid-row: 1;
    text-align: right;
    padding-left: 0;
    margin-bottom: 0;
    position: sticky;
    top: 6.5rem;
    align-self: start;
    line-height: 1.7;
  }

  .section__content {
    grid-column: 3;
    grid-row: 1;
    padding-left: 0;
  }
}

/* ============================================
   HERO
   ============================================ */

.hero {
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-top: 5rem;
  padding-bottom: 6rem;
}

.hero__title {
  display: flex;
  flex-direction: column;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 3.25rem;
  line-height: 0.98;
  letter-spacing: -0.03em; /* tightened for all-caps display so 11rem holds 2 rows */
  text-transform: uppercase;
  margin-bottom: 1.75rem;
}

/* Entrance: each line rises out of its own clip box. The padding/margin
   pair extends the clip past ascenders/descenders without moving layout
   (flex column → no margin collapse, the offsets cancel exactly). */
.hero__line {
  display: block;
  overflow: clip;
  padding-block: 0.12em;
  margin-block: -0.12em;
}

.hero__line-inner {
  display: block;
  transform: translateY(118%);
  animation: hero-line-in 700ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

.hero__line:nth-child(2) .hero__line-inner {
  animation-delay: 120ms;
}

.hero__subtitle {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 1.125rem;
  color: var(--ink-75);
  max-width: 34ch;
  margin-bottom: 1rem;
}

@keyframes hero-line-in {
  to { transform: none; }
}

/* CTA fades in opacity-only — its transform belongs to the magnetic hover */
@keyframes hero-fade-in {
  to { opacity: 1; }
}

.hero__grounding {
  color: var(--ink-55);
  letter-spacing: 0.04em;
  margin-bottom: 3rem;
}

/* Scramble — per-character reserved slots (zero reflow, even proportional).
   The final glyph (hidden) locks each slot's width; the cycle glyph is
   painted on top absolutely, so it never changes the box or the wrap points.
   Hidden until JS builds the slots so settled text never flashes first;
   no-JS and reduced-motion both show the settled text from first paint. */
@media (prefers-reduced-motion: no-preference) {
  .js [data-scramble] {
    visibility: hidden;
  }
}

.scramble__word {
  display: inline-block;
  white-space: nowrap;
}

.scramble__char {
  position: relative;
  display: inline-block;
}

.scramble__final {
  visibility: hidden;
}

.scramble__char.is-revealed .scramble__final {
  visibility: visible;
}

/* Left-anchored to the slot: the cycle glyph's left edge matches the final
   glyph's, so a character never shifts horizontally when it resolves. */
.scramble__cycle {
  position: absolute;
  left: 0;
  top: 0;
  color: var(--ink-38);
}

.scramble__char.is-revealed .scramble__cycle {
  display: none;
}

/* One button grammar — LET'S TALK and SEND share this exactly (§6).
   Focus is the global :focus-visible ring, identical for both. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  min-width: 44px;
  padding: 0.9375rem 2.25rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-accent);
  border: 1px solid var(--accent-55);
  border-radius: var(--radius);
  transition: color var(--t-fast), background-color var(--t-fast), border-color var(--t-fast);
  will-change: transform;
}

.btn:hover {
  background-color: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-bg);
}

/* Pending (form submitting) */
.btn:disabled {
  opacity: 0.55;
  cursor: default;
}

/* Hero CTA carries only its entrance — the button grammar is .btn */
.hero__cta {
  opacity: 0;
  animation: hero-fade-in 480ms ease-out 640ms forwards;
}

@media (min-width: 768px) {
  .hero__title {
    font-size: 6.5rem;
    margin-bottom: 2.25rem;
  }

  /* Single line on desktop, both languages — released from the 34ch cap */
  .hero__subtitle {
    font-size: 1.25rem;
    max-width: none;
  }
}

@media (min-width: 1280px) {
  /* Ceiling is the largest that holds the two authored rows in BOTH languages
     inside the shared 1200px container — so the headline stays left-aligned
     with the logo and every section. (11rem would need a wider measure than
     the container gives, which is what broke the alignment.) */
  .hero__title {
    font-size: clamp(6.5rem, 11vw, 10rem);
  }

  .hero__subtitle {
    font-size: clamp(1.25rem, 1.5vw, 1.625rem);
  }
}

/* ============================================
   INTRO
   ============================================ */

.intro__text {
  font-weight: 300;
  font-size: 1.25rem;
  line-height: 1.7;
  color: var(--color-ink);
  max-width: 34em;
  margin-bottom: 0;
}

@media (min-width: 768px) {
  .intro__text {
    font-size: 1.375rem;
  }
}

@media (min-width: 1280px) {
  .intro__text {
    font-size: clamp(1.375rem, 1.6vw, 1.625rem);
  }
}

/* ============================================
   JOURNEY — the fork lives here
   ============================================ */

.journey__list {
  display: flex;
  flex-direction: column;
  gap: 4.5rem;
  padding-left: var(--rail-mobile);
}

.journey__entry {
  display: block;
}

.journey__period {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink-38);
  margin-bottom: 0.375rem;
}

.journey__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.375rem;
  letter-spacing: -0.01em;
  line-height: 1.15;
  margin-bottom: 0.25rem;
}

.journey__line {
  color: var(--ink-55);
  margin-bottom: 0;
}

/* Extra air where the branch departs — the fork needs room to breathe */
.journey__entry--branch {
  margin-top: 4rem;
}

@media (min-width: 768px) {
  .journey__list {
    gap: 5.5rem;
    padding-left: 0;
    margin-top: 0.25rem;
  }

  .journey__entry {
    display: grid;
    grid-template-columns: var(--rail-w) var(--gutter-w) 1fr;
    align-items: baseline;
  }

  .journey__period {
    grid-column: 1;
    text-align: right;
    margin-bottom: 0;
  }

  .journey__body {
    grid-column: 3;
  }

  .journey__title {
    font-size: 1.625rem;
  }

  .journey__entry--branch {
    margin-top: 6.5rem;
  }
}

@media (min-width: 1280px) {
  .journey__title {
    font-size: clamp(1.625rem, 1.8vw, 1.875rem);
  }
}

/* Journey uses its own grid rows: label above the list */
.journey .section__label {
  position: static;
  margin-bottom: 3.5rem;
}

@media (min-width: 768px) {
  .journey .section__grid {
    grid-template-rows: auto auto;
  }

  .journey .section__label {
    grid-row: 1;
    grid-column: 1;
  }

  .journey__list {
    grid-row: 2;
    grid-column: 1 / -1;
  }
}

/* ============================================
   WHAT I DO NOW — typographic columns, no boxes
   ============================================ */

.now__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
}

.now__item {
  border-top: 1px solid var(--ink-16);
  padding-top: 1.25rem;
}

.now__index {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-38);
  margin-bottom: 1rem;
}

.now__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.25rem;
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin-bottom: 0.625rem;
}

.now__body {
  color: var(--ink-55);
  margin-bottom: 0;
}

@media (min-width: 768px) {
  .now__grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 2.5rem;
  }
}

@media (min-width: 1280px) {
  .now__title {
    font-size: clamp(1.25rem, 1.3vw, 1.375rem);
  }
}

/* ============================================
   PROJECTS — blocks hanging off the strands
   ============================================ */

.projects__list {
  display: flex;
  flex-direction: column;
  gap: 6rem;
}

.project__label {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-38);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  margin-bottom: 0.75rem;
}

.project__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.75rem;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin-bottom: 1rem;
}

.project__desc {
  color: var(--ink-75);
  line-height: 1.7;
  max-width: 60ch;
}

.project__testimonial {
  border-left: 2px solid var(--ink-16);
  padding-left: 1.25rem;
  margin: 1.5rem 0;
  color: var(--ink-75);
  font-style: italic;
}

.project__closing {
  font-weight: 500;
  color: var(--color-ink);
}

.project__links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.75rem;
  margin-top: 1.25rem;
}

.project__link {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--color-ink);
  border-bottom: 1px solid var(--ink-16);
  padding-bottom: 2px;
  transition: color var(--t-fast), border-color var(--t-fast);
}

.project__link:hover {
  color: var(--color-accent);
  border-color: var(--color-accent);
}

.project__visual {
  margin-top: 2rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Project visual — warm-monochrome screenshot mounted on a warm-paper mat
   (gallery-frame register): the paper surface pops the dark-UI shots off the
   dark section, the frame clips a hover zoom, and the whole framed photo tilts
   (JS, pointer:fine). Amendment D. */

/* The paper mat */
.project__image {
  background-color: var(--color-paper);
  padding: 0.6rem;
  border: 1px solid color-mix(in srgb, var(--color-dark) 14%, transparent);
  border-radius: var(--radius);
  box-shadow: 0 4px 18px color-mix(in srgb, var(--color-dark) 45%, transparent);
  transition: transform 180ms ease-out;
}

/* The clipped image frame (inside the mat padding) */
.project__frame {
  position: relative;
  overflow: hidden;
  border-radius: calc(var(--radius) - 1px);
  aspect-ratio: 3 / 2;
  background-color: color-mix(in srgb, var(--color-dark) 10%, var(--color-paper));
}

.project__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Warm monochrome — full sepia for a strongly warm tone (grayscale()/sepia()
     clamp at 1, so Adrian's grayscale(8) sepia(2.07) renders as this) */
  filter: grayscale(1) sepia(1) brightness(1.05) contrast(0.97);
  transition: filter var(--t-med), transform var(--t-med);
}

/* Ember hover tint (multiply) */
.project__frame::after {
  content: '';
  position: absolute;
  inset: 0;
  background-color: var(--color-accent);
  opacity: 0;
  mix-blend-mode: multiply;
  transition: opacity var(--t-med);
  pointer-events: none;
}

/* Hover: warm-mono lifts to full colour, ember tint lands */
.project__image:hover .project__frame img {
  filter: grayscale(0) sepia(0) brightness(1) contrast(1);
}

.project__image:hover .project__frame::after {
  opacity: 0.2;
}

/* Hover zoom is motion → gated behind no-preference (tilt is JS-gated too) */
@media (prefers-reduced-motion: no-preference) {
  .project__image:hover .project__frame img {
    transform: scale(1.04);
  }
}

@media (min-width: 768px) {
  .project {
    display: flex;
    align-items: flex-start;
    gap: 3.5rem;
  }

  .project__content {
    flex: 1;
  }

  .project__visual {
    flex: 0 0 42%;
    margin-top: 0.5rem;
  }

  .project__name {
    font-size: 2rem;
  }

  .projects__list {
    gap: 8rem;
  }
}

@media (min-width: 1280px) {
  .project__name {
    font-size: clamp(2rem, 2vw, 2.25rem);
  }
}

/* ============================================
   CONTACT — the path delivers you here
   ============================================ */

.contact {
  padding-top: 9rem;
}

@media (min-width: 768px) {
  .contact { padding-top: 13rem; }
}

.contact__heading {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2rem;
  letter-spacing: -0.02em;
  line-height: 1.08;
  max-width: 20ch;
  margin-bottom: 3.5rem;
}

@media (min-width: 768px) {
  .contact__heading {
    font-size: 2.75rem;
  }
}

@media (min-width: 1280px) {
  .contact__heading {
    font-size: clamp(2.75rem, 3.2vw, 3.5rem);
  }
}

/* Channels LEFT, form RIGHT (desktop) — keeps the final screen compact
   so the footer reveal lands near viewport height */
.contact__split {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4rem;
}

@media (min-width: 768px) {
  .contact__split {
    grid-template-columns: 1fr 1fr;
    gap: 4rem;
    align-items: start;
  }
}

/* Grid blowout guard — long mono strings must not widen the columns */
.contact__split > * {
  min-width: 0;
}

.contact__channels {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.contact__channel-label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-38);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  margin-bottom: 0.375rem;
}

/* Click-to-copy email — the primary act of the section */
.contact__copy {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.375rem 1rem;
  font-family: var(--font-mono);
  font-size: 1.125rem;
  color: var(--color-ink);
  padding: 0;
  min-height: 44px;
  transition: color var(--t-fast);
}

.contact__copy-value {
  border-bottom: 1px solid var(--ink-16);
  padding-bottom: 2px;
  transition: border-color var(--t-fast);
}

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

.contact__copy:hover .contact__copy-value {
  border-color: var(--color-accent);
}

.contact__copy-done {
  font-size: var(--text-mono);
  color: var(--color-accent);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--t-fast), transform var(--t-fast);
}

.contact__copy.is-copied .contact__copy-done {
  opacity: 1;
  transform: none;
}

.contact__wa {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 1.125rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-ink);
  min-height: 44px;
}

.contact__wa span {
  border-bottom: 1px solid var(--ink-16);
  padding-bottom: 2px;
  transition: border-color var(--t-fast);
}

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

.contact__wa:hover span {
  border-color: var(--color-accent);
}

@media (min-width: 768px) {
  .contact__copy,
  .contact__wa {
    font-size: 1.375rem;
  }
}

/* Form — stays, but visually subordinate to the direct channels */
.contact__form-heading {
  color: var(--ink-38);
  margin-bottom: 1.75rem;
}

.contact__form {
  max-width: 460px;
}

/* Honeypot — off-screen (NOT display:none, so bots still fill it) */
.contact__hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact__field {
  margin-bottom: 1.75rem;
}

.contact__label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-38);
  margin-bottom: 0.375rem;
}

.contact__input,
.contact__textarea {
  width: 100%;
  padding: 0.5rem 0;
  background-color: transparent;
  border: none;
  border-bottom: 1px solid var(--ink-16);
  border-radius: 0;
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--text-body);
  min-height: 44px;
  transition: border-color var(--t-fast);
}

.contact__input:focus,
.contact__textarea:focus {
  outline: none;
  border-bottom-color: var(--color-accent);
}

.contact__textarea {
  resize: vertical;
  min-height: 100px;
}

.contact__form-status {
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-55);
}

/* ============================================
   FOOTER
   ============================================ */

/* Reveal: the footer pins to the viewport bottom (sticky, z below main)
   and the opaque page slides up over it. Pure CSS — no measured heights,
   works at 375px; body overflow-x is `clip`, which keeps sticky alive. */
.footer {
  position: sticky;
  bottom: 0;
  z-index: var(--z-under);
  padding: 3rem 0 2.5rem;
}

@media (min-width: 768px) {
  .footer {
    padding: 4.5rem 0 3rem;
  }
}

.footer__inner {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  color: var(--ink-38);
}

.footer__meta {
  margin-bottom: 0;
  font-variant-numeric: tabular-nums;
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.footer__links a {
  color: var(--ink-55);
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

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

@media (min-width: 768px) {
  .footer__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
  }
}

/* ============================================
   SCROLL REVEALS — short-travel, once-only
   ============================================ */

.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 480ms cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 480ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

.reveal-child {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 440ms cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 440ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.reveal-stagger.is-visible .reveal-child { opacity: 1; transform: none; }
.reveal-stagger.is-visible .reveal-child:nth-child(1) { transition-delay: 0ms; }
.reveal-stagger.is-visible .reveal-child:nth-child(2) { transition-delay: 60ms; }
.reveal-stagger.is-visible .reveal-child:nth-child(3) { transition-delay: 120ms; }
.reveal-stagger.is-visible .reveal-child:nth-child(4) { transition-delay: 180ms; }
.reveal-stagger.is-visible .reveal-child:nth-child(5) { transition-delay: 240ms; }
.reveal-stagger.is-visible .reveal-child:nth-child(6) { transition-delay: 300ms; }

/* ============================================
   REDUCED MOTION — everything gated, Path pre-drawn
   ============================================ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0s !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0s !important;
  }

  .reveal,
  .reveal-child,
  .hero__line-inner,
  .hero__cta {
    opacity: 1 !important;
    transform: none !important;
    transition-delay: 0s !important;
  }

  .path-line,
  .path-stub {
    stroke-dasharray: none !important;
    stroke-dashoffset: 0 !important;
  }

  .path-glow {
    display: none !important;
  }

  .path-dot {
    opacity: 1 !important;
  }
}
