/* STstudio — v4 */

/* Vendetta loaded via Adobe Fonts (Typekit kit sop6jim) — see <head> */
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap');

@font-face {
  font-family: 'Infinit Dingbats';
  src: url('../fonts/InfinitDingbats.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* Sanjan — Korean text only. unicode-range restricts it to Hangul,
   so Latin glyphs always fall through to vendetta / Space Mono. */
@font-face {
  font-family: 'Sanjan';
  src: url('../fonts/sanjan-regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+1100-11FF, U+3130-318F, U+A960-A97F, U+AC00-D7A3, U+D7B0-D7FF;
}

/* TOKENS */
/* All px-based tokens converted to rem (1rem = 16px). */
:root {
  /* colour — dark-first */
  --cream: #111110;       --cream-2: #1C1C1A;
  --ink: #E4E3DD;         --ink-soft: #AEADA6;
  --rule: #282826;        --rule-dark: #1A1A18;
  --muted: #686862;       --muted-dark: #4A4A45;
  --accent: #0000FF;      --accent-dim: rgba(0,0,255,0.12);

  /* type families — 'Sanjan' first catches Hangul (unicode-range), Latin falls through */
  --serif: 'Sanjan', 'vendetta', Georgia, serif;
  --sans:  'Sanjan', 'Space Mono', 'Courier New', monospace;

  /* type scale (rem) */
  --tx-display: clamp(4.5rem,   14vw,  15rem);     /*  72→240px */
  --tx-hero:    clamp(3rem,     8.5vw, 8.75rem);   /*  48→140px */
  --tx-xl:      clamp(2.125rem, 5vw,   5rem);      /*  34→ 80px */
  --tx-l:       clamp(1.375rem, 2.4vw, 2.25rem);   /*  22→ 36px */
  --tx-m:       1.0625rem;                         /*  17px */
  --tx-s:       0.8125rem;                         /*  13px */
  --tx-xs:      0.6875rem;                         /*  11px */

  /* spacing scale — 4px base (rem) */
  --sp-1:  0.25rem;   /*  4 */
  --sp-2:  0.5rem;    /*  8 */
  --sp-3:  0.75rem;   /* 12 */
  --sp-4:  1rem;      /* 16 */
  --sp-5:  1.25rem;   /* 20 */
  --sp-6:  1.5rem;    /* 24 */
  --sp-8:  2rem;      /* 32 */
  --sp-10: 2.5rem;    /* 40 */
  --sp-14: 3.5rem;    /* 56 */
  --sp-18: 4.5rem;    /* 72 */
  --sp-20: 5rem;      /* 80 */

  /* layout (rem) */
  --gutter:     clamp(2rem, 5.5vw, 6rem);      /* 32→96px */
  --max-w:      102.5rem;                       /* 1640px */
  --header-h:   4.75rem;                        /*   76px */
  --section-py: clamp(1.75rem, 3.4vw, 3.5rem);  /* 28→56px */
  --col-gap:    clamp(var(--sp-10), 6vw, 120px); /* shared 2-column content grid gap: 40→120 */

  /* easing */
  --ease-out:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft: cubic-bezier(0.65, 0, 0.35, 1);
}

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

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

body.menu-open { overflow: hidden; }

body {
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 400;
  font-size: var(--tx-m);
  line-height: 1.35;
  letter-spacing: -0.02em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a {
  color: inherit;
  text-decoration: none;
  transition: opacity 280ms var(--ease-out);
}
a:hover { opacity: 0.6; }

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

img { display: block; max-width: 100%; height: auto; }
ul  { list-style: none; }

/* PRELOADER — full-screen splash that hides the messy image load on first paint.
   z-index sits above all content (detail panel z-120) but below the custom
   cursor (z-9999) so the cursor stays visible while it fades. JS adds .is-done
   on window.load to fade it out, then removes the node. */
#preloader {
  position: fixed;
  inset: 0;
  z-index: 4000;
  display: grid;
  place-items: center;
  background: var(--cream);
  opacity: 1;
  transition: opacity 0.7s var(--ease-out), visibility 0.7s var(--ease-out);
}
#preloader.is-done {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.preloader-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  animation: preloaderPulse 1.8s var(--ease-out) infinite;
}
.preloader-bar {
  position: relative;
  width: 120px;
  height: 2px;
  overflow: hidden;
  background: var(--rule);
}
.preloader-bar::after {
  content: "";
  position: absolute;
  top: 0;
  left: -40%;
  width: 40%;
  height: 100%;
  background: var(--ink);
  animation: preloaderSlide 1.15s var(--ease-in-out, ease-in-out) infinite;
}
@keyframes preloaderSlide {
  0%   { left: -40%; }
  100% { left: 100%; }
}
@keyframes preloaderPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.6; }
}
@media (prefers-reduced-motion: reduce) {
  .preloader-inner { animation: none; }
  .preloader-bar::after { animation-duration: 2.4s; }
}

/* CUSTOM CURSOR */
.cursor-dot,
.cursor-ring {
  position: fixed;
  top: 0; left: 0;
  pointer-events: none;
  z-index: 9999;   /* always above every overlay (detail panel z-120, menu z-80) — native cursor is hidden, so this must never be occluded */
  border-radius: 50%;
  mix-blend-mode: difference;
  will-change: transform;
}
.cursor-dot {
  width: 6px; height: 6px;
  background: var(--ink);
  transform: translate(-50%, -50%);
}
.cursor-ring {
  width: 34px; height: 34px;
  border: 1px solid var(--ink);
  transform: translate(-50%, -50%) scale(0.6);
  opacity: 0.55;
  transition:
    transform 420ms var(--ease-out),
    background 280ms var(--ease-out),
    opacity 280ms var(--ease-out);
}
.cursor-ring.is-hover { transform: translate(-50%, -50%) scale(1.4); background: rgba(228,227,221,0.06); }
.cursor-ring.is-image { transform: translate(-50%, -50%) scale(2);   background: rgba(228,227,221,0.03); }

