/* ==========================================================================
   Rafael Styles — Design System
   Black #000000 / Gold #D4AF37, editorial red-carpet aesthetic
   ========================================================================== */

:root {
  --black: #000000;
  --black-soft: #0a0a0a;
  --panel: #111111;
  --gold: #D4AF37;
  --gold-bright: #f0cf6b;
  --gold-dim: #8a7226;
  --gold-trim: #B77924; /* sampled from gold_velvet_tray reference; matches the velvet textures */
  --hairline: rgba(183, 121, 36, 0.45);
  --text: #f3efe4;
  --text-muted: #c9c3b3;
  --font-display: "Cormorant Garamond", "Playfair Display", Georgia, serif;
  --font-script: "Tangerine", "Brush Script MT", cursive;
  --font-body: "Jost", "Helvetica Neue", Arial, sans-serif;
  --nav-height: 76px;
  --max-width: 1180px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

body {
  margin: 0;
  background: var(--black);
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 300;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 600; margin: 0 0 0.5em; letter-spacing: 0.02em; }
p { margin: 0 0 1.1em; }
ul { margin: 0; padding: 0; list-style: none; }
button { font-family: inherit; }

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 5vw, 3rem);
}

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

.skip-link {
  position: absolute;
  left: 1rem;
  top: -60px;
  background: var(--gold);
  color: var(--black);
  padding: 0.65em 1.2em;
  z-index: 1000;
  font-family: var(--font-body);
  font-weight: 600;
  text-decoration: none;
  border-radius: 2px;
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 1rem; }

.eyebrow {
  display: block;
  font-family: var(--font-body);
  font-size: 0.72rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.85em;
}

.ornament {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  margin: 1.75rem 0;
  color: var(--gold);
  opacity: 0.85;
}
.ornament::before,
.ornament::after {
  content: "";
  flex: 1 1 60px;
  max-width: 140px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}
.ornament .ornament-glyph { font-size: 1rem; line-height: 1; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.9em 2.1em;
  border: 1px solid var(--gold);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--gold);
  background: transparent;
  cursor: pointer;
  transition: background 0.35s var(--ease), color 0.35s var(--ease), box-shadow 0.35s var(--ease);
  white-space: nowrap;
}
.btn:hover, .btn:focus-visible {
  background: var(--gold);
  color: var(--black);
  box-shadow: 0 0 24px rgba(212, 175, 55, 0.35);
}
.btn-solid {
  background: var(--gold);
  color: var(--black);
}
.btn-solid:hover, .btn-solid:focus-visible {
  background: var(--gold-bright);
  color: var(--black);
}
.btn-block { width: 100%; justify-content: center; }

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

/* ---------- Nav ---------- */
.site-nav {
  position: sticky;
  top: 0;
  z-index: 500;
  height: var(--nav-height);
  display: flex;
  align-items: center;
  background: rgba(0, 0, 0, 0.88);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border-bottom: 1px solid var(--hairline);
}
.site-nav .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  max-width: none;
  padding: 0 clamp(1.25rem, 4vw, 3rem);
}
.nav-brand {
  display: flex;
  flex-direction: column;
  line-height: 1.05;
  text-decoration: none;
  color: var(--text);
}
.nav-brand .brand-name {
  font-family: var(--font-display);
  font-size: 1.55rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  color: var(--gold);
}
.nav-brand .brand-sub {
  font-size: 0.58rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 6px;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  cursor: pointer;
}
.nav-toggle svg { width: 22px; height: 22px; }

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(1.1rem, 2.4vw, 2.4rem);
}
.nav-links a {
  text-decoration: none;
  font-size: 0.76rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text);
  padding: 0.4em 0.1em;
  position: relative;
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -2px;
  height: 1px;
  background: var(--gold);
  transition: right 0.3s var(--ease);
}
.nav-links a:hover::after,
.nav-links a:focus-visible::after,
.nav-links a[aria-current="page"]::after {
  right: 0;
}
.nav-links a[aria-current="page"] { color: var(--gold); }
.nav-links .btn { padding: 0.65em 1.5em; }

@media (max-width: 780px) {
  .nav-toggle { display: inline-flex; }
  .nav-links {
    position: absolute;
    top: var(--nav-height);
    left: 0; right: 0;
    background: rgba(0, 0, 0, 0.97);
    border-bottom: 1px solid var(--hairline);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.5rem clamp(1.25rem, 5vw, 3rem) 1.25rem;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
  }
  .nav-links.is-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .nav-links a {
    display: block;
    width: 100%;
    padding: 0.9em 0;
    border-bottom: 1px solid rgba(212,175,55,0.12);
  }
  .nav-links a::after { bottom: -1px; }
  .nav-links .btn {
    display: inline-flex;
    width: auto;
    margin-top: 0.85em;
    text-align: center;
    justify-content: center;
    border-bottom: none;
  }
}

/* ---------- Fullscreen intro ---------- */
.intro { display: none; }
/* When the inline head script (index.html) has already decided to skip the intro -- already
   seen this visit, or reduced-motion is on -- it never even renders, not even for a frame.
   This has to win over ".js .intro" below regardless of source order, so it repeats that
   selector's specificity exactly (html.no-intro.js beats html.js alone either way, but being
   explicit here keeps this rule's intent obvious rather than relying on cascade position). */
.no-intro .intro { display: none !important; }

.js .intro {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 2rem;
  background: #000000;
  text-align: center;
  cursor: pointer;
  opacity: 1;
  transition: opacity 1s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0s;
}
.js .intro.is-dismissed {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 1s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 1s;
}
/* Crossfade: the intro's contents drift up and swell slightly as the whole screen fades */
.js .intro > * { transition: transform 1.2s var(--ease); }
.js .intro.is-dismissed > * { transform: translateY(-10px) scale(1.035); }
.js .intro.is-dismissed .intro-cue { animation: none; }
.intro-logo {
  /* Full lockup (crest + wordmark + slogan baked into the art), 1490x1674 — taller than the old crest-only mark.
     Bounded on BOTH axes so it scales down cleanly and never overflows a short mobile viewport. */
  display: block;
  width: auto;
  height: auto;
  max-width: min(80vw, 520px);
  max-height: min(58svh, 640px);
}
.intro-tagline { /* same treatment as the sticky nav's .brand-sub */
  font-size: 0.58rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 0.5rem; /* a touch more than the original 0.25rem: the art's own baked-in slogan
    now sits right above it, so this keeps the two from reading as crowded together */
}
.intro-cue {
  margin-top: 2.25rem;
  font-size: 0.68rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--gold-dim);
  animation: intro-cue-pulse 2.6s ease-in-out infinite;
}
.js body.intro-active { overflow: hidden; }
@keyframes intro-cue-pulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }

