/* ============================================================
   PROGNE.CO — MAIN SITE CSS
   Aesthetic: Raw / Textural / Brutalist Found-Art
   ============================================================ */

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

:root {
  --ink:      #0a0a0a;
  --paper:    #f0ede6;
  --off:      #e2ddd5;
  --chalk:    #f8f5f0;
  --accent:   #bb0303;
  --accent2:  #1a3a6e;
  --muted:    #7a7368;
  --font-disp: 'Bebas Neue', 'Arial Narrow', sans-serif;
  --font-mono: 'IBM Plex Mono', 'Courier New', monospace;
  --font-goth: 'UnifrakturMaguntia', serif;
  --section-pad: clamp(4rem, 10vw, 9rem);
}

html { scroll-behavior: smooth; }

body {
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 1.7;
  background: var(--paper);
  color: var(--ink);
  overflow-x: hidden;
  cursor: none;
  -webkit-tap-highlight-color: transparent;
}

a { color: inherit; text-decoration: none; }
ul { list-style: none; }
img, video { max-width: 100%; display: block; }
button { cursor: none; font-family: inherit; background: none; border: none; }
textarea, input, select { font-family: var(--font-mono); }

/* Visible keyboard focus, site-wide. Form fields override this with
   their own accent-underline treatment further down (outline: none
   there is intentional, not a lost focus state). */
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ── GRAIN CANVAS ─────────────────────────────────────────── */
#grain {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 9000;
  mix-blend-mode: multiply;
  opacity: 0.45;
}

/* ── CUSTOM CURSOR ────────────────────────────────────────── */
.cur-dot {
  position: fixed;
  width: 6px;
  height: 6px;
  background: var(--ink);
  border-radius: 50%;
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  transition: background 0.2s;
}
.cur-ring {
  position: fixed;
  width: 32px;
  height: 32px;
  border: 1.5px solid var(--ink);
  border-radius: 50%;
  pointer-events: none;
  z-index: 9998;
  transform: translate(-50%, -50%);
  transition: transform 0.12s ease, width 0.2s ease, height 0.2s ease, border-color 0.2s;
}
body.cursor-hover .cur-dot { background: var(--accent); }
body.cursor-hover .cur-ring {
  width: 54px;
  height: 54px;
  border-color: var(--accent);
}
@media (hover: none) {
  .cur-dot, .cur-ring { display: none; }
}

/* ── PRELOADER ────────────────────────────────────────────── */
#preloader {
  position: fixed;
  inset: 0;
  background: var(--ink);
  z-index: 99999;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  transition: opacity 0.6s ease, visibility 0.6s ease;
}
#preloader.done { opacity: 0; visibility: hidden; }

.pre-inner { text-align: center; }

.pre-word {
  font-family: var(--font-disp);
  font-size: clamp(3rem, 15vw, 10rem);
  color: var(--paper);
  letter-spacing: 0.1em;
  display: block;
  position: relative;
  overflow: hidden;
  /* Font-cycling used to live here as a CSS @keyframes animation on
     font-family, using steps(1). Pulled it out entirely — animating
     a discrete (non-interpolable) property through multiple keyframes
     with an explicit steps() function is a genuinely inconsistent
     area of the CSS spec across browsers (which keyframe "wins" and
     exactly when isn't handled identically everywhere). That's
     consistent with it working in some sessions/browsers and not
     others. Driven by plain JS now instead — see initPreloaderFonts()
     in script.js — which has zero ambiguity: it just sets the actual
     font-family string at each step, directly. */
}
.pre-word::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  color: var(--accent);
  clip-path: inset(100% 0 0 0);
  /* No fixed delay anymore — JS adds .pre-reveal to .pre-word the
     moment the font cycle actually finishes (which itself now waits
     for the fonts to genuinely be loaded, not a guessed clock time).
     See initPreloaderSequence() in script.js. This removes the whole
     class of bug where a fixed-time guess and real font-load time
     drift apart — most visible on a first-ever visit with nothing
     cached yet. */
  transition: clip-path 1.8s cubic-bezier(0.77,0,0.175,1);
}
.pre-word.pre-reveal::after {
  clip-path: inset(-2px 0 0 0);
}

.pre-bar {
  width: 200px;
  height: 2px;
  background: rgba(240,237,230,0.2);
  margin: 1.5rem auto 0;
  overflow: hidden;
}
.pre-fill {
  height: 100%;
  background: var(--accent);
  width: 0;
  transition: width 1.8s ease;
}
@media (prefers-reduced-motion: reduce) {
  .pre-word::after, .pre-fill { transition: none; }
}

/* ── HEADER / NAV ─────────────────────────────────────────── */
#nav-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  padding: 1.5rem 2.5rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  z-index: 1000;
  mix-blend-mode: difference;
}

.nav-right {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}
.nav-quicklinks {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}
.nav-quicklink {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--paper);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease;
}
.nav-quicklink:hover { border-bottom-color: var(--paper); }

@media (max-width: 600px) {
  .nav-quicklinks { gap: 1rem; }
  .nav-quicklink { font-size: 0.66rem; }
  .nav-right { gap: 1rem; }
}

.logo {
  font-family: var(--font-disp);
  font-size: 1.6rem;
  letter-spacing: 0.15em;
  color: var(--paper);
  transition: color 0.2s;
}
.logo span { color: var(--accent); }