@media (hover: none), (pointer: coarse) {
  .cursor-dot, .cursor-ring { display: none; }
}
@media (hover: hover) and (pointer: fine) {
  body.has-cursor,
  body.has-cursor * { cursor: none !important; }
}

/* HEADER */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--header-h);
  z-index: 60;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 0 clamp(1rem, 2.5vw, 2rem);   /* tighter than the page gutter */
  font-family: var(--sans);
  font-size: var(--tx-s);
  letter-spacing: 0.04em;
  color: var(--ink);
}

.site-header .brand {
  font-weight: 300;
  font-size: 15px;
  letter-spacing: 0.02em;
  text-transform: none;
}
.site-header .brand a { display: inline-flex; align-items: center; }
/* Brand wordmark — "STstudio" text in EN; the Korean 생태제작소 SVG logo in KO.
   initLang() sets html[lang] from the saved language (localStorage), so this also
   flips on work pages. onerror falls back to the text if the SVG fails to load. */
.brand-logo {
  height: 20px;
  width: auto;
  display: none;
  filter: brightness(0) invert(1);   /* any source colour → white for the dark header */
}
html[lang^="ko"] .brand:not(.no-logo) .brand-logo { display: block; }
html[lang^="ko"] .brand:not(.no-logo) .brand-text { display: none; }

/* Korean tracking — Sanjan (Hangul) sets tight, so the wide editorial
   tracking on labels/eyebrows (0.08–0.18em, tuned for Latin/vendetta)
   reads too loose in Korean. Pull these back to ~0.02em in KO only;
   English keeps its original spacing. */
html[lang^="ko"] .section-label,
html[lang^="ko"] .site-menu .close,
html[lang^="ko"] .hero-eyebrow,
html[lang^="ko"] .hero-meta,
html[lang^="ko"] .gallery-strip .hint,
html[lang^="ko"] .h-card .h-num,
html[lang^="ko"] .statement-foot,
html[lang^="ko"] .about-snippet .more,
html[lang^="ko"] .about-grid dt,
html[lang^="ko"] .work-row .num {
  letter-spacing: 0.02em;
}

/* Korean word-spacing — Hangul sets the spaces between 어절 wider than Latin
   needs, so the body prose (the only copy that's Korean) reads slightly gappy.
   Pull the inter-word gap in a touch, KO only; English is untouched. */
html[lang^="ko"] .hero-lede,
html[lang^="ko"] .about-grid p,
html[lang^="ko"] dd[data-i18n^="svc"],
html[lang^="ko"] .contact-sub,
html[lang^="ko"] .project-descriptions p {
  word-spacing: -0.06em;
}

/* Korean line-height — Hangul has no ascenders/descenders to breathe, so the
   default 1.35 reads cramped in KO. Open the leading to 1.4 (KO only; headings
   keep their own tight line-heights, so only running prose loosens). */
html[lang^="ko"] body {
  line-height: 1.4;
}

.site-header .center-link {
  text-align: center;
  font-family: var(--sans);
  font-size: 15px;
  text-transform: none;
  letter-spacing: 0;
}

.site-header .right {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  grid-column: 3;
}

.site-header .header-contact {
  font-size: var(--tx-s);
  letter-spacing: 0.06em;
  text-transform: none;
  font-family: var(--sans);
}

/* KR / EN toggle — injected into .right by initLang() */
.site-header .right { gap: clamp(14px, 2vw, 24px); }
.lang-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  background: none;
  border: 0;
  font-family: var(--sans);
  font-size: var(--tx-s);
  letter-spacing: 0.06em;
  color: var(--muted);
  cursor: pointer;
  line-height: 1;
}
.lang-toggle [data-l] { color: var(--muted); transition: color 0.2s ease; }
.lang-toggle [data-l].is-on { color: var(--ink); }
.lang-toggle .lt-sep { color: var(--muted-dark); }
.lang-toggle:hover [data-l]:not(.is-on) { color: var(--ink-soft); }

/* FULLSCREEN MENU */
.site-menu {
  position: fixed;
  inset: 0;
  background: rgba(15,15,15,0.96);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  z-index: 80;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--header-h) var(--gutter) var(--sp-8);
  color: var(--ink);
  opacity: 0;
  pointer-events: none;
  transition: opacity 420ms var(--ease-out);
}
.site-menu.is-open { opacity: 1; pointer-events: auto; }

.site-menu .close {
  position: absolute;
  top: var(--sp-6);
  right: var(--gutter);
  font-size: var(--tx-s);
  letter-spacing: 0.08em;
  color: var(--ink);
}

.site-menu nav {
  display: flex;
  flex-direction: column;
  gap: clamp(var(--sp-2), 1.4vw, var(--sp-5));
  max-width: 900px;
}
.site-menu nav a {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(48px, 9vw, 132px);
  letter-spacing: -0.02em;
  color: var(--ink);
  display: inline-block;
  opacity: 0;
  transform: translateY(40px);
  transition:
    opacity    700ms var(--ease-out),
    transform  700ms var(--ease-out),
    color      280ms var(--ease-out);
}
.site-menu.is-open nav a               { opacity: 1; transform: none; }
.site-menu.is-open nav a:nth-child(1)  { transition-delay: 100ms; }
.site-menu.is-open nav a:nth-child(2)  { transition-delay: 170ms; }
.site-menu.is-open nav a:nth-child(3)  { transition-delay: 240ms; }
.site-menu.is-open nav a:nth-child(4)  { transition-delay: 310ms; }
.site-menu.is-open nav a:nth-child(5)  { transition-delay: 380ms; }
.site-menu nav a:hover { color: #d8d2c4; }

.site-menu .menu-meta {
  margin-top: var(--sp-14);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--sp-4);
  font-size: var(--tx-s);
  letter-spacing: 0.06em;
  opacity: 0.6;
}

/* ===========================================================
   SECTION — base container
   The section provides all horizontal padding.
   Children must NOT add their own horizontal padding.
   =========================================================== */
.section { padding: var(--section-py) var(--gutter); }
.section.dark  { background: var(--cream-2); color: var(--ink); }

