/* =========================================================================
   PORTFOLIO — single stylesheet
   Sections:
   01. Tokens & reset
   02. Base & typography
   03. Preloader
   04. Header / nav (desktop)
   05. Mobile menu
   06. Hero (+ entrance reveal animations)
   07. Skills marquee
   08. Section heads (shared)
   09. Project cards
   10. Expanded project view (View Transitions)
   11. About
   12. Contact
   13. Footer
   14. Reduced motion
   15. Responsive (≤768px)
   ========================================================================= */

/* ====================== 01. TOKENS & RESET ====================== */
:root {
  /* Palette — "forest sheet": gesso paper, ink text, forest as the system.
     The accent appears on labels, dots, buttons, borders, links and dark
     surfaces — never as a lone note. Change these six hexes to retheme the
     entire site: js/palette.js reads them at runtime for the canvas too. */
  --paper:    #eef0ec;
  --paper-rgb: 238, 240, 236;   /* channels of --paper, for alpha variants */
  --ink:      #14161a;          /* body text only */
  --ink-rgb:  20, 22, 26;

  --forest:      #1b4332;       /* the accent: labels, links, solid buttons */
  --forest-rgb:  27, 67, 50;    /* channels, for alpha variants */
  --forest-mid:  #2d6a4f;       /* hover state of solid forest surfaces */
  --forest-deep: #0f2a1e;       /* dark surfaces: preloader, menu, image beds */
  --forest-glow: #74a892;       /* sage: accents ON dark forest surfaces */
  --graphite: #4f5a55;          /* muted text, warmed toward the accent */
  --line:     rgba(var(--forest-rgb), 0.30);  /* hairlines, visibly green */
  --paper-raise: #f5f7f3;   /* cards / form fields, a touch greener */


  /* Type */
  --font-display: "Archivo", system-ui, sans-serif;  /* used with wdth 125 */
  --font-body:    "Archivo", system-ui, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, monospace;

  /* Rhythm */
  --gutter: clamp(1.25rem, 4vw, 4rem);
  --section-gap: clamp(5rem, 12vh, 9rem);

  /* Readability veil — a feathered paper wash UNDER text. Translucent, so
     the dot field still reads through it; contained, so it never spills
     onto neighbouring elements (a box-shadow spread used to bleed over the
     project hero image). Lower the alpha to let more field show through. */
  --veil:      rgba(var(--paper-rgb), 0.70);

  /* Motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

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

img { display: block; max-width: 100%; height: auto; }
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea { font: inherit; color: inherit; }

/* ====================== 02. BASE & TYPOGRAPHY ====================== */
html { scroll-behavior: smooth; }

body {
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* --- Background ---
   Stack, back to front:
     canvas.bg-canvas  interactive magnetic dot field (js/dots-bg.js)     (z -2)
     body::after       paper grain                                       (z -1)
   Both fixed and pointer-transparent; content renders untouched above. */
.bg-canvas {
  position: fixed;
  inset: 0;
  /* canvas is a replaced element: inset alone does NOT stretch it, so its
     CSS box must be set explicitly or it stays at the default 300x150 */
  width: 100%;
  height: 100%;
  z-index: -2;
  pointer-events: none;   /* the module listens on window, not the canvas */
}

/* Paper grain: a breath of physical texture over everything */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Readability guarantee: text blocks get a feathered paper wash behind them.
   Implemented as an inset ::before with a radial mask — the wash fades out
   INSIDE the element's own box, so there is no hard edge and no spill onto
   siblings. The selector list is the contract: if it holds text, it veils. */
.hero__eyebrow,
.hero__line,
.hero__role,
.hero__tagline,
.hero__mark,
.section-head__title,
.section-head__index,
.project-card__body,
.about__bio,
.about__facts,
.contact__channels,
.contact-form,
.project-detail__meta,
.project-detail__title,
.project-detail__desc,
.site-footer {
  position: relative;
  isolation: isolate;   /* keep the wash below this element's own text */
}

.hero__eyebrow::before,
.hero__line::before,
.hero__role::before,
.hero__tagline::before,
.hero__mark::before,
.section-head__title::before,
.section-head__index::before,
.project-card__body::before,
.about__bio::before,
.about__facts::before,
.contact__channels::before,
.contact-form::before,
.project-detail__meta::before,
.project-detail__title::before,
.project-detail__desc::before,
.site-footer::before {
  content: "";
  position: absolute;
  inset: -0.6rem -0.9rem;   /* a little breathing room around the glyphs */
  z-index: -1;
  background: var(--veil);
  pointer-events: none;
  /* Feather the wash out before it reaches its own edge */
  -webkit-mask-image: radial-gradient(115% 130% at 50% 50%, #000 52%, transparent 100%);
  mask-image: radial-gradient(115% 130% at 50% 50%, #000 52%, transparent 100%);
}

/* The detail hero image sits directly above the body: clip the topmost
   wash so nothing can ever wander up over the photograph. */
.project-detail__meta::before { inset: -0.2rem -0.9rem -0.6rem; }

/* The footer bar already spans edge to edge (its own padding creates the
   gutter), so the wash needs no horizontal breathing room — without this
   it oversteps the page's own edges and creates a few px of side-scroll. */
.site-footer::before { inset: -0.6rem 0; }

/* Veiled text that would otherwise fill its row is shrunk to its content,
   so the dot field keeps breathing to the left and right of the words. */
.hero__eyebrow,
.hero__mark,
.project-detail__meta,
.project-detail__title { width: fit-content; }

.hero__role,
.hero__tagline,
.project-detail__desc { width: fit-content; max-width: 100%; }

/* Each hero line veils itself: the wash tracks the letters, not the grid row */
.hero__line { width: fit-content; }
/* Huge type needs a tighter wash, or the feather swallows the whole hero */
.hero__line::before {
  inset: -0.1rem -0.6rem;
  -webkit-mask-image: radial-gradient(100% 115% at 50% 50%, #000 60%, transparent 100%);
  mask-image: radial-gradient(100% 115% at 50% 50%, #000 60%, transparent 100%);
}

/* Short labels: the wash hugs the text instead of spanning the whole row,
   so the dot field stays visible across the rest of the line. */
.hero__eyebrow,
.hero__mark,
.project-detail__meta {
  width: fit-content;
}

/* The hero title is display type at 800 weight — it out-contrasts the field
   on its own. No veil, so the wallpaper runs clean across the name. */

body.no-scroll { overflow: hidden; }

::selection { background: var(--forest); color: var(--paper); }

/* Scrollbar in the palette (WebKit; Firefox uses scrollbar-color) */
html { scrollbar-color: var(--forest) var(--paper); }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb {
  background: rgba(var(--forest-rgb), 0.55);
  border: 3px solid var(--paper);
  border-radius: 99px;
}
::-webkit-scrollbar-thumb:hover { background: var(--forest); }

/* Accessible, consistent focus style */
:focus-visible {
  outline: 2px solid var(--forest);
  outline-offset: 3px;
  border-radius: 2px;
}

.mono {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Shared buttons */
.btn {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.9em 1.8em;
  border: 1px solid var(--forest);
  background: var(--veil);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background-color 0.25s var(--ease-soft), color 0.25s var(--ease-soft),
              border-color 0.25s var(--ease-soft), transform 0.12s var(--ease-soft);
}
.btn:active { transform: translateY(1px); }
.btn--solid { background: var(--forest); color: var(--paper); border-color: var(--forest); }
.btn--solid:hover { background: var(--forest-mid); border-color: var(--forest-mid); }
.btn--ghost { color: var(--forest); }
.btn--ghost:hover { background: rgba(var(--forest-rgb), 0.08); }

/* ====================== 03. PRELOADER ====================== */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--forest-deep);
  color: var(--paper);
  /* Exit = slide up out of the viewport, not a fade */
  transition: transform 0.8s var(--ease-out);
  will-change: transform;
}
.preloader.is-exiting { transform: translateY(-101%); }
.preloader.is-removed { display: none; }

.preloader__initials {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 125;
  font-weight: 800;
  font-size: clamp(3rem, 10vw, 6rem);
  letter-spacing: 0.04em;
  animation: preloader-pulse 1.2s ease-in-out infinite;
}
.preloader__count {
  position: absolute;
  right: var(--gutter);
  bottom: var(--gutter);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.2em;
  color: var(--forest-glow);
}
@keyframes preloader-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

/* ====================== 04. HEADER / NAV (DESKTOP) ====================== */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.1rem var(--gutter);
  pointer-events: none;              /* re-enabled on children */
  transition: background-color 0.3s var(--ease-soft), border-color 0.3s var(--ease-soft);
  border-bottom: 1px solid transparent;
}
/* Once scrolled, the bar earns a surface so it never floats over content */
.site-header.is-scrolled {
  background: var(--veil);
  border-bottom-color: var(--line);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.site-header > * { pointer-events: auto; }

.brand {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 0.35em 0.6em;
  color: var(--forest);
  background: var(--veil);
  border: 1px solid rgba(var(--forest-rgb), 0.35);
}

.nav__list {
  display: flex;
  gap: 1.9rem;
  background: var(--veil);
  border: 1px solid rgba(var(--forest-rgb), 0.35);
  padding: 0.55em 1.1em;
}
.nav__link {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  position: relative;
  transition: color 0.2s var(--ease-out);
}
.nav__link::after {
  /* underline drawn on hover — transform only, no layout */
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 1px;
  background: var(--forest);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s var(--ease-out);
}
.nav__link:hover { color: var(--forest); }
.nav__link:hover::after { transform: scaleX(1); }

/* Hamburger (hidden on desktop) */
.nav__burger {
  display: none;
  width: 44px;
  height: 44px;
  position: relative;
  background: var(--veil);
  border: 1px solid rgba(var(--forest-rgb), 0.35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.nav__burger-line {
  position: absolute;
  left: 11px; right: 11px;
  height: 2px;
  background: var(--ink);
  transition: transform 0.35s var(--ease-out);
}
.nav__burger-line:nth-child(1) { top: 17px; }
.nav__burger-line:nth-child(2) { top: 25px; }
.nav__burger[aria-expanded="true"] .nav__burger-line:nth-child(1) { transform: translateY(4px) rotate(45deg); }
.nav__burger[aria-expanded="true"] .nav__burger-line:nth-child(2) { transform: translateY(-4px) rotate(-45deg); }

/* ====================== 05. MOBILE MENU ====================== */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--forest-deep);
  color: var(--paper);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--gutter);
  /* Enters the same way the preloader exits: vertical slide, no generic fade */
  transform: translateY(-101%);
  transition: transform 0.55s var(--ease-out), visibility 0s linear 0.55s;
  visibility: hidden;
}
.mobile-menu.is-open {
  transform: translateY(0);
  visibility: visible;
  transition: transform 0.55s var(--ease-out);
}

.mobile-menu__list { display: grid; gap: 0.4rem; }
.mobile-menu__link {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 125;
  font-weight: 800;
  font-size: clamp(2.4rem, 11vw, 4rem);
  text-transform: uppercase;
  line-height: 1.05;
  display: inline-block;
  transition: color 0.2s;
}
.mobile-menu__link:hover { color: var(--forest-glow); }

/* Staggered link reveal, driven by --i set inline in the HTML */
.mobile-menu__list li {
  opacity: 0;
  transform: translateX(-2rem);
}
.mobile-menu.is-open .mobile-menu__list li {
  animation: reveal-left 0.55s var(--ease-out) forwards;
  animation-delay: calc(0.18s + var(--i) * 0.07s);
}

.mobile-menu__foot {
  position: absolute;
  bottom: var(--gutter);
  left: var(--gutter);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  color: var(--graphite);
}

/* ====================== 06. HERO ====================== */
.hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 7rem var(--gutter) 4rem;
  position: relative;
}

.hero__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--forest);
  margin-bottom: 1.4rem;
}

.hero__title {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 125;
  font-weight: 800;
  font-size: clamp(3rem, 11vw, 9.5rem);
  line-height: 0.95;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  display: grid;
}
.hero__line { display: inline-block; color: var(--forest); }
.hero__line--outline {
  /* Second line set as an outline: the green is "not yet filled in" */
  color: transparent;
  -webkit-text-stroke: 2px var(--forest);
}

.hero__role {
  margin-top: 2rem;
  font-size: clamp(1.05rem, 2vw, 1.35rem);
  font-weight: 500;
  max-width: 34ch;
}
.hero__tagline {
  margin-top: 0.6rem;
  color: var(--graphite);
  max-width: 52ch;
}

.hero__cta {
  margin-top: 2.4rem;
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

/* Registration mark, bottom-right of the hero sheet */
.hero__mark {
  position: absolute;
  right: var(--gutter);
  bottom: 2.2rem;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--graphite);
}
.hero__mark-cross { color: var(--forest); font-size: 1.3rem; line-height: 1; }
.hero__mark-label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  color: var(--forest);
}