/* Burger */
.burger {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px;
  z-index: 1001;
}
.burger span {
  display: block;
  width: 28px;
  height: 2px;
  background: var(--paper);
  transition: transform 0.3s ease, opacity 0.3s ease, width 0.3s ease;
  transform-origin: center;
}
.burger span:last-child { width: 18px; }
.burger:hover span { width: 28px; }

body.nav-open .burger span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
body.nav-open .burger span:nth-child(2) { opacity: 0; transform: scaleX(0); }
body.nav-open .burger span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); width: 28px; }

/* Nav overlay */
.nav-overlay {
  position: fixed;
  inset: 0;
  background: var(--ink);
  z-index: 999;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 5rem 3rem 3rem;
  clip-path: circle(0% at calc(100% - 3.5rem) 3.5rem);
  transition: clip-path 0.7s cubic-bezier(0.77, 0, 0.175, 1);
  pointer-events: none;
}
body.nav-open .nav-overlay {
  clip-path: circle(150% at calc(100% - 3.5rem) 3.5rem);
  pointer-events: all;
}

.nav-overlay ul {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.nav-link {
  font-family: var(--font-disp);
  font-size: clamp(3rem, 9vw, 7rem);
  color: rgba(240,237,230,0.35);
  letter-spacing: 0.05em;
  line-height: 1.1;
  display: flex;
  align-items: baseline;
  gap: 1rem;
  transition: color 0.2s ease;
  opacity: 0;
  transform: translateX(-40px);
}
.nav-link::before {
  content: attr(data-label);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--muted);
  letter-spacing: 0.1em;
  min-width: 2rem;
}
body.nav-open .nav-link {
  opacity: 1;
  transform: translateX(0);
}
body.nav-open .nav-link:nth-child(1) { transition: opacity 0.4s 0.3s, transform 0.4s 0.3s, color 0.2s; }
body.nav-open .nav-link:nth-child(2) { transition: opacity 0.4s 0.38s, transform 0.4s 0.38s, color 0.2s; }
body.nav-open .nav-link:nth-child(3) { transition: opacity 0.4s 0.46s, transform 0.4s 0.46s, color 0.2s; }
body.nav-open .nav-link:nth-child(4) { transition: opacity 0.4s 0.54s, transform 0.4s 0.54s, color 0.2s; }
body.nav-open .nav-link:nth-child(5) { transition: opacity 0.4s 0.62s, transform 0.4s 0.62s, color 0.2s; }
.nav-link:hover { color: var(--paper); }
.nav-link--cta { color: var(--accent); }
.nav-link--cta:hover { color: var(--paper); }

.nav-footer {
  margin-top: auto;
  display: flex;
  gap: 2rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 0.4s 0.7s;
}
body.nav-open .nav-footer { opacity: 1; }

/* ── SECTIONS ─────────────────────────────────────────────── */
.section { position: relative; width: 100%; padding: var(--section-pad) 0; }
.section--dark { background: var(--ink); color: var(--paper); }
.container { max-width: 1200px; margin: 0 auto; padding: 0 2.5rem; }

.section-header {
  display: flex;
  align-items: baseline;
  gap: 1.5rem;
  margin-bottom: clamp(3rem, 6vw, 5rem);
  border-bottom: 1px solid currentColor;
  padding-bottom: 1rem;
  opacity: 0.9;
}
.section-num {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  color: var(--accent);
  padding-top: 0.3em;
}
.section-title {
  font-family: var(--font-disp);
  font-size: clamp(2.5rem, 6vw, 5rem);
  letter-spacing: 0.05em;
  line-height: 1;
  font-weight: 400;
}

/* ── HERO ─────────────────────────────────────────────────── */
#hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0;
  overflow: hidden;
  position: relative;
}

.hero-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.hero-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(10,10,10,0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(10,10,10,0.07) 1px, transparent 1px);
  background-size: 60px 60px;
}

.hero-content {
  position: relative;
  z-index: 2;
  padding: 8rem 2.5rem 8rem;
  max-width: 1200px;
  margin: 0 auto;
  width: 100%;
}

.hero-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  color: var(--muted);
  text-transform: uppercase;
  margin-bottom: 1.5rem;
}
.nowrap { white-space: nowrap; }

.hero-title {
  font-family: var(--font-disp);
  font-size: clamp(6rem, 22vw, 18rem);
  line-height: 0.88;
  letter-spacing: -0.01em;
  color: var(--ink);
  display: flex;
  flex-direction: column;
  margin-bottom: 3rem;
  pointer-events: none;
  user-select: none;
  position: relative;
}
.ht-line {
  display: block;
  -webkit-text-stroke: 1.5px var(--ink);
  position: relative;
}
.ht-line--right {
  text-indent: 0.25em;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--ink);
}
.ht-line--right::after {
  content: 'GNE';
  position: absolute;
  left: 0px;
  color: var(--accent);
  -webkit-text-stroke: 0;
  clip-path: inset(0 100% 0 0);
  /* No fixed delay anymore. This used to be timed to a guessed clock
     offset from page load, assuming the preloader's total duration
     stayed constant — which meant every time the preloader's own
     timing changed (twice, so far), this had to be manually re-tuned
     to match or it would start too early/late. JS now adds .reveal to
     #hero-title the moment the preloader actually finishes (a real
     event, not a guess), removing that whole class of bug for good. */
  transition: clip-path 1.8s cubic-bezier(0.77,0,0.175,1);
  transition-delay: 0.6s;
}
#hero-title.reveal .ht-line--right::after {
  clip-path: inset(0 0% 0 0);
}