.section-heading {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--tx-xl);
  line-height: 0.9;
  letter-spacing: -0.01em;
}

.section-label {
  font-size: var(--tx-xs);
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: var(--sp-8);
}
.section.dark .section-label { color: var(--muted); }

/* HERO */
.hero {
  position: relative;
  min-height: 100svh;
  padding: var(--gutter) var(--section-py);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0; /* internal spacing handled per-child below */
  overflow: hidden;
}

/* three.js project-cover carousel backdrop */
.hero-3d {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.hero-3d canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}
/* left-anchored scrim keeps the title legible over the orbiting covers */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(90deg, var(--cream) 0%, rgba(17,17,16,0.78) 32%, rgba(17,17,16,0) 72%),
    linear-gradient(0deg, var(--cream) 0%, rgba(17,17,16,0) 26%);
}
/* lift all hero content above the backdrop + scrim */
.hero > *:not(.hero-3d) { position: relative; z-index: 2; }

.hero-eyebrow {
  font-size: var(--tx-xs);
  letter-spacing: 0.1em;
  color: var(--muted);
  margin-bottom: clamp(var(--sp-6), 3vw, var(--sp-10));
}

.hero-title {
  font-family: var(--serif);
  font-weight: 300;
  font-style: italic;
  font-size: var(--tx-hero);
  line-height: 0.82;
  letter-spacing: -0.03em;
  max-width: 1400px;
}
.hero-title em { font-style: normal; }
/* Inline dingbat: keep font-size == parent so it doesn't expand the line box;
   use transform: scale for visual emphasis. line-height inherits parent's tight value. */
.hero-title .inline-img {
  display: inline-block;
  font-family: 'Infinit Dingbats', serif;
  font-size: 1em;
  line-height: 1;
  vertical-align: baseline;
  transform: scale(1.1) translateY(0.2rem);
  transform-origin: center 60%;
  color: var(--ink-soft);
  margin: 0 0.08em;
  user-select: none;
  transition: color 300ms var(--ease-out);
}
.hero-title .inline-img:hover { color: var(--accent); }
.hero-lede {
  margin-top: clamp(var(--sp-6), 3vw, var(--sp-10));
  max-width: 600px;
  font-size: clamp(14px, 1.2vw, 17px);
  font-weight: 300;

  color: var(--ink-soft);
}

/* hero-meta sits below the lede in flow — no absolute positioning */
.hero-meta {
  padding-top: clamp(var(--sp-6), 3vw, var(--sp-10));
  display: flex;
  flex-wrap: wrap;
  gap: clamp(var(--sp-6), 4vw, var(--sp-14));
  font-size: var(--tx-xs);
  letter-spacing: 0.14em;
  color: var(--muted);
}
.hero-meta strong {
  display: block;
  margin-top: var(--sp-1);
  font-family: var(--sans);
  font-weight: 300;
  text-transform: none;
  letter-spacing: 0;
  font-size: 17px;
  color: var(--ink);
}

/* ===========================================================
   HORIZONTAL GALLERY
   Gallery strip has its own padding rhythm:
   — strip: vertical padding only (no horizontal)
   — header + h-scroll: get horizontal gutter independently
   This allows cards to bleed edge-to-edge while header aligns.
   =========================================================== */
.gallery-strip { padding: var(--section-py) 0; }
.gallery-strip > header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-6);
  padding: 0 var(--gutter);
  margin-bottom: clamp(var(--sp-8), 4vw, var(--sp-14));
}

.gallery-strip h2 {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--tx-xl);
  letter-spacing: -0.01em;
}

.gallery-strip .hint {
  font-size: var(--tx-xs);
  letter-spacing: 0.16em;
  color: var(--muted);
  white-space: nowrap;
}

.h-scroll { overflow: hidden; }
.h-track {
  display: flex;
  width: max-content;
  animation: h-scroll-loop 48s linear infinite;
}
.h-track .h-card { margin-right: clamp(var(--sp-3), 1.5vw, var(--sp-6)); }
.h-scroll:hover .h-track { animation-play-state: paused; }

@keyframes h-scroll-loop {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.h-card {
  flex: 0 0 clamp(150px, 13vw, 210px);
  scroll-snap-align: start;
  cursor: pointer;
}
.h-card .h-num {
  font-size: var(--tx-xs);
  letter-spacing: 0.16em;
  color: var(--muted);
  margin-bottom: var(--sp-3);
  display: block;
}
.h-card .h-frame {
  overflow: hidden;
  background: #000;
  aspect-ratio: 3 / 4;
  display: flex;
  align-items: center;
  justify-content: center;
}
.h-card .h-fill {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: filter 600ms ease;
}
.h-card:hover .h-fill { filter: brightness(1.06); }

/* video thumbnails inside cards */
.h-card .h-frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.h-card .h-cap {
  margin-top: var(--sp-4);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-3);
  font-size: var(--tx-s);
}
.h-card .h-cap .name {
  font-family: var(--sans);
  font-size: 18px;
}
.h-card .h-cap .year { color: var(--muted); }

/* STATEMENT (dark full-bleed) */
.statement {
  background: var(--cream-2);
  color: var(--ink);
  padding: calc(var(--section-py) * 1.1) var(--gutter);
  text-align: center;
}
.statement-text {
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--tx-hero);
  line-height: 0.9;
  letter-spacing: -0.03em;
  max-width: 1400px;
  margin: 0 auto;
}
.statement-text .em {
  font-style: italic;
  font-weight: 700;
  color: var(--accent);
}
.statement-foot {
  margin-top: var(--sp-8);
  font-size: var(--tx-xs);
  letter-spacing: 0.18em;
  color: var(--muted);
}