/* --- Entrance reveal: elements marked data-reveal start offset + transparent
       and settle in once body.is-loaded is set by the preloader script. --- */
[data-reveal] { opacity: 0; }
[data-reveal="left"]  { transform: translateX(-2.5rem); }
[data-reveal="right"] { transform: translateX(2.5rem); }

body.is-loaded [data-reveal] {
  animation: 0.8s var(--ease-out) forwards;
  animation-delay: var(--d, 0s);
}
body.is-loaded [data-reveal="left"]  { animation-name: reveal-left; }
body.is-loaded [data-reveal="right"] { animation-name: reveal-right; }

@keyframes reveal-left {
  from { opacity: 0; transform: translateX(-2.5rem); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes reveal-right {
  from { opacity: 0; transform: translateX(2.5rem); }
  to   { opacity: 1; transform: translateX(0); }
}

/* ====================== 07. SKILLS MARQUEE ====================== */
.marquee {
  /* A light band ruled in forest: reads as a spec strip, not a color block */
  border-top: 1px solid var(--forest);
  border-bottom: 1px solid var(--forest);
  background: var(--paper-raise);
  padding: 1.1rem 0;
}
.marquee__viewport { overflow: hidden; }

.marquee__track {
  display: flex;
  width: max-content;                 /* two identical halves side by side */
  animation: marquee-scroll 28s linear infinite;
  will-change: transform;
}
/* Pause on hover — pointer devices only, so touch scrolling isn't affected */
@media (hover: hover) {
  .marquee__viewport:hover .marquee__track { animation-play-state: paused; }
}

.marquee__half { display: flex; flex-shrink: 0; }
.marquee__item {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 110;
  font-weight: 600;
  font-size: 1.35rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  padding: 0 1.4rem;
  display: flex;
  align-items: center;
  gap: 2.8rem;
  color: var(--ink);
}
.marquee__sep { color: var(--forest); font-size: 0.9rem; }

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }   /* seamless: track = 2 equal halves */
}