/* CMYK color-separation wipe, staggered behind the red reveal above —
   same left-to-right clip-path sweep, just offset in start time.
   Cyan's edge leads, magenta trails slightly behind it, yellow
   behind that, red last of all (0s/0.2s/0.4s/0.6s transition-delay,
   relative to when #hero-title.reveal is added — not a fixed clock
   time — so the stagger stays correct regardless of when that
   actually happens). Since red is painted on top (it's the ::after,
   always topmost) its advancing edge covers each color in turn as it
   catches up — so what actually reads on screen is a single sweep
   with a trailing chromatic edge, not four separate wipes. */
.cmyk-layer {
  position: absolute;
  left: 0px;
  -webkit-text-stroke: 0;
  clip-path: inset(0 100% 0 0);
  transition: clip-path 1.8s cubic-bezier(0.77,0,0.175,1);
}
.cmyk-c { color: #00AEEF; transition-delay: 0s; }
.cmyk-m { color: #EC008C; transition-delay: 0.2s; }
.cmyk-y { color: #FFED00; transition-delay: 0.4s; }
#hero-title.reveal .cmyk-c,
#hero-title.reveal .cmyk-m,
#hero-title.reveal .cmyk-y {
  clip-path: inset(0 0% 0 0);
}

@media (prefers-reduced-motion: reduce) {
  .cmyk-layer, .ht-line--right::after { transition: none; }
}

/* ── HERO BIRD ────────────────────────────────────────────── */
.hero-bird {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 70vh;
  width: auto;
  max-width:70%;
  object-fit: contain;
  z-index: 1;
  opacity: 0.92;
  cursor: pointer;
}

.hero-sub {
  display: flex;
  align-items: flex-end;
  gap: 3rem;
  flex-wrap: wrap;
  position: relative;
  z-index: 3;
}
.hero-sub p {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  line-height: 1.7;
  color: var(--muted);
  max-width: 28ch;
}

/* Buttons */
.btn-raw {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.85rem 2rem;
  border: 1.5px solid var(--ink);
  color: var(--ink);
  background: transparent;
  position: relative;
  overflow: hidden;
  transition: color 0.25s ease;
  white-space: nowrap;
}
.btn-raw::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s cubic-bezier(0.77,0,0.175,1);
  z-index: -1;
}
.btn-raw:hover { color: var(--paper); }
.btn-raw:hover::before { transform: scaleX(1); }

.section--dark .btn-raw {
  border-color: var(--paper);
  color: var(--paper);
}
.section--dark .btn-raw::before { background: var(--paper); }
.section--dark .btn-raw:hover { color: var(--ink); }

.hero-scroll-hint {
  position: absolute;
  bottom: 2.5rem;
  right: 2.5rem;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.2em;
  color: var(--muted);
  writing-mode: vertical-rl;
  text-transform: lowercase;
  z-index: 2;
  animation: blink 2.5s step-end infinite;
}
@keyframes blink { 50% { opacity: 0.2; } }

/* ── MARQUEE BAR ──────────────────────────────────────────── */
/*
  This is the single scrolling-motion beat on the page (the hero's
  own ticker was removed so this doesn't compete with itself).
  Content is duplicated (10 items = 2× the same 5), so -50% is
  exactly one full copy and the loop is seamless.
*/
.marquee-bar {
  background: var(--accent);
  overflow: hidden;
  padding: 0.8rem 0;
  border-top: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
}
.marquee-track {
  display: flex;
  gap: 3rem;
  white-space: nowrap;
  width: max-content;
  animation: marquee-scroll 28s linear infinite;
}
.marquee-track span {
  font-family: var(--font-disp);
  font-size: 1.1rem;
  letter-spacing: 0.2em;
  color: var(--paper);
}

@keyframes marquee-scroll {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}

/* ── WORK GRID ────────────────────────────────────────────── */
.work-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto;
  gap: 2px;
}
.work-card--wide {
  grid-column: 2 / 4;
}
.work-card {}
.work-card-img {
  aspect-ratio: 4/5;
  position: relative;
  overflow: hidden;
  background: var(--off);
}
.work-card--wide .work-card-img {
  aspect-ratio: 16/7;
}
/* Row 2 (the notebook square + the wide Event Drops card) needs to
   line up exactly. Independent aspect-ratios on a 1-col vs 2-col-span
   item will never produce equal heights by coincidence — a 4:5 image
   at one column's width is taller than a 16:7 image at two columns'
   width. Overriding both to one explicit height (rather than a ratio)
   is what actually guarantees the row — and the caption borders below
   it — sit level. */
.work-card-img--row2 {
  aspect-ratio: unset;
  height: clamp(240px, 27vw, 380px);
}

/* Base ink washes per project type — visible fallback if a photo is
   ever missing, and the tint that keeps every card reading as one
   family even though the photos vary a lot in color. */