/* The hero rises into place while the intro fades, so there's no hard cut */
.hero { transition: opacity 1.1s cubic-bezier(0.4, 0, 0.2, 1) 0.25s, transform 1.3s var(--ease) 0.25s; }
.js body.intro-active .hero { opacity: 0; transform: translateY(28px); }

@media (prefers-reduced-motion: reduce) {
  .js .intro { display: none; }
  .js body.intro-active { overflow: auto; }
}

/* ---------- Hero: one full-width living-room photo, nav + welcome text overlaid on top ----------
   Per spec: "The first layout layer revealed is a full-width section displaying my background
   graphic of luxury armchairs... Placed cleanly on top of this section is the brand header and
   its main navigation tabs" + "Sitting cleanly and right next to the living area armchair
   graphics (not stretched borderless across the screen) is my primary introductory text block."
   So: the photo fills the entire section edge-to-edge (no split columns), the nav floats
   transparently over it (see body.is-home .site-nav below), and the welcome text is a bounded
   panel (not full-width) overlaid on the photo itself, not a separate column beside it. */
.hero {
  position: relative;
  min-height: 100vh;
  overflow: hidden;
  background: var(--black);
}
.hero-photo { position: absolute; inset: 0; z-index: 0; }
.hero-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
}
.hero-copy {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  /* Pinning to the bottom (flex-end) of a full 100vh box left a large empty gap above the text,
     since the text block itself is much shorter than the viewport. Centering removes that. */
  justify-content: center;
  min-height: 100vh;
  max-width: 680px;
  /* Shifted right and widened from the original flush-left 560px box, so it reads as sitting
     "next to" the armchair graphics rather than pinned to the very left edge of the screen. */
  margin-left: 8%;
  padding: calc(var(--nav-height) + 3rem) clamp(1.5rem, 5vw, 4.5rem) clamp(2.5rem, 6vw, 4rem);
  /* A gradient scrim, not a flat/heavy overlay filter: it only darkens where the text actually
     sits, leaving the rest of the photo clear — the spec explicitly rules out "heavy dark
     overlay filters that wash out graphic details". Vignette-shaped (dark in the middle, clear
     top and bottom) since the text is now vertically centered, not pinned to the bottom. */
  background: linear-gradient(180deg, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.6) 30%, rgba(0,0,0,0.65) 70%, rgba(0,0,0,0.25) 100%);
}
.hero-copy h1 {
  font-size: clamp(2.1rem, 4.2vw, 3.4rem);
  color: var(--gold);
  line-height: 1.1;
  margin-bottom: 0.6em;
}
.hero-copy p { color: var(--text-muted); font-size: 1.02rem; }
.hero-copy p:last-of-type { color: var(--text); margin-bottom: 0; }

/* Fine metallic gold hairline framing any two-block split against black (still used by
   .about-grid.split-frame on about.html; unrelated to the hero now). */
.split-frame {
  border-top: 1px solid var(--gold-trim);
  border-bottom: 1px solid var(--gold-trim);
}
.split-frame > * + * { border-left: 1px solid var(--gold-trim); }

@media (max-width: 900px) {
  .hero, .hero-copy { min-height: 100vh; }
  .hero-copy {
    /* Horizontally centered in the frame -- not shifted to one side -- with a cap on width so
       it reads as a centered column rather than stretching edge to edge. */
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
    text-align: center;
    /* Desktop pins the text to the bottom (flex-end), which works there because the box is
       much wider so the text block itself is short. On a narrow phone the same 3 paragraphs
       wrap into a much taller block, and flex-end was pushing most of it down past the bottom
       of the screen. Centering keeps it fully in view instead. */
    justify-content: center;
    /* The bottom-weighted scrim above is tuned for text pinned at the bottom (the desktop
       layout) -- with the text now vertically centered on mobile, that gradient left the
       heading sitting in its barely-darkened top band, right over the brightest part of the
       photo. This vignette instead darkens where the now-centered text actually is. */
    background: linear-gradient(180deg, rgba(0,0,0,0.25) 0%, rgba(0,0,0,0.6) 30%, rgba(0,0,0,0.65) 75%, rgba(0,0,0,0.3) 100%);
  }
}

/* ---------- Every page: nav starts transparent (a soft dark gradient, not solid) at the very
   top, then becomes the normal solid bar once scrolled down a bit (toggled via .is-solid, see
   main.js). Applied site-wide, not just the homepage, so the nav behaves identically everywhere
   -- on the homepage that means it floats over the living-room photo as the client described;
   on the other pages, the top section is already solid black, so the "transparent" state just
   blends into that rather than revealing a photo, but the interaction stays consistent. ---------- */
.site-nav {
  position: absolute;
  top: 0; left: 0; right: 0;
  /* Fully transparent made the gold/white nav text unreadable against a busy photo behind it --
     a soft dark gradient (fading to nothing by the bottom of the nav) keeps whatever's behind it
     visible while still giving the text enough contrast to read. */
  background: linear-gradient(to bottom, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.15) 100%);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom-color: transparent;
  transition: background 0.35s var(--ease), backdrop-filter 0.35s var(--ease), border-color 0.35s var(--ease);
}
.site-nav.is-solid {
  position: fixed;
  background: rgba(0, 0, 0, 0.88);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border-bottom-color: var(--hairline);
}