/* ====================== 08. SECTION HEADS (shared) ====================== */
.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 0 var(--gutter);
  margin: var(--section-gap) 0 3rem;
  border-bottom: 2px solid var(--forest);
  padding-bottom: 1rem;
}
.section-head__title {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 125;
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(1.8rem, 4.5vw, 3.2rem);
  line-height: 1;
  color: var(--forest);
}
.section-head__index {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  color: var(--forest);
}

/* ====================== 09. PROJECT CARDS ====================== */
.projects__list {
  display: grid;
  gap: clamp(3rem, 8vh, 6rem);
  padding: 0 var(--gutter);
}

/* One wide horizontal band per project */
.project-card {
  display: grid;
  grid-template-columns: 7fr 5fr;    /* image | text */
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: center;
  text-align: left;
  width: 100%;
}
/* Alternate composition for scroll rhythm: even cards flip image/text */
.project-card:nth-child(even) { grid-template-columns: 5fr 7fr; }
.project-card:nth-child(even) .project-card__media { order: 2; }
.project-card:nth-child(even) .project-card__body  { order: 1; }

.project-card__media {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--forest);
  background: var(--forest-deep);
  aspect-ratio: 16 / 10;
  transition: box-shadow 0.4s var(--ease-soft), transform 0.4s var(--ease-soft);
}
.project-card:hover .project-card__media,
.project-card:focus-visible .project-card__media {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px -20px rgba(var(--forest-rgb), 0.55);
}
.project-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease-out);
  will-change: transform;
}