.wc-1 { background: #1a1a1a; }
.wc-2 { background: #2a2320; }
.wc-3 { background: #0f1a2e; }
.wc-4 { background: #1f1008; }
.wc-5 { background: #14201c; }

/* Real production photography, when present. Sits above the base
   wash, below the noise/halftone/gradient treatment — the print
   texture reads as applied TO the photo, like ink on a printed
   photo, rather than the photo being a separate element. */
.wc-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  filter: contrast(1.06) saturate(0.88);
  transform: scale(1);
  transition: transform 0.7s cubic-bezier(0.16,1,0.3,1);
}
.work-card:hover .wc-photo { transform: scale(1.045); }

/* Fine paper-grain noise, sits just above the base wash */
.work-card-img::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.25'/%3E%3C/svg%3E");
  background-size: 200px 200px;
  mix-blend-mode: overlay;
  opacity: 0.6;
  z-index: 1;
}

/* Halftone dot screen — the actual texture of a printed film separation.
   This is the placeholder's real content: it reads as "this is a print
   shop" even with zero photography. */
.wc-halftone {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(var(--paper) 1px, transparent 1.7px);
  background-size: 8px 8px;
  opacity: 0.16;
  mix-blend-mode: overlay;
  z-index: 2;
  pointer-events: none;
}

/* Bottom shadow so the label/tag stay legible over any wash */
.work-card-img::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(10,10,10,0.7) 0%, transparent 55%);
  z-index: 3;
}

/* Registration mark — the crosshair-in-circle press operators use to
   align color layers. Sits top-right, like a mark on a print proof. */
.wc-reg {
  position: absolute;
  top: 0.9rem;
  right: 0.9rem;
  color: var(--accent);
  opacity: 0.85;
  z-index: 4;
}
.wc-reg svg { display: block; }

/* Ink spec tag — small, factual, mono. Reads like a real production tag. */
.wc-ink-tag {
  position: absolute;
  top: 0.9rem;
  left: 0.9rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(240,237,230,0.55);
  z-index: 4;
}

.wc-label {
  position: absolute;
  bottom: 1rem;
  left: 1rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(240,237,230,0.7);
  z-index: 4;
}

.work-card-desc {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  line-height: 1.6;
  color: rgba(240,237,230,0.5);
  padding: 0.75rem 0;
  border-bottom: 1px solid rgba(240,237,230,0.1);
}

.work-card-img { cursor: none; }
.work-card:hover .work-card-img::after {
  background: linear-gradient(to top, rgba(200,56,10,0.6) 0%, transparent 60%);
  transition: background 0.4s ease;
}

/* ── PROCESS ──────────────────────────────────────────────── */
#process .container {
  position: relative;
}

/* Line-art bird mark, quiet background art in the empty right margin.
   Fixed size + contain (was an invalid "background-size: absolute",
   which browsers silently ignore) so it renders predictably at any
   viewport width instead of relying on an oversized 2000px box. */
#process .container::before {
  content: '';
  position: absolute;
  top: -6rem;
  right: -4rem;
  width: 640px;
  height: 640px;
  background-image: url('assets/bird-contour.svg');
  background-repeat: no-repeat;
  background-size: contain;
  background-position: top right;
  opacity: 0.08;
  pointer-events: none;
  z-index: 0;
}

.process-section { padding-bottom: clamp(3rem, 6vw, 5rem); }

.process-intro {
  position: relative;
  z-index: 1;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--muted);
  letter-spacing: 0.05em;
  margin-top: -1.5rem;
  margin-bottom: 2.5rem;
}

/* ── PRESS STAGE ──────────────────────────────────────────────
   The pinned unit. Fixed to 100svh so the carousel and the progress
   bar live in the same frame with no overflow below the fold —
   that's what makes the progress bar read as part of the experience
   instead of arriving late. */
.press-stage {
  position: relative;
  height: 100svh;
  min-height: 480px;
  display: flex;
  flex-direction: column;
  background: var(--chalk);
  border-top: 1px solid rgba(10,10,10,0.1);
  border-bottom: 1px solid rgba(10,10,10,0.1);
  overflow: hidden;
}

/* ── PRESS PASS CAROUSEL ──────────────────────────────────── */
/* Baseline: a native horizontal scroll-snap strip. Works with zero
   JS, respects reduced-motion by default, and is what mobile always
   uses. On wide viewports with motion allowed, script.js upgrades
   this into a GSAP scroll-pinned experience — see initPressPass(). */
.press-pass {
  position: relative;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.press-pass::-webkit-scrollbar { display: none; }

/* Once JS confirms desktop + motion allowed, .press-stage gets
   .is-enhanced and this switches .press-track to a GSAP transform
   instead of native scroll. */
.press-stage.is-enhanced .press-pass {
  overflow: hidden;
}

.press-track {
  display: flex;
  height: 100%;
  width: max-content;
  will-change: transform;
}

.press-panel {
  position: relative;
  flex: 0 0 100vw;
  max-width: 100vw;
  height: 100%;
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.press-ink-wash {
  position: absolute;
  inset: 0;
  mix-blend-mode: multiply;
  opacity: 0.16;
  clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
  pointer-events: none;
  z-index: 0;
}
.press-photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0.22;
}
.press-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(0.4);
}
.press-panel--stage1 .press-ink-wash { background: var(--accent2); }
.press-panel--stage2 .press-ink-wash { background: var(--accent); }
.press-panel--stage3 .press-ink-wash { background: var(--ink); }
.press-panel--stage4 .press-ink-wash { background: var(--muted); }