.placeholder-slot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  border: 1px dashed var(--hairline);
  border-radius: 4px;
  background:
    repeating-linear-gradient(135deg, rgba(212,175,55,0.05) 0 2px, transparent 2px 14px),
    linear-gradient(160deg, #121212, #050505);
  color: var(--gold-dim);
  overflow: hidden;
}
.placeholder-slot .placeholder-label {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  padding: 1.5rem;
  font-family: var(--font-body);
}
.placeholder-slot .placeholder-icon {
  width: 34px; height: 34px;
  opacity: 0.8;
}
.placeholder-slot .placeholder-title {
  font-family: var(--font-display);
  font-size: 1rem;
  letter-spacing: 0.05em;
  color: var(--gold);
}
.placeholder-slot .placeholder-dims {
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ---------- Section shells ---------- */
.section {
  padding: clamp(3.5rem, 8vw, 6.5rem) 0;
  position: relative;
}
.section-black { background: var(--black); }
.section-panel { background: var(--black-soft); border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }
/* A section-black that's a direct child of .fabric-veil must not paint its own opaque black,
   or it hides the wrapper's texture behind it entirely (the two sections sit flush with no
   gap between them). This only fires when .fabric-veil is wrapping sections rather than being
   applied directly to a single element (the about.html bio, the lookbook.html header). */
.fabric-veil > .section-black { background: none; }
/* Fabric texture, applied via this standalone class so every plain section-black/other surface
   stays untouched. Painted once on the .fabric-veil element itself, so where it wraps multiple
   sections (the About Teaser + Lookbook Menu intro on index.html) the diagonal fold pattern
   runs continuously across their combined height instead of each section re-covering its own
   height independently and breaking the pattern at the seam. Also used directly on a single
   element with both classes: the bio section on about.html, and the lookbook.html page header. */
.fabric-veil {
  position: relative;
  background:
    linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)),
    url("../assets/fabric-velvet-drapery.jpg") center / cover no-repeat,
    var(--black);
}
/* Client spec: "my original metallic gold dust sprays [must be] clearly visible at their three
   specific spots" -- the delivered fabric texture (fabric-velvet-drapery.jpg) is plain black
   satin with no gold in it at all, so that detail was simply missing from all three sections
   that use it. Added here as a CSS effect (a scattering of small soft gold specks) rather than
   a new image asset, since no such gold-dust photo was ever actually provided. */