/* MARQUEE */
.marquee {
  background: var(--cream-2);
  color: var(--ink);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  overflow: hidden;
  padding: var(--sp-8) 0;
}
.marquee-track {
  display: flex;
  gap: var(--sp-14);
  white-space: nowrap;
  animation: marquee 36s linear infinite;
  will-change: transform;
}
.marquee-track span {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(28px, 4vw, 56px);
  letter-spacing: -0.01em;
}
.marquee-track .dot {
  font-family: var(--sans);
  font-style: normal;
  font-size: 20px;
  align-self: center;
  opacity: 0.5;
}
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ABOUT SNIPPET (index page) */
.about-snippet {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: var(--col-gap);
  align-items: start;
}
.about-snippet h2 {
  font-family: var(--serif);
  font-weight: 300;
  font-size: var(--tx-xl);
  letter-spacing: -0.01em;
}
.about-snippet p {
  font-size: clamp(16px, 1.4vw, 19px);
  margin-bottom: var(--sp-5);
  color: var(--ink-soft);
}
.about-snippet .more {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--tx-s);
  letter-spacing: 0.14em;
  margin-top: var(--sp-6);
}
.about-snippet .more::after { content: "→"; }

/* ===========================================================
   ABOUT GRID (about / services pages)
   NO horizontal padding — parent .section already provides it.
   =========================================================== */
.about-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--col-gap);
  align-items: start;
}
.about-grid p {
  font-size: clamp(13px, 1.1vw, 16px);
  margin-bottom: var(--sp-4);
}
.about-grid dl { font-family: var(--sans); }
.about-grid dt {
  font-size: var(--tx-xs);
  letter-spacing: 0.14em;
  color: var(--muted);
  margin-top: var(--sp-6);
  margin-bottom: var(--sp-1);
}
.about-grid dt:first-child { margin-top: 0; }
.about-grid dd {
  font-family: var(--sans);
  font-size: 16px;
}

/* ===========================================================
   WORK LIST
   NO horizontal padding — parent .section already provides it.
   =========================================================== */
.work-list {}

.work-row {
  display: grid;
  grid-template-columns: 72px 1.4fr 1fr auto;
  gap: var(--sp-8);
  align-items: center;
  padding: clamp(var(--sp-8), 2.5vw, var(--sp-10)) 0;
  border-top: 1px solid var(--rule);
  cursor: pointer;
  transition: color 280ms var(--ease-out);
}
.work-row:last-child { border-bottom: 1px solid var(--rule); }

.work-row .num {
  font-size: var(--tx-xs);
  letter-spacing: 0.16em;
  color: var(--muted);
}
.work-row .title {
  font-family: var(--serif);
  font-size: clamp(20px, 2.6vw, 38px);
  letter-spacing: -0.01em;
}
.work-row .tags,
.work-row .year {
  font-size: var(--tx-s);
  color: var(--muted);
  letter-spacing: 0.04em;
}
.work-row:hover .title { color: var(--accent); }

/* hover image preview — desktop only */
.work-preview {
  position: fixed;
  pointer-events: none;
  width: 360px;
  height: 240px;
  background-size: cover;
  background-position: center;
  z-index: 40;
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 300ms var(--ease-out), transform 400ms var(--ease-out);
}
.work-preview.is-active { opacity: 1; transform: scale(1); }

/* BIG CONTACT LINK */
.big-mail {
  font-family: var(--serif);
  font-size: clamp(32px, 7vw, 110px);

  letter-spacing: -0.02em;
  display: inline-block;
  padding-bottom: var(--sp-3);
  transition: letter-spacing 380ms ease;
}
.big-mail:hover {
  opacity: 1; /* override global a:hover */
  letter-spacing: -0.016em;
}

/* ── Desktop split detail panel ─────────────────────────── */
.detail-panel {
  position: fixed;
  top: 0; right: 0;
  width: 50vw;
  height: 100vh;
  background: var(--cream);
  border-left: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 520ms var(--ease-out);
  z-index: 120;
  will-change: transform;
}
.detail-panel.is-open { transform: translateX(0); }
.dp-bar {
  flex-shrink: 0;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 clamp(1rem, 2.5vw, 2rem);   /* tighter than the page gutter */
  border-bottom: 1px solid var(--rule);
  background: var(--cream);
  font-family: var(--sans);
  font-size: var(--tx-s);
  letter-spacing: 0.04em;
}
.dp-open, .dp-close {
  font-family: var(--sans);
  font-size: var(--tx-s);
  color: var(--ink-soft);
  background: none;
  border: none;
  cursor: pointer;
  letter-spacing: 0.04em;
  transition: color 200ms;
}
.dp-open:hover, .dp-close:hover { color: var(--accent); opacity: 1; }
.dp-frame {
  flex: 1;
  width: 100%;
  border: none;
  background: var(--cream);
}

/* shell shrinks to left half when a detail is open */
.page-shell { transition: width 520ms var(--ease-out); }
@media (min-width: 1024px) {
  body.detail-open .page-shell { width: 50vw; overflow: hidden; }
  body.detail-open .site-header { right: auto; width: 50vw; }
}

/* ── Contact form ───────────────────────────────────────── */
#contact { padding-top: var(--sp-8); padding-bottom: var(--sp-8); }
#contact .section-heading {
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  font-weight: 300;
  letter-spacing: -0.01em;
  line-height: 1.15;
}
.contact-wrap {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--col-gap);
  align-items: start;
}
.contact-intro { display: flex; flex-direction: column; gap: var(--sp-3); }
.contact-sub {
  font-family: var(--sans);
  font-size: var(--tx-s);
  color: var(--ink-soft);
  line-height: 1.5;
  max-width: 340px;
}
.contact-mail-link {
  font-family: var(--sans);
  font-size: var(--tx-s);
  color: var(--ink-soft);
  text-decoration: none;
  width: fit-content;
  transition: color 200ms;
}
.contact-mail-link:hover { color: var(--ink); opacity: 1; }