.press-panel-inner {
  position: relative;
  z-index: 1;
  max-width: 640px;
  padding: 3rem clamp(2rem, 6vw, 6rem);
}

.press-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 2.5rem;
}
.press-tag {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.15em;
  color: var(--accent);
  text-transform: uppercase;
}
.press-reg { color: var(--muted); opacity: 0.7; }
.press-reg svg { display: block; }

.press-icon {
  color: var(--ink);
  margin-bottom: 1.5rem;
  opacity: 0.85;
}

.press-num {
  display: block;
  font-family: var(--font-goth);
  font-size: 3.25rem;
  line-height: 1;
  color: var(--accent);
  margin-bottom: 0.5rem;
}

.press-panel-inner h3 {
  font-family: var(--font-disp);
  font-size: clamp(2rem, 4vw, 2.75rem);
  letter-spacing: 0.04em;
  font-weight: 400;
  color: var(--ink);
  margin-bottom: 0.9rem;
}

.press-panel-inner p {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  line-height: 1.8;
  color: var(--ink);
  opacity: 0.75;
  max-width: 44ch;
}

/* ── PRESS PROGRESS BAR ───────────────────────────────────── */
.press-progress {
  flex: 0 0 auto;
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  padding: 1.25rem 2.5rem;
}
.press-progress-track {
  position: relative;
  height: 2px;
  background: rgba(10,10,10,0.12);
  margin-bottom: 1rem;
}
.press-progress-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 0%;
  background: var(--accent);
  transition: width 0.2s linear;
}
.press-progress-ticks {
  display: flex;
  justify-content: space-between;
}
.press-tick {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  color: var(--muted);
  padding: 0.3rem 0.1rem;
  transition: color 0.2s ease;
}
.press-tick.active { color: var(--accent); }
.press-tick:hover { color: var(--ink); }

@media (max-width: 600px) {
  .press-stage { height: auto; min-height: 0; }
  .press-panel { height: auto; min-height: 66vh; }
  .press-panel-inner { padding: 2.5rem 1.5rem; }
  .press-progress { padding: 1rem 1.5rem; }
}

/* ── STATEMENT ────────────────────────────────────────────── */
.statement-section {
  background: var(--ink) url('assets/birds-sunset.jpg') center 30% / cover no-repeat;
  padding: clamp(5rem, 12vw, 10rem) 2.5rem;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.statement-section::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(10,10,10,0.82) 0%, rgba(10,10,10,0.65) 45%, rgba(10,10,10,0.85) 100%);
  z-index: 1;
}

/* The watermark used to be centered on the whole .statement-section
   box (padding + content). On mobile the quote wraps into many more
   lines than desktop, so the section gets much taller — and "50% of
   the section" drifts away from where the quote actually sits.
   Centering it on .statement-inner instead (sized exactly to the
   blockquote + cite) keeps it tracking the visible text at any
   viewport or line-wrap count. */
.statement-inner {
  position: relative;
  z-index: 3;
}

blockquote {
  position: relative;
  font-family: var(--font-goth);
  font-size: clamp(2rem, 5vw, 4rem);
  line-height: 1.4;
  color: var(--paper);
  margin-bottom: 1.5rem;
}
/* Anchored to the blockquote specifically, not .statement-inner as a
   whole — the cite line below the quote was adding height that
   pulled the combined box's center (and this watermark, when it was
   centered on that combined box) down past the actual quote text. */
blockquote::before {
  content: 'PROGNE';
  position: absolute;
  font-family: var(--font-disp);
  font-size: 30vw;
  color: rgba(240,237,230,0.07);
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  pointer-events: none;
  white-space: nowrap;
  line-height: 1;
  z-index: -1;
}

cite {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.15em;
  color: var(--accent);
  font-style: normal;
}

/* ── CONNECT ──────────────────────────────────────────────── */
.connect-grid {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: 5rem;
  align-items: start;
}

.connect-info p {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  line-height: 1.8;
  color: rgba(240,237,230,0.65);
  margin-bottom: 1rem;
}
.inline-link {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(200,56,10,0.4);
  transition: border-color 0.2s;
}
.inline-link:hover { border-color: var(--accent); }

.connect-details {
  margin-top: 2.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.connect-details > div {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid rgba(240,237,230,0.1);
}
.cd-label {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
}
.cd-val {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--paper);
}
.cd-val[href]:hover { color: var(--accent); }