.fabric-veil::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* Each speck is a bright metallic core plus a soft glow halo at the same spot, so it reads as
     an actual glinting gold particle against the dark fabric rather than a faint flat dot.
     Sized and brightened up to read clearly as a "spray" at a normal glance, not just on
     close inspection. */
  background-image:
    radial-gradient(10px 10px at 18% 22%, rgba(240,207,107,0.55), transparent 70%),
    radial-gradient(3px 3px at 18% 22%, #fef0c0, transparent 80%),
    radial-gradient(9px 9px at 78% 32%, rgba(240,207,107,0.5), transparent 70%),
    radial-gradient(2.8px 2.8px at 78% 32%, #fef0c0, transparent 80%),
    radial-gradient(9px 9px at 30% 58%, rgba(212,175,55,0.5), transparent 70%),
    radial-gradient(2.8px 2.8px at 30% 58%, #f6dc8a, transparent 80%),
    radial-gradient(9px 9px at 88% 78%, rgba(240,207,107,0.48), transparent 70%),
    radial-gradient(2.8px 2.8px at 88% 78%, #fef0c0, transparent 80%),
    radial-gradient(8px 8px at 12% 82%, rgba(212,175,55,0.46), transparent 70%),
    radial-gradient(2.4px 2.4px at 12% 82%, #f6dc8a, transparent 80%),
    radial-gradient(8px 8px at 55% 14%, rgba(240,207,107,0.46), transparent 70%),
    radial-gradient(2.4px 2.4px at 55% 14%, #fef0c0, transparent 80%);
  background-repeat: no-repeat;
}
/* Keeps the real content (headings, text, portraits) painting above the gold-dust layer -- a
   positioned pseudo-element otherwise paints above plain static content regardless of z-index
   value, the same stacking rule already handled for the lookbook curtain and footer elsewhere
   in this file. */
.fabric-veil > * { position: relative; z-index: 1; }

.section-head {
  max-width: 720px;
  margin: 0 auto 3rem;
  text-align: center;
}
.section-head h2 {
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  color: var(--gold);
}
.section-head .lede { color: var(--text-muted); font-size: 1.02rem; }

/* ---------- About ---------- */
.about-grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
.about-grid.split-frame { gap: 0; border: 1px solid var(--gold-trim); align-items: stretch; }
.about-grid.split-frame > * + * { border-left: 1px solid var(--gold-trim); }
.about-grid.split-frame .about-body { padding: clamp(1.5rem, 4vw, 3rem); }
.about-portrait.placeholder-slot { aspect-ratio: 3 / 4; border: 0; border-radius: 0; }
.about-body h3 { color: var(--gold); font-size: clamp(1.4rem, 3vw, 1.9rem); }
.about-body p { color: var(--text-muted); }
.about-note {
  margin-top: 2rem;
  padding: 1.4rem 1.6rem;
  border-left: 2px solid var(--gold);
  background: rgba(212, 175, 55, 0.05);
}
.about-note strong { color: var(--gold); display: block; margin-bottom: 0.4em; font-family: var(--font-display); font-size: 1.05rem; }
.about-note a { color: var(--gold); text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 860px) {
  .about-grid { grid-template-columns: 1fr; }
  .about-portrait.placeholder-slot { aspect-ratio: 16 / 10; }
  .about-grid.split-frame > * + * { border-left: 0; border-top: 1px solid var(--gold-trim); }
}

/* ---------- Lookbook ---------- */
.lookbook-hero {
  position: relative;
  z-index: 1; /* same reason as .site-footer below: stay above the fixed curtain layer */
  padding: calc(var(--nav-height) + 3rem) 0 2.5rem;
  text-align: center;
  border-bottom: 1px solid var(--hairline);
}
.lookbook-hero h1 { color: var(--gold); font-size: clamp(2rem, 5vw, 3rem); }
.lookbook-hero .lede { max-width: 620px; margin: 0 auto; color: var(--text-muted); }

.parallax-stage {
  position: relative;
  overflow: hidden;
}
.parallax-layer {
  position: absolute;
  inset: -10% -5%;
  z-index: 0;
  pointer-events: none;
  will-change: transform;
}
/* The gold drape (.layer-far) must read as completely still behind the scrolling text/cards,
   on EVERY device including iPhone. `background-attachment: fixed` cannot be trusted for that:
   iOS Safari (and anything else running the iOS WebKit engine, so this includes Chrome/Firefox
   on iPhone too) has never reliably supported it — the background ends up scrolling along with
   the page instead of staying put, which is exactly the "curtain is moving" bug this fixes.
   The old mobile fallback (a slow JS-driven translate3d "drift") avoided that specific bug but
   wasn't actually still either — it drifted at 6% of scroll speed, which doesn't satisfy the
   client's explicit "must stand completely still" requirement.
   Fix: make .layer-far a real `position: fixed` element pinned to the viewport at every width,
   instead of an absolutely-positioned part of the (very tall) scrolling .parallax-stage. A fixed
   element simply never moves, on any browser — no background-attachment trick, no scroll-linked
   JS needed. It sits at z-index 0, behind the actual page content (.category-block is z-index 1),
   and outside this parallax-stage section it's naturally covered by the opaque black sections
   before/after it, so it only ever shows through here. */
/* The client's spec for this texture is explicit: "Absolutely no repeating tile grid patterns,
   blurry stretching, or dark filters." The old rule broke all three — it tiled a small image in
   a repeating grid, upscaled that same small image past its native resolution (blurry on mobile),
   and mixed a black linear-gradient straight into the background (a dark filter over the whole
   texture). Fixed by using ONE real high-resolution photo (gold-satin-drape.jpg, 1264x1264) at
   every screen width, shown with `cover` + `no-repeat` so it fills the screen as a single clean
   image with no tiling and no upscaling blur, and with no gradient/overlay mixed into it. */
.parallax-layer.layer-far {
  position: fixed;
  inset: 0;
  background: url("../assets/gold-satin-drape.jpg") center / cover no-repeat;
}
@media (min-width: 901px) {
  /* Legibility now lives here, not in the backdrop overlay above: a soft scrim scoped to each
     category's own heading block, so it scrolls with the text and always sits behind it no
     matter which part of the (fixed-attachment) fabric happens to be showing through at the time. */
  .category-head {
    position: relative;
    z-index: 0; /* own stacking context, keeps the scrim scoped to just this block */
  }
  .category-head::before {
    content: "";
    position: absolute;
    inset: -1.75rem -3rem;
    z-index: -1;
    background: radial-gradient(ellipse 60% 78% at 50% 50%, rgba(0,0,0,0.62) 0%, rgba(0,0,0,0.62) 38%, transparent 78%);
    pointer-events: none;
  }
}
.parallax-layer.layer-near {
  background:
    radial-gradient(ellipse 55% 40% at 20% 15%, rgba(240,207,107,0.10), transparent 65%),
    radial-gradient(ellipse 50% 40% at 80% 80%, rgba(240,207,107,0.08), transparent 65%);
}

.category-block {
  position: relative;
  z-index: 1;
  padding: clamp(2.5rem, 6vw, 4rem) 0;
}
.category-block + .category-block { border-top: 1px solid var(--hairline); }
.category-head { text-align: center; max-width: 680px; margin: 0 auto 2.5rem; }
.category-head .eyebrow { text-align: center; }
.category-head h2 { color: var(--gold); font-size: clamp(1.6rem, 3.6vw, 2.2rem); }
.category-head p { color: var(--text-muted); font-size: 0.95rem; }

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1.75rem;
}

.lookbook-card {
  background: linear-gradient(180deg, rgba(212,175,55,0.04), transparent 30%), var(--panel);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease), border-color 0.4s var(--ease);
}
.lookbook-card:hover {
  transform: translateY(-6px);
  border-color: var(--gold);
  box-shadow: 0 18px 40px rgba(0,0,0,0.5);
}
.lookbook-card .card-photo.placeholder-slot { aspect-ratio: 4 / 5; border-radius: 0; border-width: 0 0 1px 0; }
.lookbook-card .card-photo:not(.placeholder-slot) { aspect-ratio: 4 / 5; overflow: hidden; border-bottom: 1px solid var(--hairline); background: #000; }
.lookbook-card .card-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }

.lookbook-card .card-photo { position: relative; }

.lookbook-card .card-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0; /* off by default (mobile grid, and desktop before JS marks a card centered) —
    only the desktop carousel's non-centered cards switch this on, below */
  transition: opacity 0.4s var(--ease);
  pointer-events: none;
}
.lookbook-card .card-body { padding: 1.4rem 1.5rem 1.7rem; display: flex; flex-direction: column; flex: 1; }
.lookbook-card h3 {
  font-size: 1.2rem;
  color: var(--text);
  margin-bottom: 0.55em;
}
.lookbook-card .card-dek {
  font-size: 0.82rem;
  color: var(--gold-dim);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin-bottom: 0.9em;
}

/* Accordion */
.accordion-item { border-top: 1px solid rgba(212,175,55,0.18); margin-top: auto; }
.accordion-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: none;
  border: 0;
  color: var(--gold);
  padding: 0.9em 0 0.7em;
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  text-align: left;
}
.accordion-trigger .chevron {
  flex-shrink: 0;
  width: 11px; height: 11px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.35s var(--ease);
}
.accordion-trigger[aria-expanded="true"] .chevron { transform: rotate(-135deg); }

/* Below 901px the lookbook cards are a plain stacked grid, not the desktop carousel — there's
   no "centered card" for the description to auto-open on, so instead of a collapsed-by-default
   accordion behind a click, the description is just always visible here, same "no click needed"
   principle as the flip-book pages. The desktop carousel (>=901px) keeps the click-to-expand
   accordion, since there every non-centered card collapsing is what makes the centered one's
   auto-open meaningful. */
@media (max-width: 900px) {
  .lookbook-card .accordion-trigger { display: none; }
  .lookbook-card .accordion-panel {
    max-height: none !important;
    overflow: visible;
  }
}

.accordion-panel {
  overflow: hidden;
  max-height: 0;
  transition: max-height 0.45s var(--ease);
}
.accordion-panel[data-open="true"] { }
.accordion-panel .accordion-panel-inner {
  padding: 0 0 1.2rem;
  color: var(--text-muted);
  font-size: 0.93rem;
}
.accordion-panel .badge {
  display: inline-block;
  margin-top: 0.7em;
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--black);
  background: var(--gold);
  padding: 0.35em 0.7em;
  border-radius: 999px;
}

.card-reserve {
  margin-top: 1.1rem;
  align-self: flex-start;
}

@media (prefers-reduced-motion: reduce) {
  .lookbook-card:hover { transform: none; }
}

/* ---------- Policies ---------- */
.policy-hero {
  padding: calc(var(--nav-height) + 3rem) 0 1rem;
  text-align: center;
}
.policy-hero h1 { color: var(--gold); font-size: clamp(2rem, 5vw, 2.8rem); }
.policy-hero .lede { max-width: 640px; margin: 0 auto; color: var(--text-muted); }