.contact-form { display: flex; flex-direction: column; gap: var(--sp-3); }
.cf-row { display: flex; flex-direction: column; gap: var(--sp-1); }
.cf-label {
  font-family: var(--sans);
  font-size: var(--tx-xs);
  color: var(--muted);
  letter-spacing: 0.08em;
}
.cf-input {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--tx-s);
  padding: var(--sp-1) 0 var(--sp-2);
  outline: none;
  width: 100%;
  transition: border-color 200ms;
  -webkit-appearance: none;
}
.cf-input:focus { border-bottom-color: var(--accent); }
.cf-input::placeholder { color: var(--muted-dark); }
.cf-textarea {
  resize: none;
  min-height: 4.5rem;
  line-height: 1.5;
}
.cf-footer {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-1);
  flex-wrap: wrap;
}
.cf-submit {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  background: transparent;
  border: 1px solid var(--rule);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--tx-s);
  letter-spacing: 0.06em;
  padding: var(--sp-3) var(--sp-6);
  cursor: pointer;
  transition: border-color 220ms, color 220ms;
}
.cf-submit:hover { border-color: var(--accent); color: var(--accent); }
.cf-submit:disabled { opacity: 0.45; cursor: default; }
.cf-btn-arrow { transition: transform 220ms; }
.cf-submit:hover .cf-btn-arrow { transform: translateX(4px); }
.cf-status {
  font-family: var(--sans);
  font-size: var(--tx-xs);
  letter-spacing: 0.06em;
  min-height: 1.2em;
  color: var(--accent);
}
.cf-status.is-error { color: #FF5F57; }

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

/* REVEAL ANIMATIONS */
@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(32px);
    transition: opacity 1000ms var(--ease-out), transform 1000ms var(--ease-out);
  }
  .reveal.in { opacity: 1; transform: none; }
  .reveal.d1 { transition-delay:  80ms; }
  .reveal.d2 { transition-delay: 160ms; }
  .reveal.d3 { transition-delay: 240ms; }
  .reveal.d4 { transition-delay: 320ms; }

  .reveal-img {
    opacity: 0;
    transform: scale(0.96);
    transition: opacity 1000ms var(--ease-out), transform 1200ms var(--ease-out);
  }
  .reveal-img.in { opacity: 1; transform: none; }

  .split .word {
    display: inline-block;
    overflow: hidden;
    vertical-align: top;
    margin-right: 0.25em;
  }
  .split .word > span {
    display: inline-block;
    transform: translateY(110%);
    transition: transform 900ms var(--ease-out);
    transition-delay: calc(var(--i, 0) * 60ms);
  }
  .split.in .word > span { transform: none; }
}

/* FOOTER — compact single bar */
.site-footer {
  background: var(--cream);
  color: var(--ink);
  padding: var(--sp-6) var(--gutter);
  border-top: 1px solid var(--rule);
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-4);
  font-size: var(--tx-xs);
  letter-spacing: 0.1em;
  color: var(--muted);
}

.footer-nav {
  display: flex;
  gap: var(--sp-5);
}
.footer-nav a {
  color: var(--ink);
  opacity: 0.6;
}
.footer-nav a:hover { opacity: 1; }

/* ===========================================================
   RESPONSIVE
   Breakpoints: 900px (tablet), 640px (large phone), 480px (phone)
   =========================================================== */

/* — tablet — */
@media (max-width: 900px) {
  :root { --header-h: 68px; }

  .site-header { grid-template-columns: 1fr auto; }
  .site-header .center-link { display: none; }

  .about-snippet,
  .about-grid { grid-template-columns: 1fr; }

  .work-row { grid-template-columns: 1fr auto; gap: var(--sp-4); }
  .work-row .num,
  .work-row .tags { display: none; }

  .footer-inner { flex-direction: column; align-items: flex-start; gap: var(--sp-3); }

  .work-preview { display: none; }

  .statement { padding-top: var(--section-py); padding-bottom: var(--section-py); }

  .project-info-row { grid-template-columns: 1fr; }
  .project-meta { max-width: none; }
}

/* — large phone — */

/* WORK ARCHIVE — catalogue interface (featured + collection) */
.archive { border-top: 1px solid var(--rule); }
/* head rows */
.arch-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--gutter);
  border-bottom: 1px solid var(--rule);
  font-size: var(--tx-xs);
  letter-spacing: 0.04em;
  color: var(--muted);
}
.arch-head .section-label { margin: 0; }
.arch-head-sub { margin-top: var(--section-py); border-top: 1px solid var(--rule); }
.arch-explore { color: var(--ink); letter-spacing: 0.06em; cursor: pointer; transition: color 240ms var(--ease-out); }
.arch-explore:hover { color: var(--accent); }
.arch-arrows { display: flex; gap: var(--sp-3); }
.arch-arrows button:hover { opacity: 0.5; }

/* featured */
.arch-featured {
  display: grid;
  grid-template-columns: 38% 62%;
  border-bottom: 1px solid var(--rule);
}

.arch-info {
  display: flex;
  flex-direction: column;
  padding: clamp(18px, 2.2vw, 32px) var(--gutter);
  border-right: 1px solid var(--rule);
}
.arch-info-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: var(--tx-s);
  letter-spacing: 0.02em;
}
.arch-num em { font-style: normal; color: var(--accent); }

/* slide animation when auto-advancing projects */
.arch-info-body { transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out); }
.arch-info-body.is-out {
  transform: translateY(10px);
  opacity: 0;
}

.arch-title {
  font-size: clamp(17px, 1.9vw, 28px);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin: var(--sp-4) 0 var(--sp-5);
}
/* featured-panel tag chips — same .ac-tag pills the cards use */
.arch-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin: 0 0 var(--sp-5);
}
.arch-desc {
  font-size: 13px;
  color: var(--ink-soft);
  max-width: 44ch;
  margin-bottom: var(--sp-8);
}

.arch-specs { margin-top: auto; }
.arch-specs > div {
  display: grid;
  grid-template-columns: 34% 1fr;
  gap: var(--sp-4);
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--rule);
  font-size: 12px;
  letter-spacing: 0.01em;
}
.arch-specs dt {
  color: var(--muted);
  letter-spacing: 0.06em;
  font-size: 10px;
  align-self: center;
}
.arch-specs dd { align-self: center; }