/* Form */
.connect-form {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.field-group {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.field-group label {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
}
.field-group input,
.field-group textarea {
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(240,237,230,0.25);
  color: var(--paper);
  padding: 0.6rem 0;
  font-size: 0.875rem;
  outline: none;
  resize: vertical;
  transition: border-color 0.2s;
  width: 100%;
}
.field-group input::placeholder,
.field-group textarea::placeholder { color: rgba(240,237,230,0.3); }
.field-group input:focus,
.field-group textarea:focus {
  border-bottom-color: var(--accent);
  box-shadow: 0 1px 0 0 var(--accent);
}

.btn-submit {
  align-self: flex-start;
  cursor: none;
}

.form-notice {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  color: var(--accent);
  min-height: 1.2em;
}

/* ── FOOTER ───────────────────────────────────────────────── */
.site-footer {
  background: var(--ink);
  border-top: 1px solid rgba(240,237,230,0.1);
  padding: 2rem 2.5rem;
}
.footer-inner {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
}
.footer-logo {
  font-family: var(--font-disp);
  font-size: 1.1rem;
  letter-spacing: 0.2em;
  color: rgba(240,237,230,0.5);
}
.footer-copy {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  color: rgba(240,237,230,0.3);
}
.footer-links {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.footer-portal {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  color: var(--accent);
  text-transform: uppercase;
  border-bottom: 1px solid rgba(200,56,10,0.3);
  transition: border-color 0.2s;
}
.footer-portal:hover { border-color: var(--accent); }

/* ── SCROLL ANIMATIONS ────────────────────────────────────── */
.fade-up {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.fade-up.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ── RESPONSIVE ───────────────────────────────────────────── */
@media (max-width: 900px) {
  .work-grid {
    grid-template-columns: 1fr 1fr;
  }
  .work-card--wide { grid-column: 1 / 3; }
  /* At 2 columns the notebook card re-pairs with Art Editions (not
     the wide card anymore), so the row-2 height override no longer
     applies — each reverts to its own natural ratio. */
  .wc-5.work-card-img--row2 { aspect-ratio: 4/5; height: auto; }
  .work-card--wide .work-card-img--row2 { aspect-ratio: 16/7; height: auto; }
  .connect-grid {
    grid-template-columns: 1fr;
    gap: 3rem;
  }
  /* On tablet, bird shrinks to not crowd the text */
  .hero-bird {
    height: 40vh;
    max-width: 45%;
  }
  /* Process line art gets cramped next to text at this width */
  #process .container::before {
    display: none;
  }
}

@media (max-width: 600px) {
  #nav-header { padding: 1.2rem 1.5rem; }
  .hero-content { padding: 7rem 1.5rem 6rem; }
  .container { padding: 0 1.5rem; }
  /* PRO and GNE now sit side by side on mobile instead of stacked —
     row instead of column. That means fitting roughly twice the
     characters on the same line width as before, so the per-character
     size necessarily comes down from the old stacked version (that's
     unavoidable geometry, not a smaller/timid choice) — this pushes
     it as large as reasonably fits on one line. text-indent reset to
     0 since that offset was tuned for GNE sitting on its own line
     below PRO; spacing between the two words is handled by the gap
     below instead. */
  .hero-title {
    flex-direction: row;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.12em;
    font-size: clamp(4rem, 25vw, 7rem);
  }
  .ht-line--right { text-indent: 0; }
  /* The quote wraps into 4 lines on phone widths instead of 3, so the
     desktop watermark size (30vw) — still centered correctly — only
     reaches the middle two lines and reads as "too low" even though
     it's mathematically centered. Sizing it up so it actually spans
     close to the full 4-line block fixes the perception without
     touching the (correct) centering logic. */
  blockquote::before { font-size: 48vw; }
  /* Step-jump dots (01-04 under the carousel) were ~23px tall — well
     under the 44px minimum touch target, and four of them sit right
     next to each other, so mis-taps are likely on a phone. Label
     stays the same visual size; the actual hit area grows. */
  .press-tick {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .hero-sub { flex-direction: column; align-items: flex-start; gap: 1.5rem; }
  .work-grid { grid-template-columns: 1fr; }
  .work-card--wide { grid-column: 1; }
  .step { grid-template-columns: 50px 1fr; gap: 1rem; }
  .step-divider { padding-left: 50px; }
  .footer-inner { flex-direction: column; align-items: flex-start; }
  .nav-overlay { padding: 5rem 1.5rem 2rem; }
  /* Hidden on mobile — tried showing it in-flow, but keeping it
     simple and out of the way instead. */
  .hero-bird { display: none; }
}

/* ── BUSINESS PORTAL PLACEHOLDER (local.html) ─────────────────
   Deliberately lightweight — no preloader, no custom cursor, no
   grain canvas. A "coming soon" page should load instantly and get
   out of the way, not put a visitor through the full site's intro
   sequence for two lines of text. */
.placeholder-page {
  cursor: auto;
  background: var(--ink);
  color: var(--paper);
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  position: relative;
  overflow: hidden;
}
.placeholder-page * { cursor: auto; }

/* ── ANIMATED BACKGROUND (Inquiry Portal) ─────────────────────
   Four thin diagonal lines, staggered speed and delay, sweeping
   continuously — reads as registration guides in motion rather than
   a generic "glitch" effect. Pure CSS: no JS dependency, negligible
   performance cost, and cleanly disabled for reduced-motion. */
.portal-fx {
  position: absolute;
  inset: -10% -10%;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.portal-line {
  position: absolute;
  top: 0;
  left: -20%;
  width: 1px;
  height: 140%;
  background: linear-gradient(180deg, transparent, rgba(187,3,3,0.55) 40%, rgba(187,3,3,0.55) 60%, transparent);
  transform: rotate(18deg);
  animation: portal-sweep linear infinite;
}
.portal-line--1 { left: 5%;  animation-duration: 7s;  animation-delay: 0s;   }
.portal-line--2 { left: 30%; animation-duration: 9.5s; animation-delay: -3s;  opacity: 0.7; }
.portal-line--3 { left: 60%; animation-duration: 6.5s; animation-delay: -1.5s; opacity: 0.5; }
.portal-line--4 { left: 85%; animation-duration: 11s;  animation-delay: -6s;  opacity: 0.8; }

@keyframes portal-sweep {
  0%   { transform: rotate(18deg) translateX(0); }
  100% { transform: rotate(18deg) translateX(-140vw); }
}
@media (prefers-reduced-motion: reduce) {
  .portal-line { animation: none; opacity: 0.25; }
}

.placeholder-wrap {
  position: relative;
  z-index: 1;
  text-align: center;
  max-width: 560px;
}
.placeholder-wrap--wide { max-width: 640px; }

.placeholder-note {
  margin-top: 2rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: rgba(240,237,230,0.5);
}

.placeholder-logo {
  display: inline-block;
  margin-bottom: 3rem;
  font-family: var(--font-disp);
  font-size: 1.6rem;
  letter-spacing: 0.15em;
  color: var(--paper);
}
.placeholder-logo span { color: var(--accent); }

.placeholder-bird {
  height: 120px;
  width: auto;
  margin: 0 auto 2rem;
  opacity: 0.95;
  /* The source art is dark-stroke linework — fine on the light hero
     section elsewhere on the site, but nearly invisible against this
     page's dark background. Inverting flips it to a light outline,
     and the glow gives it presence without needing a second asset. */
  filter: invert(1) drop-shadow(0 0 18px rgba(187,3,3,0.45));
}

.placeholder-page .hero-eyebrow {
  margin-bottom: 1rem;
}

.placeholder-title {
  font-family: var(--font-goth);
  font-size: clamp(2.75rem, 8vw, 5rem);
  line-height: 1.15;
  color: var(--paper);
  margin-bottom: 2.5rem;
}

.placeholder-actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
}
.placeholder-page .btn-raw {
  border-color: var(--paper);
  color: var(--paper);
}
.placeholder-page .btn-raw::before { background: var(--paper); }
.placeholder-page .btn-raw:hover { color: var(--ink); }
.placeholder-page .btn-raw--ghost {
  border-color: rgba(240,237,230,0.3);
  color: rgba(240,237,230,0.7);
}
.placeholder-page .btn-raw--ghost::before { background: rgba(240,237,230,0.7); }
.placeholder-page .btn-raw--ghost:hover { color: var(--ink); }

/* Idle pulse on the primary CTA specifically (not every .btn-raw
   site-wide) — a slow breathing glow so the button feels alive
   before anyone even touches it. */
.btn-raw--pulse {
  animation: btn-pulse 2.4s ease-in-out infinite;
}
@keyframes btn-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(187,3,3,0.5); }
  50%      { box-shadow: 0 0 0 10px rgba(187,3,3,0); }
}
@media (prefers-reduced-motion: reduce) {
  .btn-raw--pulse { animation: none; }
}

@media (max-width: 600px) {
  .placeholder-actions { flex-direction: column; align-items: stretch; }
}

/* ── STORE / BLOG SHARED HERO ─────────────────────────────────
   Reuses the same light-section pattern as the main hero, just
   shorter — these pages don't need the full title treatment. */
.store-hero {
  padding-top: 8rem;
  padding-bottom: 3rem;
}
.store-title {
  font-family: var(--font-disp);
  font-size: clamp(2.75rem, 8vw, 5.5rem);
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--ink);
  margin: 1rem 0 1.25rem;
}
.store-intro {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  line-height: 1.8;
  color: var(--muted);
  max-width: 52ch;
}

/* ── STORE GRID ────────────────────────────────────────────── */
.store-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem 1.5rem;
}
.store-item-media {
  display: block;
  position: relative;
  aspect-ratio: 4/5;
  overflow: hidden;
  background: var(--off);
  margin-bottom: 1rem;
}
.store-item-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: contrast(1.06) saturate(0.88);
  transition: transform 0.6s cubic-bezier(0.16,1,0.3,1);
}
/* For irregular shapes — die-cut stickers, the two-panel tee flatlay —
   where cropping to fill the box would cut off real product detail.
   Letterboxed on the card's own background instead of losing edges. */