.policy-doc {
  max-width: 820px;
  margin: 0 auto;
  padding: 1rem 0 2rem;
}
.policy-doc h2 {
  color: var(--gold);
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  margin-top: 2.4em;
  padding-bottom: 0.5em;
  border-bottom: 1px solid var(--hairline);
}
.policy-doc h2:first-child { margin-top: 0; }
.policy-doc p { color: var(--text-muted); font-size: 0.97rem; }
.policy-region {
  font-family: var(--font-display);
  font-size: 1.3rem;
  color: var(--text);
  text-align: center;
  margin-bottom: 0.3em;
}
.policy-region-sub { text-align: center; color: var(--text-muted); margin-bottom: 2.5rem; }

/* ---------- Footer ---------- */
.site-footer {
  position: relative;
  z-index: 1; /* Must paint above the lookbook page's fixed gold-curtain layer (z-index: 0),
    or the curtain — which is pinned to the viewport and never scrolls away — visually covers
    the footer once scrolled into view, since a positioned z-index:0 element otherwise paints
    above plain non-positioned content regardless of DOM order. */
  border-top: 1px solid var(--hairline);
  background: var(--black-soft);
  padding: 3.5rem 0 2.5rem;
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr 1fr;
  gap: 2.5rem;
  margin-bottom: 2.5rem;
}
.footer-brand .brand-name {
  font-family: var(--font-display);
  color: var(--gold);
  font-size: 1.5rem;
  letter-spacing: 0.06em;
}
.footer-brand p { color: var(--text-muted); font-size: 0.9rem; margin-top: 0.75em; }
.footer-col h4 {
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 1em;
}
.footer-col ul li { margin-bottom: 0.7em; }
.footer-col a {
  text-decoration: none;
  color: var(--text-muted);
  font-size: 0.92rem;
}
.footer-col a:hover, .footer-col a:focus-visible { color: var(--gold); }
/* Client asked for "clean, minimal icon links" for Instagram/Facebook/email; these were plain
   text with no icon at all. Small inline icons added (matching the site's own hand-drawn SVG
   style used elsewhere — the nav toggle and carousel arrows — rather than pulling in an icon
   font/library for just three glyphs). */
.footer-col a.social-link { display: inline-flex; align-items: center; gap: 0.6em; }
.footer-col a.social-link svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--gold-dim); transition: color 0.25s var(--ease); }
.footer-col a.social-link:hover svg, .footer-col a.social-link:focus-visible svg { color: var(--gold); }
.footer-bottom {
  border-top: 1px solid var(--hairline);
  padding-top: 1.6rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  justify-content: space-between;
  font-size: 0.78rem;
  color: var(--text-muted);
}
.footer-bottom a { color: var(--text-muted); text-decoration: underline; text-underline-offset: 3px; }
.footer-bottom a:hover, .footer-bottom a:focus-visible { color: var(--gold); }

@media (max-width: 780px) {
  .footer-grid { grid-template-columns: 1fr; gap: 2rem; }
}


/* ---------- Lookbook carousel (desktop) ---------- */
.carousel-controls { display: none; }
@media (min-width: 901px) {
  .card-grid {
    display: flex;
    gap: 2rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    align-items: flex-start;
    /* Reserves enough row height for the tallest card with its description open (measured
       across all 15 service cards at this 380px card width: tallest is 835px), so switching
       which card is centered -- which opens/closes that card's accordion -- never changes the
       row's own height. Without this, the arrows (positioned at 50% of this row's height) and
       everything below on the page (other categories, the scheduling note, the footer) would
       visibly shift up/down every time a different card centers. Same fix philosophy as the
       flip-book's fixed --book-track-h frame above, for the same class of bug. */
    min-height: 850px;
    /* Horizontal edge padding (letting the first/last card reach dead-center) is set by
       main.js's setEdgePadding() instead of a fixed calc() here. This track intentionally
       bleeds past .container via the negative margin below, so its real rendered width isn't
       the same box a CSS percentage would resolve against -- a fixed `calc(50%-190px)` guess
       left both edge cards sitting ~48px permanently off-center (confirmed in real-browser
       testing). Measuring the actual track/card widths at runtime removes that guesswork. */
    padding: 0.5rem 0 2rem;
    margin: 0 calc(-1 * clamp(1.25rem, 5vw, 3rem));
    scrollbar-width: none;
    cursor: grab;
    -webkit-overflow-scrolling: touch;
  }
  .card-grid::-webkit-scrollbar { display: none; }
  .card-grid.is-dragging { cursor: grabbing; scroll-snap-type: none; scroll-behavior: auto; }
  .card-grid.is-dragging * { user-select: none; }
  .card-grid .lookbook-card {
    flex: 0 0 380px;
    /* Fixed, not min-height on the row: every card -- centered or not, accordion open or
       closed -- always occupies exactly this much vertical space. Sized to comfortably fit the
       tallest real card's photo + full text + open description (measured at 835px for the
       longest one). A row-level min-height was tried first but the carousel's centering/scale
       transform interacted with it in a way that still let the row grow by ~24px when a
       different card centered -- still shifting the arrows and everything below. Fixing each
       card's own height directly removes that dynamic entirely: there is no "tallest content
       wins" calculation left to go wrong. */
    height: 850px;
    scroll-snap-align: center;
    transform: scale(0.94);
    transition: transform 0.4s var(--ease), border-color 0.4s var(--ease), box-shadow 0.4s var(--ease);
  }
  .card-grid .lookbook-card.is-centered { transform: none; border-color: var(--gold); }
  .card-grid .lookbook-card:not(.is-centered) .card-photo::after { opacity: 1; }
  .card-grid .lookbook-card:hover { transform: none; }
  .card-grid .lookbook-card:not(.is-centered):hover { transform: scale(0.94); }
  .card-grid .lookbook-card.is-centered:hover { box-shadow: 0 18px 40px rgba(0,0,0,0.5); }

  .carousel-wrap { position: relative; }
  .carousel-controls { display: block; }
  .carousel-btn {
    position: absolute;
    z-index: 5;
    top: calc(50% - 0.75rem); /* track padding is 0.5rem top / 2rem bottom */
    margin-top: -23px;
    width: 46px; height: 46px;
    border-radius: 50%;
    border: 1px solid var(--gold);
    background: rgba(0,0,0,0.6);
    color: var(--gold);
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 0.3s var(--ease), color 0.3s var(--ease);
  }
  .carousel-btn[data-dir="-1"] { left: calc(50% - 190px - 72px); }
  .carousel-btn[data-dir="1"] { right: calc(50% - 190px - 72px); }
  .carousel-btn:hover, .carousel-btn:focus-visible { background: var(--gold); color: var(--black); }
  .carousel-btn svg { width: 18px; height: 18px; }
}
@media (min-width: 901px) and (prefers-reduced-motion: reduce) {
  .card-grid { scroll-behavior: auto; }
  .card-grid .lookbook-card { transition: none; }
}