.arch-action {
  display: flex;
  justify-content: space-between;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--rule);
  font-size: 12px;
  letter-spacing: 0.06em;
}
.arch-action:hover { opacity: 1; color: var(--accent); }

/* stage (image/video) */
.arch-stage {
  --stage-h: clamp(360px, 44vw, 560px);
  --stage-pad: clamp(20px, 3vw, 48px);
  position: relative;
  height: var(--stage-h);
  background: var(--cream-2);
  overflow: hidden;
}
.arch-stage[data-frame="browser"] {
  background: #000;
  padding: var(--stage-pad);
  display: flex;
  align-items: center;
  justify-content: center;     /* centre the browser window in the stage */
}
.arch-stage-media { width: 100%; height: 100%; position: relative; }
.arch-stage-media img,
.arch-stage-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: opacity 300ms var(--ease-out);
}
/* browser mode: the window shrink-wraps to the media in BOTH axes so the chrome
   and the content stay one unit — bar flush on top, window centred, no crop, no
   vertical letterbox gap. The image (height:auto below) drives the box size. */
.arch-stage[data-frame="browser"] .arch-stage-media {
  height: auto;                /* hug the image vertically (was 100% → caused the gap) */
  max-height: 100%;            /* never taller than the stage */
  width: fit-content;          /* shrink-wrap the window to the media width */
  max-width: 100%;
  position: relative;
  display: block;
  box-sizing: border-box;
  padding-top: 28px;           /* reserve space for the overlay chrome bar */
  background: #1A1A18;
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
}
.arch-stage[data-frame="browser"] .arch-stage-media::before {
  content: '';
  position: absolute;          /* overlay → spans the window (= media) width exactly */
  top: 0; left: 0; right: 0;
  height: 28px;
  background: #1A1A18;
  background-image:
    radial-gradient(circle at 14px 14px, #FF5F57 5px, transparent 5.5px),
    radial-gradient(circle at 34px 14px, #FEBC2E 5px, transparent 5.5px),
    radial-gradient(circle at 54px 14px, #28C840 5px, transparent 5.5px);
  border-bottom: 1px solid var(--rule);
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
}
.arch-stage[data-frame="browser"] .arch-stage-media img,
.arch-stage[data-frame="browser"] .arch-stage-media video {
  display: block;
  height: auto;           /* size to the image so width-clamping shrinks it as one unit (no letterbox) */
  width: auto;
  max-width: 100%;        /* clamp by stage width → height follows the ratio */
  max-height: calc(var(--stage-h) - 2 * var(--stage-pad) - 28px);  /* clamp by stage height minus chrome */
  object-fit: contain;    /* harmless now the box equals the media; guards the edge case */
  background: #000;
}
.arch-stage-media.is-fading img,
.arch-stage-media.is-fading video { opacity: 0; }

/* poster mode: show the whole poster letterboxed on black — no crop, no chrome */
.arch-stage[data-frame="poster"] .arch-stage-media img,
.arch-stage[data-frame="poster"] .arch-stage-media video {
  object-fit: contain;
  background: #000;
}

.arch-pager {
  position: absolute;
  bottom: 12px; right: 12px; z-index: 2;
  display: flex; align-items: center; gap: var(--sp-3);
  border: 1px solid var(--rule);
  background: var(--cream);
  padding: 4px 10px;
  font-size: 10px;
  letter-spacing: 0.08em;
}
.arch-pager button:hover { color: var(--accent); }

/* collection cards */
.arch-cards {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(190px, 23vw, 300px);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -ms-overflow-style: none;
  border-bottom: 1px solid var(--rule);
}
.arch-cards::-webkit-scrollbar { display: none; }

.arch-card {
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  text-align: left;
  background: none;
  border-right: 1px solid var(--rule);
  padding: var(--sp-3) var(--sp-3) var(--sp-4);
  cursor: pointer;
  transition: background 240ms var(--ease-out);
}
.arch-card:hover { background: var(--cream-2); }
.arch-card.is-active { background: var(--cream-2); color: var(--ink); border-right-color: var(--rule); }

.ac-frame {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--cream);
  margin-bottom: var(--sp-3);
  position: relative;
}
.ac-frame img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  transition: transform 800ms var(--ease-out);
}
.arch-card:hover .ac-frame img { transform: scale(1.04); }

/* tag chips under the title — vibrant fill, knockout (page-bg) text */
.ac-tags {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin: 2px 0 1px;
  pointer-events: none;
}
.ac-tag {
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 400;
  line-height: 1;
  text-box: trim-both cap alphabetic;  /* trim font leading → symmetric padding truly centers the glyphs */
  letter-spacing: 0.04em;
  padding: 4px 8px;
  border-radius: 999px;       /* pill — matches .project-tags on detail pages */
  background: var(--c, var(--accent));
  color: var(--cream);        /* text = page background → knockout */
  white-space: nowrap;
}

/* mini browser chrome on web-project thumbnails */
.arch-card[data-frame="browser"] .ac-frame {
  background: transparent;   /* no black mat — the mini-window floats on the page bg */
  padding: 5%;          /* % = always relative to frame WIDTH → scales proportionally */
  display: block;
  aspect-ratio: auto;   /* drop the fixed 4/3 → window matches each image's ratio */
  align-self: start;    /* don't stretch the window to the row height */
}
.arch-card[data-frame="browser"] .ac-frame::before {
  content: '';
  display: block;       /* grid flow, not absolute — always flush with image */
  height: 10px;
  background: #1A1A18;
  background-image:
    radial-gradient(circle at 7px 5px, #FF5F57 1.8px, transparent 2.2px),
    radial-gradient(circle at 15px 5px, #FEBC2E 1.8px, transparent 2.2px),
    radial-gradient(circle at 23px 5px, #28C840 1.8px, transparent 2.2px);
  border-bottom: 1px solid var(--rule);
  border-radius: 3px 3px 0 0;
}
.arch-card[data-frame="browser"] .ac-frame img {
  width: 100%; height: auto;   /* natural ratio drives the window height — no crop */
  object-fit: contain;
  background: transparent;
  transition: filter 600ms var(--ease-out);
}
/* override default scale-on-hover so the image stays glued to the bar */
.arch-card[data-frame="browser"]:hover .ac-frame img {
  transform: none;
  filter: brightness(1.08);
}

/* poster thumbnails: full poster, no crop — keep the 4/3 card height */
.arch-card[data-frame="poster"] .ac-frame { background: transparent; }
.arch-card[data-frame="poster"] .ac-frame img { object-fit: contain; }
.arch-card[data-frame="poster"]:hover .ac-frame img { transform: none; filter: brightness(1.06); }

/* web-project thumbnails: the clip layers over the resting poster and
   fades in on hover (video injected by initArchive). */
.ac-media { position: relative; display: block; line-height: 0; width: 100%; }
.arch-card:not([data-frame="browser"]) .ac-frame .ac-media { height: 100%; }
.ac-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;          /* matches the browser-frame img (no crop) */
  background: transparent;
  opacity: 0;
  transition: opacity 320ms var(--ease-out);
  pointer-events: none;
}
.arch-card:not([data-frame="browser"]) .ac-video { object-fit: cover; }
.arch-card:hover .ac-video { opacity: 1; }

.ac-meta { display: flex; flex-direction: column; gap: 3px; }
.ac-num {
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.arch-card.is-active .ac-num { color: var(--accent); }
.ac-title { font-size: 12px; letter-spacing: 0.01em; }
.ac-by, .ac-year {
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.arch-card.is-active .ac-by,
.arch-card.is-active .ac-year { color: var(--muted); }

/* tablet / mobile */
@media (max-width: 900px) {
  .arch-featured { grid-template-columns: 1fr; }
  .arch-info { border-right: none; border-bottom: 1px solid var(--rule); }
  .arch-stage { order: -1; --stage-h: clamp(280px, 60vw, 440px); height: var(--stage-h); }
  .arch-specs { margin-top: var(--sp-6); }
}

/* PROJECT DETAIL — image at natural ratio, info below */
.project-detail { margin-top: var(--header-h); }
.project-cover {
  width: 100%;
  background: var(--cream-2);
  overflow: hidden;
  display: flex;
  justify-content: center;
}
.project-cover[data-frame="browser"] {
  background: transparent;            /* no black field — the window floats on the page bg */
  overflow: visible;                 /* let the window's drop-shadow breathe */
  padding: clamp(24px, 4vw, 56px) clamp(16px, 3vw, 40px);
}
.project-cover img,
.project-cover video {
  width: auto;
  max-width: 100%;
  max-height: 90vh;
  height: auto;
  object-fit: contain;
  display: block;
}

/* stacked frame gallery — browser-framed web mockups */
.project-gallery {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(32px, 5vw, 64px);
  padding: clamp(28px, 5vw, 64px) var(--gutter);
  background: #000;
}
.project-gallery img,
.project-gallery video {
  width: auto;
  max-width: 100%;
  max-height: 88vh;
  height: auto;
  object-fit: contain;
  display: block;
}

/* full case-study galleries — real photos extracted from the source PDFs.
   Container-responsive masonry: column count follows available width, so it
   adapts to both the half-width detail panel and a full-width page. */
.project-pages {
  column-width: 20rem;
  column-gap: clamp(12px, 1.6vw, 22px);
  padding: clamp(24px, 4.5vw, 60px) var(--gutter);
  background: var(--cream-2);
}
.project-pages img {
  width: 100%;
  height: auto;
  display: block;
  margin: 0 0 clamp(12px, 1.6vw, 22px);
  break-inside: avoid;
  border-radius: 2px;
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.45);
}
/* lead image runs full-width as a hero — but only when the set is large
   enough that a banner won't leave a lone orphan below it (4+ images) */
.project-pages img:first-child:not(:nth-last-child(-n + 3)) {
  column-span: all;
  margin-bottom: clamp(16px, 2.4vw, 32px);
}

/* browser chrome wrapper (injected by JS) */
.browser-wrap {
  display: inline-flex;   /* shrinks to image's natural width */
  flex-direction: column;
  max-width: 100%;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--rule);
  box-shadow: 0 24px 64px rgba(0,0,0,0.55);
}
/* Cap the WINDOW width by the viewport-height budget (bar is 36px tall) using
   the media's aspect ratio (--ar = w/h, set by JS). This is what kills the
   black pillarbox: if we instead clamp the image's max-height, a tall shot
   shrinks its own width while the inline-flex wrap stays at the image's
   intrinsic width — so the chrome bar ends up wider than the image. Capping
   the wrap width means the image always fills it and the bar matches. */
.browser-wrap:not(.browser-wrap--embed) {
  max-width: min(100%, calc((88vh - 36px) * var(--ar, 1.6)));
}
.browser-wrap img,
.browser-wrap video {
  width: auto;
  max-width: 100%;
  max-height: none;   /* the wrap's max-width now enforces the height budget */
  height: auto;
  display: block;
  flex-shrink: 0;
}
/* Vimeo cover embed: fills a capped width instead of shrink-wrapping to an
   intrinsic media size, holding each clip's aspect ratio via the --r variable. */
.browser-wrap--embed {
  display: flex;
  width: min(100%, 1340px);   /* fill the width on laptops so the window isn't boxed in black */
}
.vimeo-embed {
  position: relative;
  width: 100%;
  background: #000;
}
.vimeo-embed::before {
  content: '';
  display: block;
  padding-top: calc(var(--r, .5625) * 100%);
}
.vimeo-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.browser-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 14px;
  background: #1A1A18;
  border-bottom: 1px solid var(--rule);
  flex-shrink: 0;
}
.br-dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  flex-shrink: 0;
}
.br-close { background: #FF5F57; }
.br-min   { background: #FEBC2E; }
.br-max   { background: #28C840; }
.br-url {
  flex: 1;
  display: flex;
  justify-content: center;
}
.br-url span {
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--muted);
  background: var(--cream);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 2px 10px;
  max-width: 260px;
  width: 100%;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* PDF photo grid — uniform 4:3 cells (cropped via cover) */
.project-shots {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--gutter) 0;
}
.project-shots img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  background: var(--cream-2);
}
@media (max-width: 640px) {
  .project-shots { grid-template-columns: 1fr; }
}
.project-shots--portrait img { aspect-ratio: 2 / 3; }

/* year section label within a project */
.project-year {
  padding: var(--sp-5) var(--gutter) var(--sp-1);
  font-family: var(--sans);
  font-size: var(--tx-xs);
  letter-spacing: 0.14em;
  color: var(--muted);
  border-top: 1px solid var(--rule);
}
.project-year:first-of-type { border-top: none; }

/* single-column header band: meta (num/title/tags) stacked over the spec list.
   The body copy is pulled out below into its own full-width column. */
.project-info-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(var(--sp-5), 2.5vw, var(--sp-8));
  padding: clamp(var(--sp-6), 3vw, var(--sp-10)) var(--gutter);
  border-bottom: 1px solid var(--rule);
  align-items: start;
}

.project-meta { max-width: 640px; }

.project-num {
  font-size: var(--tx-xs);
  letter-spacing: 0.14em;
  color: var(--muted);
  margin-bottom: var(--sp-3);
}

.project-h1 {
  font-size: clamp(16px, 1.8vw, 26px);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: 0.03em;
  margin-bottom: clamp(var(--sp-5), 2.2vw, var(--sp-8));
}

/* discipline tags — pulled from each project's PDF case study */
.project-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  list-style: none;
  margin: 0 0 clamp(var(--sp-5), 2.4vw, var(--sp-8));
  padding: 0;
  max-width: 520px;
}
.project-tags li {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--cream);                 /* knockout: text = page background */
  background: var(--c, var(--accent));  /* vibrant per-tag fill — matches thumbnail chips */
  border-radius: 999px;
  line-height: 1;                       /* tighten vertical box — match .ac-tag chips */
  text-box: trim-both cap alphabetic;  /* trim font leading → symmetric padding truly centers the glyphs */
  padding: 5px 10px;
  white-space: nowrap;
}