/* Preview clip: sits over the cover image, crossfades in on hover
   (desktop) or when the card is mostly in view (touch) */
.project-card__preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.1s var(--ease-soft);
  pointer-events: none;
}
.project-card__media.is-previewing .project-card__preview { opacity: 1; }

/* Faint scrim so the OPEN tag stays legible over motion */
.project-card__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(var(--forest-rgb), 0) 55%, rgba(var(--forest-rgb), 0.5) 100%);
  opacity: 0;
  transition: opacity 1.1s var(--ease-soft);
  pointer-events: none;
}
.project-card__media.is-previewing .project-card__scrim { opacity: 1; }

/* Signature hover: sage corner registration brackets + measurement tag */
.project-card__media::before,
.project-card__media::after {
  content: "";
  position: absolute;
  width: 26px;
  height: 26px;
  border: 2px solid var(--forest-glow);  /* sage pops on dark cover imagery */
  opacity: 0;
  transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out);
  pointer-events: none;
}
.project-card__media::before {
  top: 12px; left: 12px;
  border-right: 0; border-bottom: 0;
  transform: translate(6px, 6px);
}
.project-card__media::after {
  bottom: 12px; right: 12px;
  border-left: 0; border-top: 0;
  transform: translate(-6px, -6px);
}
.project-card__open-tag {
  position: absolute;
  bottom: 14px; left: 14px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  color: var(--paper);
  background: var(--forest-mid);
  padding: 0.4em 0.8em;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out);
  pointer-events: none;
}