/* ---------- Scheduling note (standalone) ---------- */
.scheduling-section { position: relative; z-index: 1; padding: clamp(2.5rem, 6vw, 4rem) 0; }
.scheduling-section .about-note { max-width: 820px; margin: 0 auto; }
.scheduling-section .about-note p { color: var(--text-muted); margin-bottom: 0; }

/* ---------- Flip-book ---------- */
.flipbook { position: relative; display: flex; justify-content: center; min-height: 460px; }
.flipbook-cta { text-align: center; margin-top: clamp(1.5rem, 4vw, 2.5rem); }

/* Closed: dark cover, tilted, coloured back cover peeking out, resting shadow */
.book-cover {
  position: relative;
  display: block;
  width: min(78vw, 340px);
  aspect-ratio: 3 / 4;
  margin: 1.5rem 0 3.25rem;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  perspective: 900px;
  transition: transform 0.4s var(--ease);
}
.book-cover:hover { transform: translateY(-4px); }
.book-back, .book-front { position: absolute; inset: 0; border-radius: 4px 8px 8px 4px; }
.book-back {
  background: linear-gradient(135deg, #7a1420, #3d0810);
  transform: rotate(5deg) translate(16px, 6px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.6);
}
.book-front {
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(ellipse at 30% 20%, rgba(255,255,255,0.07), transparent 55%),
    linear-gradient(145deg, #1b1512, #050403);
  border: 1px solid rgba(212,175,55,0.35);
  box-shadow: inset 0 0 0 7px #0a0807, inset 0 0 0 8px rgba(212,175,55,0.5), -6px 0 0 -1px #000, 0 20px 30px rgba(0,0,0,0.55);
  transform: rotate(-4deg);
}
.book-front { overflow: hidden; }
.book-front img { width: 122%; max-width: none; height: auto; mix-blend-mode: screen; /* PNG has an opaque black ground */ }
.book-corner {
  position: absolute; width: 22px; height: 22px;
  border: 0 solid var(--gold);
}
.book-corner.tl { top: 14px; left: 14px; border-top-width: 2px; border-left-width: 2px; }
.book-corner.tr { top: 14px; right: 14px; border-top-width: 2px; border-right-width: 2px; }
.book-corner.bl { bottom: 14px; left: 14px; border-bottom-width: 2px; border-left-width: 2px; }
.book-corner.br { bottom: 14px; right: 14px; border-bottom-width: 2px; border-right-width: 2px; }
.book-shadow {
  position: absolute;
  left: 6%; right: -4%; bottom: -26px; height: 32px;
  background: radial-gradient(ellipse at center, rgba(0,0,0,0.75), transparent 70%);
  filter: blur(6px);
}
.book-cue {
  position: absolute;
  left: 50%; bottom: -3.4rem;
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 0.45em 1.1em;
  background: rgba(0,0,0,0.7);
  border: 1px solid var(--gold-trim);
  border-radius: 999px;
  text-align: center;
  font-size: 0.72rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold);
}

/* Open: magazine-style reading view */
.book-reader {
  width: min(100%, 560px);
  background: rgba(0,0,0,0.88);
  border: 1px solid var(--gold-trim);
  border-radius: 4px;
  padding: clamp(1.25rem, 4vw, 2rem);
  box-shadow: 0 24px 60px rgba(0,0,0,0.6);
}
.book-reader:not([hidden]) { animation: book-open 0.5s var(--ease) both; }
@keyframes book-open { from { opacity: 0; transform: scale(0.94) translateY(14px); } to { opacity: 1; transform: none; } }
.book-masthead { text-align: center; padding-bottom: 1.1rem; margin-bottom: 1.1rem; border-bottom: 1px solid var(--hairline); }
.masthead-name {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.9rem, 6vw, 2.7rem);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold);
  line-height: 1.05;
}
.masthead-sub {
  display: block;
  margin-top: 0.4em;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.05rem;
  color: var(--text-muted);
}
.page-counter {
  position: absolute;
  z-index: 5;
  font-family: var(--font-body);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold-bright);
  background: rgba(0,0,0,0.7);
  padding: 0.35em 0.75em;
  border-radius: 999px;
  top: 0.75rem; left: 0.75rem;
}

/* ---------- Book pages: two templates, turning on a 3D hinge in a shared track ---------- */
.book-spread {
  position: relative;
  perspective: 1500px;
  -webkit-perspective: 1500px;
}
.book-track {
  /* Fixed per breakpoint (mobile override below) instead of auto/min-height, so the frame
     itself never resizes as pages turn or an accordion opens/closes — only the tallest
     realistic state (a content page with its longest description expanded) is what it needs
     to fit; every shorter page just sits centered inside it (see justify-content below).
     --book-track-h was measured empirically: true max natural page height (photo + copy +
     open accordion, including the three two-paragraph "note" pages — Tailored Bespoke
     Accents, Bespoke Tress Liberation, Extended Care) across 320/390/501/560/600/768/900px
     (mobile) and 901/1024/1280/1920px (desktop) topped out at 511px mobile / 517px desktop;
     these values give a ~60-80px comfortable margin above that measured max. */
  --book-track-h: 640px;
  --book-track-pad-top: 2.5rem; /* clears the page-counter pill floating above */
  position: relative;
  overflow: hidden;
  height: var(--book-track-h);
  padding-top: var(--book-track-pad-top);
  display: flex;
  flex-direction: column;
  /* flex-start (not center): centering recalculated per page based on that page's own natural
     height, so the photo/title visibly shifted up or down every time you moved Prev/Next
     between pages of different heights — the "section adjusts itself" complaint, even though
     the outer frame itself had already stopped resizing. Content-template pages now anchor to
     a constant top position (flush after the page-counter padding) and stay at their natural
     height, so any leftover frame space appears below them, never above, and the photo never
     moves. Divider-template pages opt back into a centered look via their own explicit height
     below (data-template="divider"), which fills the whole frame so their EXISTING internal
     centering (already flex/justify-content: center on that rule) has the full frame to center
     within — a deliberate, book-like title-page treatment, distinct from photo pages on
     purpose. align-items: stretch (the default) keeps .book-unit at its full block width,
     preserving each template's own internal layout untouched. */
  justify-content: flex-start;
}
.book-unit[hidden] { display: none; }
/* Safety net: if any page's content somehow exceeds the fixed frame (an unusually long future
   description, extreme browser zoom, etc.), it scrolls internally instead of clipping or
   growing the frame. calc() (not a % max-height) so it resolves identically for the normal-flow
   resting page and the position: absolute is-turning/is-under pages below. */