/* body copy — its own full-width single column, separate from the info row */
.project-descriptions {
  padding: clamp(var(--sp-6), 3vw, var(--sp-10)) var(--gutter);
}
.project-descriptions p {
  font-size: 13px;
  color: var(--ink-soft);
  margin-bottom: var(--sp-3);
  max-width: 720px;
}

.project-specs {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-1) var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--rule);
  white-space: nowrap;
  min-width: 160px;
}
.project-specs dt {
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--muted);
  padding-top: 3px;
}
.project-specs dd {
  font-size: 12px;
  letter-spacing: 0.02em;
}

.project-nav-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--sp-4) var(--gutter);
  border-bottom: 1px solid var(--rule);
  font-size: 10px;
  letter-spacing: 0.14em;
}
.project-nav-bar .pn-next { text-align: right; }

@media (max-width: 640px) {
  :root {
    --header-h: 60px;
    /* headings tower on phones — pull every display/heading token down so the
       whole page reads a notch smaller, not just the body. */
    --tx-display: clamp(2.25rem,   10vw, 3.25rem); /* 72→240 → 36→52 */
    --tx-hero:    clamp(1.6875rem, 7vw,  2.25rem); /* 48→140 → 27→36 */
    --tx-xl:      clamp(1.25rem,   4vw,  1.5rem);  /* 34→80  → 20→24 */
    --tx-l:       clamp(1rem,      2.6vw, 1.1875rem);/* 22→36 → 16→19 */
    --tx-m:  0.8125rem;   /* 17 → 13 — body/lede on phones */
    --tx-s:  0.6875rem;   /* 13 → 11 — UI/label text */
    --tx-xs: 0.625rem;    /* 11 → 10 — eyebrows/captions (floor) */
    /* tighter page padding on phones — pull side gutters + section vertical
       padding in so content isn't boxed by fat margins on a small screen. */
    --gutter:     clamp(1.25rem,  5vw, 1.75rem);   /* 32→96 → 20→28 */
    --section-py: clamp(1.375rem, 3vw, 1.75rem);   /* 28→56 → 22→28 */
  }

  /* Korean reads cramped at small sizes — give KO extra leading on phones so the
     now-smaller body breathes (EN keeps its tighter 1.35; desktop KO stays 1.4). */
  html[lang^="ko"] body { line-height: 1.55; }

  /* logo down to ~1rem so it sits level with the brand text; drop the top-bar
     email on phones — it still lives in the contact section + footer. */
  .brand-logo { height: 1rem; }
  .site-header .header-contact { display: none; }

  .gallery-strip .hint { display: none; }

  /* IG strip on phones: stop the auto-marquee and let the finger swipe through
     it; shrink the cards so a single portrait doesn't tower over the screen.
     The cloned (aria-hidden) duplicates are hidden so the swipe runs each post
     once. (overflow:hidden + the marquee is what blocked manual scrolling.) */
  .h-scroll {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .h-scroll::-webkit-scrollbar { display: none; }
  .h-track { animation: none; width: max-content; }
  .h-track [aria-hidden="true"] { display: none; }
  .h-card { flex: 0 0 44vw; }

  /* detail page: full-width, larger body so it doesn't read as a thin column of
     fine print on a phone */
  .project-h1 { font-size: clamp(18px, 5.5vw, 24px); }
  .project-descriptions p { font-size: 13.5px; line-height: 1.6; max-width: none; }
  .project-tags { max-width: none; }

  .hero-meta { gap: var(--sp-5); }

  .site-menu nav a { font-size: clamp(40px, 11vw, 80px); }
}

/* — phone — */
@media (max-width: 480px) {
  :root { --header-h: 56px; --gutter: 1rem; }   /* 16px side padding on small phones */

  .h-card { flex: 0 0 46vw; }

  .big-mail { font-size: clamp(28px, 8vw, 60px); }

  .footer-grid .col-contact { text-align: left; }
}