.project-card:hover .project-card__media img,
.project-card:focus-visible .project-card__media img { transform: scale(1.04); }
.project-card:hover .project-card__media::before,
.project-card:hover .project-card__media::after,
.project-card:focus-visible .project-card__media::before,
.project-card:focus-visible .project-card__media::after { opacity: 1; transform: translate(0, 0); }
.project-card:hover .project-card__open-tag,
.project-card:focus-visible .project-card__open-tag { opacity: 1; transform: translateY(0); }

.project-card__fig {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  color: var(--forest);
  margin-bottom: 0.9rem;
}
.project-card__title {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 118;
  font-weight: 700;
  font-size: clamp(1.6rem, 3.4vw, 2.6rem);
  line-height: 1.05;
  text-transform: uppercase;
  transition: color 0.3s var(--ease-soft);
}
.project-card:hover .project-card__title,
.project-card:focus-visible .project-card__title { color: var(--forest); }
.project-card__desc {
  margin-top: 0.9rem;
  color: var(--graphite);
  max-width: 44ch;
}
.project-card__stack {
  margin-top: 1.2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.stack-badge {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--forest);
  border: 1px solid rgba(var(--forest-rgb), 0.35);
  padding: 0.35em 0.7em;
  border-radius: 2px;
  background: rgba(var(--forest-rgb), 0.05);
}

/* ====================== 10. EXPANDED PROJECT VIEW ====================== */
/* The cover image morphs card → detail via the View Transitions API.
   js/projects-view.js assigns view-transition-name: project-cover to the
   active image on each side of the transition. */
::view-transition-old(project-cover),
::view-transition-new(project-cover) {
  animation-duration: 0.55s;
  height: 100%;
  object-fit: cover;
  overflow: hidden;
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.45s;
}