.book-unit {
  max-height: calc(var(--book-track-h) - var(--book-track-pad-top));
  overflow-y: auto;
}

/* The page underneath: sits flat, no rotation, revealed once the turning page's
   backface hides past 90°. */
.book-unit.is-under,
.book-unit.is-turning {
  background: #0a0705; /* opaque "paper" — without this the stacked layer beneath shows through
    in every gap between glyphs, since both sit at the exact same position during the turn */
}
/* is-under/is-turning are position: absolute, so they're removed from the flex flow above and
   would otherwise anchor to the track's padding-box top edge (i.e. under the counter pill,
   top-pinned) regardless of the resting page's position — a visible vertical snap right as a
   turn starts/ends. top: var(--book-track-pad-top) (instead of relying on the ancestor's
   padding, which absolute children don't get pushed by) puts them at the exact same top offset
   #book-track's flex-start already rests content-template pages at, and height is left auto —
   so a content page lands at the same Y turning as it does resting, no jump. Divider-template
   pages get their own explicit height (see data-template="divider" below) that applies
   regardless of is-under/is-turning, so they still fill the whole frame and center internally
   the same way turning as resting. */
.book-unit.is-under {
  position: absolute;
  top: var(--book-track-pad-top); left: 0; right: 0;
  z-index: 1;
}

/* The page actually turning. Forward hinges on its LEFT edge (spine), rotating away from
   0deg to -180deg; backward hinges on the RIGHT edge, unfolding from 180deg back to 0deg —
   a mirrored motion rather than the same animation reversed, so it reads as "undoing" a turn
   rather than a different effect. backface-visibility hides the mirrored/blank reverse of the
   page through the invisible 90deg-270deg arc, which is what reveals .is-under beneath it. */
.book-unit.is-turning {
  position: absolute;
  top: var(--book-track-pad-top); left: 0; right: 0;
  z-index: 2;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55);
}
.book-unit.is-turning::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
}
.book-unit.is-turning.turn-fwd {
  transform-origin: left center;
  animation: book-turn-fwd 0.75s cubic-bezier(0.45, 0, 0.55, 1) forwards;
}
.book-unit.is-turning.turn-fwd::after {
  /* Darkest right at the spine, fading toward the free edge — a fold shadow, not a flat tint. */
  background:
    linear-gradient(to right, rgba(0,0,0,0.62) 0%, rgba(0,0,0,0.2) 30%, transparent 58%),
    linear-gradient(to right, rgba(212,175,55,0.2) 0%, transparent 7%);
  animation: book-turn-shadow 0.75s cubic-bezier(0.45, 0, 0.55, 1) forwards;
}
.book-unit.is-turning.turn-back {
  transform-origin: right center;
  animation: book-turn-back 0.75s cubic-bezier(0.45, 0, 0.55, 1) forwards;
}
.book-unit.is-turning.turn-back::after {
  background:
    linear-gradient(to left, rgba(0,0,0,0.62) 0%, rgba(0,0,0,0.2) 30%, transparent 58%),
    linear-gradient(to left, rgba(212,175,55,0.2) 0%, transparent 7%);
  animation: book-turn-shadow 0.75s cubic-bezier(0.45, 0, 0.55, 1) forwards;
}
@keyframes book-turn-fwd {
  from { transform: rotateY(0deg); }
  to   { transform: rotateY(-180deg); }
}
@keyframes book-turn-back {
  from { transform: rotateY(180deg); }
  to   { transform: rotateY(0deg); }
}
@keyframes book-turn-shadow {
  0%, 100% { opacity: 0; }
  45%, 55% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .book-unit.is-turning.turn-fwd,
  .book-unit.is-turning.turn-back {
    animation: none;
    transform: none;
    box-shadow: none;
  }
  .book-unit.is-turning.turn-fwd::after,
  .book-unit.is-turning.turn-back::after {
    animation: none;
    opacity: 0;
  }
}

/* Content template: real service photo + copy, same visual weight as the old single layout */
.book-unit-photo { aspect-ratio: 3 / 2; overflow: hidden; border-radius: 2px; border: 1px solid var(--hairline); margin-bottom: 1.1rem; background: #000; }
.book-unit-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 22%; }
.book-unit-copy .unit-dek {
  display: block;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold-dim);
  margin-bottom: 0.5em;
}
.book-unit-copy h3 { color: var(--gold); font-size: clamp(1.3rem, 3.6vw, 1.6rem); margin-bottom: 0.4em; }
.book-unit-copy p { color: var(--text-muted); font-size: 0.92rem; margin-bottom: 0.85em; }
.book-unit-copy p:last-child { margin-bottom: 0; }

/* Client requirement: the description must be "unhidden on the bottom" and must appear as an
   "organic accordion-style sliding text drop... without requiring the user to click a rigid
   down-arrow link button." So .book-page-copy is just plain visible text (no click-to-expand,
   no collapsed state) — the "accordion-style sliding drop" is instead a one-shot entrance
   animation replayed automatically by main.js (playTextDrop) every time a page becomes current,
   not a toggle the visitor has to operate. */