.store-item-media--contain img {
  object-fit: contain;
  padding: 1.5rem;
  box-sizing: border-box;
}
.store-item-media:hover img { transform: scale(1.045); }

.store-item-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
}
.store-item-meta h3 {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 400;
  letter-spacing: 0.02em;
}
.store-item-meta h3 a {
  color: var(--paper);
  text-decoration: none;
  border-bottom: 1px solid rgba(240,237,230,0.2);
  transition: border-color 0.2s;
}
.store-item-meta h3 a:hover { border-color: var(--accent); }

/* Price as an actual tag, not plain text — like a real swing tag. */
.store-item-price {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--accent);
  border: 1px solid rgba(187,3,3,0.4);
  padding: 0.2rem 0.55rem;
  white-space: nowrap;
}

/* Halftone + registration mark on the tee photo — same print-shop
   vocabulary as the Work section cards, so Store doesn't feel like a
   different, disconnected part of the site. Not applied to the
   stickers: their own die-cut white border already reads as a
   finished object, and dot texture on top of clean line art would
   just muddy it rather than add anything. */
.store-item-halftone {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(var(--ink) 1px, transparent 1.7px);
  background-size: 8px 8px;
  opacity: 0.05;
  mix-blend-mode: multiply;
  pointer-events: none;
  z-index: 1;
}
.store-item-reg {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  color: var(--accent);
  opacity: 0.6;
  z-index: 2;
  pointer-events: none;
}
.store-item-reg svg { display: block; }