.project-detail {
  position: fixed;
  inset: 0;
  z-index: 60;
  overflow-y: auto;
  background: var(--paper);
}

/* The overlay is opaque, so it hides the page's background canvas AND the
   body's paper-grain texture. It gets its own dot field (created in
   js/projects-view.js) plus its own grain, so the overlay matches the main
   page's background exactly instead of reading as a flatter, quieter copy. */
.bg-canvas--detail {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}
.project-detail::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}
.project-detail__hero,
.project-detail__body { position: relative; z-index: 1; }

.project-detail__close {
  position: fixed;
  top: 1.25rem;
  right: var(--gutter);
  z-index: 61;
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  background: none;
  border: none;
  /* Over the hero media by default; .is-over-light flips it once the
     page has scrolled far enough that the paper-colored body sits behind
     this (fixed-position) button instead — see wireCloseContrast in
     js/projects-view.js. */
  color: var(--paper);
  transition: color 0.3s var(--ease-out);
}
.project-detail__close.is-over-light { color: var(--forest); }
.project-detail__close svg {
  width: 24px;
  height: 24px;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  fill: none;
  transform-origin: center;
  transition: transform 0.2s var(--ease-out);
}
.project-detail__close:hover svg { transform: scale(1.15); }

.project-detail__hero {
  position: relative;
  height: min(62vh, 640px);
  border-bottom: 1px solid var(--forest);
  overflow: hidden;
  background: var(--forest-deep);
}
.project-detail__hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.project-detail__preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.2s var(--ease-soft);
  pointer-events: none;
}
.project-detail__hero.is-previewing .project-detail__preview { opacity: 1; }
/* Faint scrim (same treatment as the card preview) to keep it from feeling flat */
.project-detail__hero.has-video::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(var(--forest-rgb), 0) 60%, rgba(var(--forest-rgb), 0.4) 100%);
  opacity: 0;
  transition: opacity 1.2s var(--ease-soft);
  pointer-events: none;
}
.project-detail__hero.is-previewing::after { opacity: 1; }

.project-detail__body {
  max-width: 60rem;
  margin: 0 auto;
  padding: 3rem var(--gutter) 5rem;
}

/* Content choreography after the morph: title first, then the rest */
.project-detail__meta,
.project-detail__title,
.project-detail__desc,
.project-detail__stack,
.project-detail__links,
.project-detail__gallery {
  opacity: 0;
  transform: translateY(1rem);
  animation: detail-rise 0.6s var(--ease-out) forwards;
}
.project-detail__meta    { animation-delay: 0.30s; }
.project-detail__title   { animation-delay: 0.38s; }
.project-detail__desc    { animation-delay: 0.52s; }
.project-detail__stack   { animation-delay: 0.60s; }
.project-detail__links   { animation-delay: 0.68s; }
.project-detail__gallery { animation-delay: 0.76s; }

@keyframes detail-rise {
  to { opacity: 1; transform: translateY(0); }
}

.project-detail__meta {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  color: var(--forest);
}
.project-detail__title {
  font-family: var(--font-display);
  font-variation-settings: "wdth" 122;
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(2rem, 6vw, 4.2rem);
  line-height: 1;
  margin-top: 0.8rem;
  color: var(--ink);
}
.project-detail__desc {
  margin-top: 1.6rem;
  max-width: 62ch;
  font-size: 1.1rem;
  line-height: 1.75;
}
.project-detail__stack {
  margin-top: 1.6rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.project-detail__links {
  margin-top: 2rem;
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}
.project-detail__gallery {
  margin-top: 3rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.2rem;
}
.project-detail__gallery img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border: 1px solid var(--forest);
}

/* ====================== 11. ABOUT ====================== */
.about__grid {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: clamp(2rem, 5vw, 5rem);
  padding: 0 var(--gutter);
}
.about__bio p + p { margin-top: 1rem; }
.about__bio { max-width: 60ch; padding: 0.25rem 0; }