.book-page-copy.is-revealing { animation: book-text-drop 0.6s var(--ease); }
@keyframes book-text-drop {
  from { opacity: 0; transform: translateY(-14px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Divider template: intro / category dividers / closing page — section-head styling, no photo.
   :not([hidden]) keeps this from fighting .book-unit[hidden]{display:none} above — same
   specificity, so without it, a hidden divider page would still render as a flex box. */
.book-unit[data-template="divider"]:not([hidden]) {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  min-height: 13rem;
  /* #book-track is flex-start now (see above), so without an explicit height a divider page
     would just sit at its own short natural height like a content page — this is what still
     gives divider pages the full frame to center within, keeping their existing "title page
     centered in the middle" look. Applies to this selector regardless of is-turning/is-under
     state (unaffected by :not([hidden]) — that class combo is never hidden while turning). */
  height: calc(var(--book-track-h) - var(--book-track-pad-top));
}
.book-unit[data-template="divider"] h3 { color: var(--gold); font-size: clamp(1.5rem, 4vw, 2rem); margin-bottom: 0; }
.book-unit[data-template="divider"] .ornament { margin: 1.1rem 0; }
.book-unit[data-template="divider"] .book-page-lede { max-width: 30rem; }
.book-unit[data-template="divider"] .book-page-lede + p { color: var(--text-muted); margin-bottom: 0; } /* the closing page's second line only — single-paragraph dividers are unaffected */
.book-unit[data-template="divider"].closing .book-page-lede { margin-bottom: 0.5em; }
.book-unit[data-template="divider"].closing .btn { margin-top: 1.4rem; }

.gold-rule { display: block; width: 64px; height: 1px; background: var(--gold); margin: 0 0 1rem; }
.book-page-lede { font-family: var(--font-display); font-size: 1.15rem; font-style: italic; color: var(--text); }

/* Footer nav row: explicit Prev/Next + a "PAGE 01 / 20" counter, the primary visible navigation
   alongside the existing tap-to-turn cue. The book wraps at both ends (see main.js), so neither
   button is ever disabled. */
.book-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  margin-top: 1.25rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--hairline);
}
.book-nav-btn {
  flex: 0 0 auto;
  background: none;
  border: 1px solid var(--gold-trim);
  border-radius: 999px;
  color: var(--gold);
  font-family: var(--font-body);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 0.55em 1.05em;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.3s var(--ease), color 0.3s var(--ease);
}
.book-nav-btn:hover, .book-nav-btn:focus-visible { background: var(--gold); color: var(--black); }
.book-nav-counter {
  flex: 1 1 auto;
  text-align: center;
  font-family: var(--font-body);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}
@media (max-width: 360px) {
  .book-nav { gap: 0.4rem; }
  .book-nav-btn { padding: 0.5em 0.7em; font-size: 0.64rem; letter-spacing: 0.1em; }
  .book-nav-counter { font-size: 0.62rem; letter-spacing: 0.1em; }
}
.book-close {
  display: block;
  margin: 1.4rem auto 0;
  background: none;
  border: 0;
  color: var(--gold-dim);
  font-size: 0.7rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 0.6em 1em;
}
.book-close:hover, .book-close:focus-visible { color: var(--gold); }
.flipbook[data-state="open"] .book-cover { display: none; }


/* ---------- Flip-book surface: the client's velvet + gold tray photo ---------- */
/* Plain black shell — the section itself (title/ornament/description live directly in it,
   via .container.section-head) must show no tray texture. Only .flipbook-tray below is textured. */
.flipbook-surface {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--black);
  padding-block: clamp(3rem, 7vw, 5rem);
}
/* Scoped to just the button + book block, not the whole section, so the texture doesn't bleed
   up behind the title/description above it. Its own padding keeps the tray from looking cropped
   tight against the book. */
.flipbook-tray {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(2rem, 5vw, 3.5rem);
}
.flipbook-tray::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: url("../assets/flipbook-velvet-tray.jpg") center 55% / cover no-repeat;
  background-attachment: fixed; /* ties the `cover` crop to the viewport instead of .flipbook-tray's
    own box, which resizes on every book/page/accordion state change and otherwise makes the
    backdrop visibly rescale and shift along with it */
  /* feather every edge into the surrounding black so it reads as an extension of the photo */
  -webkit-mask-image: radial-gradient(ellipse 72% 78% at 50% 50%, #000 42%, transparent 100%);
  mask-image: radial-gradient(ellipse 72% 78% at 50% 50%, #000 42%, transparent 100%);
}
.flipbook-tray::after { /* gentle vignette keeps the reading view legible */
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(ellipse at 50% 50%, transparent 35%, rgba(0,0,0,0.35) 100%);
}


/* ---------- Flip-book surface: mobile only (desktop rules above are untouched) ---------- */
@media (max-width: 900px) {
  /* Own fixed frame height for this breakpoint: measured max natural page height at mobile
     widths (320/390/501/560/600/768/900px) topped out at 511px (.book-reader's width caps at
     560px, so text reflow — and thus page height — barely differs from desktop above ~560px;
     this value is intentionally close to the desktop one for that reason), plus a comfortable
     margin. See the --book-track-h comment on .book-track above for the full measurement note. */
  .book-track { --book-track-h: 620px; }
  /* Brighter, more vibrant velvet + gold, closer to the hero photo's tone */
  .flipbook-tray::before {
    background-attachment: scroll; /* `fixed` has known rendering quirks on some mobile browsers
      (iOS Safari especially) — this codebase already avoids it on mobile elsewhere (see the
      layer-far handling in main.js). Desktop keeps `fixed` (set in the base rule above); mobile
      falls back to a stable min-height on .flipbook-tray below instead, so the backdrop still
      doesn't visibly rescale across the common open-book states at this breakpoint. */
    background-position: center 42%;
    filter: brightness(1.3) saturate(1.05) contrast(1.05);
    -webkit-mask-image: radial-gradient(ellipse 120% 105% at 50% 50%, #000 62%, transparent 100%);
    mask-image: radial-gradient(ellipse 120% 105% at 50% 50%, #000 62%, transparent 100%);
  }
  /* Floor sized to the tallest realistic mobile content state (an open page with its longest
     description expanded, measured at ~972px on a 390px-wide viewport) so the box stops
     shrinking below that point and the backdrop stays visually stable for the common cases. */
  /* Scoped to the OPEN book specifically: the closed cover doesn't vary in height, and the
     shifting complaint was about page-to-page/accordion changes once open, not the one-time
     closed-to-open transition. Applying the floor unconditionally left a lot of empty gold
     plate below the closed cover. .flipbook-tray is the ANCESTOR of #book-reader (not a
     descendant of .flipbook's data-state), so :has() is what actually lets this be scoped
     correctly without moving the floor onto the reader panel itself. */
  .flipbook-tray:has(#book-reader:not([hidden])) { min-height: 980px; }
  .flipbook-tray::after { background: none; }
  /* The peeking back cover: a deep, muted bronze-brown leather instead of saturated crimson */
  .book-back {
    background: linear-gradient(135deg, #4a2a14, #26130a);
    box-shadow: 0 2px 8px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(183,121,36,0.35);
    transform: rotate(4deg) translate(10px, 5px);
  }
}