/* Stickers get a slight peel-and-place tilt on hover instead of the
   halftone treatment — a small tactile nod to what they actually are. */
.store-item--sticker .store-item-media--contain img {
  transition: transform 0.4s cubic-bezier(0.34,1.56,0.64,1);
}
.store-item--sticker:nth-child(2) .store-item-media--contain:hover img {
  transform: rotate(-4deg) scale(1.06);
}
.store-item--sticker:nth-child(3) .store-item-media--contain:hover img {
  transform: rotate(4deg) scale(1.06);
}

@media (max-width: 900px) {
  .store-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .store-grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .store-hero { padding-top: 7rem; }
}

/* ── BLOG LIST ─────────────────────────────────────────────── */
.blog-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  max-width: 720px;
}
.blog-list-item {
  padding: 2.5rem 0;
  border-bottom: 1px solid rgba(240,237,230,0.1);
}
.blog-list-date {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.15em;
  color: var(--accent);
  text-transform: uppercase;
}
.blog-list-item h2 {
  font-family: var(--font-disp);
  font-size: clamp(1.75rem, 3.5vw, 2.5rem);
  font-weight: 400;
  letter-spacing: 0.02em;
  margin: 0.6rem 0 0.75rem;
}
.blog-list-item h2 a {
  color: var(--paper);
  text-decoration: none;
  transition: color 0.2s;
}
.blog-list-item h2 a:hover { color: var(--accent); }
.blog-list-item p {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  line-height: 1.8;
  color: rgba(240,237,230,0.6);
  max-width: 55ch;
  margin-bottom: 1rem;
}

/* ── BLOG POST ─────────────────────────────────────────────── */
.blog-back {
  display: inline-block;
  margin-bottom: 2rem;
}
.blog-post-body {
  max-width: 680px;
  font-family: var(--font-mono);
  font-size: 0.95rem;
  line-height: 1.9;
  color: rgba(240,237,230,0.8);
}
.blog-post-body p { margin-bottom: 1.5rem; }
.blog-post-body h2 {
  font-family: var(--font-disp);
  font-size: clamp(1.5rem, 3vw, 2rem);
  letter-spacing: 0.02em;
  color: var(--paper);
  margin: 2.5rem 0 1rem;
}
.blog-post-body img {
  width: 100%;
  margin: 2rem 0;
}

/* ── SOLD-OUT BADGE (Store grid) ─────────────────────────────── */
.store-item-badge {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 3;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  border: 1px solid rgba(240,237,230,0.3);
  padding: 0.3rem 0.6rem;
}
.store-item--soldout .store-item-media img { opacity: 0.55; filter: grayscale(0.4); }
.store-item--soldout .store-item-meta h3 a { color: rgba(240,237,230,0.45); }

/* ── PRODUCT DETAIL PAGE ──────────────────────────────────────── */
.product-back {
  display: inline-block;
  margin-bottom: 2rem;
}
.product-hero { padding-bottom: 2rem; }

.product-layout {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 4rem;
  align-items: start;
}

.product-gallery-main {
  position: relative;
  aspect-ratio: 4/5;
  background: var(--chalk);
  overflow: hidden;
  margin-bottom: 1rem;
}
.product-gallery-main img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 2rem;
  box-sizing: border-box;
}
.product-gallery-thumbs {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.75rem;
}
.product-thumb {
  aspect-ratio: 1;
  background: var(--off);
  overflow: hidden;
}
.product-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 0.5rem;
  box-sizing: border-box;
}
/* Clearly-marked empty slots — not broken images, deliberate space
   for the additional photos still to come. */
.product-thumb--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed rgba(10,10,10,0.25);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
  padding: 0.5rem;
}

.product-info { padding-top: 0.5rem; }
.product-info-title {
  font-family: var(--font-disp);
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--ink);
  margin-bottom: 1rem;
}
.product-info-price {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 1rem;
  letter-spacing: 0.04em;
  color: var(--accent);
  border: 1px solid rgba(187,3,3,0.4);
  padding: 0.3rem 0.7rem;
  margin-bottom: 1.75rem;
}
.product-info-desc {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  line-height: 1.9;
  color: var(--muted);
  max-width: 42ch;
  margin-bottom: 2rem;
}
.product-info-specs {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 2.1;
  color: var(--muted);
  margin-bottom: 2rem;
  border-top: 1px solid rgba(10,10,10,0.12);
  padding-top: 1.25rem;
}
.product-info-specs strong {
  color: var(--ink);
  font-weight: 400;
  display: inline-block;
  min-width: 9ch;
}

.product-soldout-badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  padding: 0.5rem 1rem;
  margin-bottom: 1.5rem;
}
.product-soldout-note {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--muted);
  margin-top: 1rem;
}

@media (max-width: 900px) {
  .product-layout { grid-template-columns: 1fr; gap: 2.5rem; }
}
@media (max-width: 600px) {
  .product-gallery-thumbs { grid-template-columns: repeat(3, 1fr); }
}