.about__facts { border-top: 1px solid var(--forest); }
.about__facts div {
  display: grid;
  grid-template-columns: 9rem 1fr;
  gap: 1rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--line);
}
.about__facts dt {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--forest);
  padding-top: 0.2rem;
}
.about__facts dd { font-size: 0.98rem; }

/* ====================== 12. CONTACT ====================== */
.contact__grid {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: clamp(2rem, 5vw, 5rem);
  padding: 0 var(--gutter);
}

.contact__lead { max-width: 32ch; font-size: 1.2rem; font-weight: 500; }
.contact__links { margin-top: 1.8rem; display: grid; gap: 0.7rem; }
.contact__links a {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  transition: color 0.2s;
}
.contact__links a::before { content: "→"; color: var(--forest); }
.contact__links a:hover { color: var(--forest); }

.contact-form { display: grid; gap: 1.2rem; }
.contact-form__field { display: grid; gap: 0.4rem; }
.contact-form__field span {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--forest);
}
.contact-form input,
.contact-form textarea {
  background: var(--paper-raise);
  border: 1px solid var(--line);
  padding: 0.85em 1em;
  border-radius: 0;
  resize: vertical;
  transition: border-color 0.2s;
}
.contact-form input:focus,
.contact-form textarea:focus { border-color: var(--forest); outline: none; }
.contact-form .btn { justify-self: start; }
.contact-form .btn[disabled] { opacity: 0.6; cursor: default; }
.contact-form__hp {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}
.contact-form__note {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  color: var(--forest);
  min-height: 1.2em;
}
.contact-form__note[data-state="error"] { color: #8a3324; }

/* ====================== 13. FOOTER ====================== */
.site-footer {
  margin-top: var(--section-gap);
  border-top: 2px solid var(--forest);
  padding: 1.4rem var(--gutter);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--forest);
}

/* ====================== 14. REDUCED MOTION ====================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  /* Show content immediately, no reveals, no marquee scroll, no pulses */
  [data-reveal] { opacity: 1; transform: none; }
  body.is-loaded [data-reveal],
  .mobile-menu.is-open .mobile-menu__list li,
  .project-detail__meta, .project-detail__title, .project-detail__desc,
  .project-detail__stack, .project-detail__links, .project-detail__gallery {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .marquee__track { animation: none; }
  .preloader { transition: none; }
  .preloader__initials { animation: none; }
  .mobile-menu { transition: none; }
  .project-card__media img { transition: none; }
  .project-card__media { transition: none; }
  .project-card:hover .project-card__media { transform: none; }
  .btn:active { transform: none; }
  /* Static cover only — no autoplaying preview clips */
  .project-card__preview, .project-detail__preview,
  .project-card__scrim, .project-detail__hero.has-video::after { display: none; }

  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* ====================== 15. RESPONSIVE (≤768px) ====================== */
@media (max-width: 768px) {
  /* Nav: hide inline links, show hamburger */
  .nav__list { display: none; }
  .nav__burger { display: block; }

  .hero { padding-top: 6rem; }
  .hero__line--outline { -webkit-text-stroke-width: 1.5px; }
  .hero__mark { position: static; margin-top: 3rem; }

  /* Projects collapse to a full-width vertical stack */
  .project-card,
  .project-card:nth-child(even) { grid-template-columns: 1fr; }
  .project-card:nth-child(even) .project-card__media { order: 0; }
  .project-card:nth-child(even) .project-card__body  { order: 0; }
  .project-card__desc { max-width: none; }

  .project-detail__hero { height: 44vh; }
  .project-detail__gallery { grid-template-columns: 1fr; }
  .project-detail__close { top: 0.9rem; }

  .about__grid,
  .contact__grid { grid-template-columns: 1fr; }
  .about__facts div { grid-template-columns: 7.5rem 1fr; }

  .marquee__item { font-size: 1.1rem; padding: 0 1rem; gap: 2rem; }

  .section-head { margin-top: 4.5rem; }
}
