/* ══════════════════════════════════════════════════════════════════
   Kitty Chow — MsKittyChow.com
   Hybrid direction: Direction A structure (sticky tabs, full-bleed
   hero) + Direction B palette (emerald & gilt over warm black).
   Colour is carried to the footer so the page never goes plain.
   ══════════════════════════════════════════════════════════════════ */

:root {
  /* Ink — warm black, never a cold grey */
  --ink:        #0B0806;
  --ink-2:      #100C09;

  /* Emerald — the depth */
  --em-900:     #08150E;
  --em-800:     #0E2519;
  --em-700:     #123726;
  --em-600:     #164430;

  /* Gilt — the joy */
  --gilt:       #D3AE68;
  --gilt-hi:    #EBD59A;
  --gilt-lo:    #8A6A2E;

  /* Type */
  --cream:      #F4EEE3;
  --cream-2:    #E6DCCC;
  /* Lifted off the deck's #A99E8F: that cleared 4.5:1 on ink but only ~4.9:1
     on the emerald plates, with no margin for the gradients' lighter stops. */
  --muted:      #B5AA99;

  --serif: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --sans:  'Montserrat', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Rhythm */
  /* --rail is the page gutter and sits OUTSIDE the measure. The previous
     version put it inside a fixed 1240px border-box, which meant the gutter ate
     into the ceiling: content peaked at 1116px on a 1240px viewport and then
     SHRANK to 1048px by 1920px and stayed there. A 27" monitor rendered less
     content than a 13" laptop. The measure is now fluid and monotonic. */
  --rail:  clamp(1.25rem, 5vw, 6rem);
  --max:   clamp(1120px, 84vw, 1660px);
  --band:  clamp(4.5rem, 8vw, 10.5rem);
  --nav-h: 68px;

  /* One wall of photographs is now one row high. Capped against the viewport's
     SHORT side as well as its width, so a 13" laptop never spends its whole
     screen on a single rail. */
  --rail-h: clamp(340px, min(34vw, 52vh), 540px);

  /* Semantic stacking order, not arbitrary numbers */
  --z-sticky: 100;
  --z-drawer: 110;
  --z-skip:   200;

  --ease: cubic-bezier(.2, .7, .3, 1);
}

/* Typed custom properties the motion layer (motion.js) animates directly via
   GSAP. Each default renders the FINISHED state, so with no JS or reduced-motion
   the marks are simply drawn in full. --rule: the short gilt rule before the
   hero eyebrow. --seam: the gilt hairline at each band seam. */
@property --rule { syntax: "<number>"; inherits: false; initial-value: 1; }
@property --seam { syntax: "<number>"; inherits: false; initial-value: 1; }

/* svh, where supported: the rail height stops jumping as the mobile URL bar
   collapses. Declared through @supports because a custom property with an
   unknown unit fails at computed-value time, not at parse time — the usual
   two-declaration fallback would not work here. */
@supports (height: 1svh) {
  :root { --rail-h: clamp(340px, min(34vw, 52svh), 540px); }
}

/* ── Reset ───────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  /* Without this the browser paints its DEFAULT LIGHT scrollbar down the side
     of a near-black page — a bright grey stripe that reads as a rendering bug.
     `color-scheme` also fixes form controls and the overscroll gutter. */
  color-scheme: dark;
  scrollbar-color: #55452E var(--ink);

  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: var(--nav-h);
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--cream-2);
  font-family: var(--sans);
  font-weight: 300;
  font-size: clamp(1rem, .96rem + .2vw, 1.0625rem);
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; height: auto; }
h1, h2, h3 { margin: 0; font-weight: 500; }
p { margin: 0; text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--gilt-hi);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: 50%; top: 0; transform: translate(-50%, -140%);
  z-index: var(--z-skip); padding: .75rem 1.25rem;
  background: var(--gilt); color: var(--ink);
  font-size: .8125rem; letter-spacing: .12em; text-transform: uppercase;
  transition: transform .2s var(--ease);
}
.skip:focus { transform: translate(-50%, 0); }

/* ── Lenis smooth-scroll (vendored) ──────────────────────────────────
   Inlined from lenis/dist/lenis.css so the library needs no extra request.
   `.lenis.lenis-smooth { scroll-behavior: auto }` is what neutralizes the
   html{scroll-behavior:smooth} above WHILE Lenis is driving the page; that
   declaration stays in place as the fallback for reduced-motion, JS-off, or a
   library load failure. Classes are added to <html> by Lenis at runtime only. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: clip; }
.lenis.lenis-smooth iframe { pointer-events: none; }

/* ONE rail for the whole page. The nav mark, the hero headline, every section
   heading, the portfolio grid and the footer all start on the same left edge —
   that shared edge is what makes a full-bleed nav read as deliberate rather
   than detached. Anything that needs its own measure insets from here. */
.wrap,
.nav__inner,
.hero__body {
  width: min(100% - var(--rail) * 2, var(--max));
  margin-inline: auto;
}

/* ── Shared type ─────────────────────────────────────────────────── */
/* Solid gilt, not a clipped gradient. The deck's shimmering wordmark was a
   decorative effect that also repainted forever; a single warm gold reads
   more expensive against the photography and costs nothing. */
.gilt { color: var(--gilt-hi); }

.eyebrow {
  font-family: var(--sans);
  font-weight: 500;
  font-size: .6875rem;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--gilt);
  margin: 0;
}
.eyebrow--rule { display: inline-flex; align-items: center; gap: .875rem; }
.eyebrow--rule::before { content: ""; width: 1.75rem; height: 1px; background: var(--gilt); flex: none; transform: scaleX(var(--rule, 1)); transform-origin: left; }
.eyebrow--red { color: #E08A7A; }

.h2 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2.125rem, 1.3rem + 3.4vw, 3.5rem);
  line-height: 1.08;
  letter-spacing: -.005em;
  color: var(--cream);
  text-wrap: balance;
}
.h2--sm { font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.5rem); }

.lede { color: var(--muted); margin-top: 1rem; }

.rule { display: block; width: 3.5rem; height: 1px; background: var(--gilt); }
.rule--flex { flex: 1 1 2rem; min-width: 1.5rem; background: rgba(211, 174, 104, .3); }

/* ── Section heads ───────────────────────────────────────────────────
   Deliberately three different shapes, not one repeated kicker block.
   Each heading names its own section, so no section needs a label above
   it — that stack of tiny tracked eyebrows is what made every section
   read the same. */
.sec-head { margin-bottom: clamp(2.5rem, 5vw, 4rem); }

/* Centred, with a short gilt rule overhead — Story and Links */
.sec-head--centred { text-align: center; }
.sec-head--centred .rule { margin: 0 auto clamp(1.5rem, 3vw, 2rem); }

/* Split, heading left and a note right — Portfolio */
.sec-head--split {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1rem 3rem; flex-wrap: wrap;
}

/* Ruled, heading then a hairline running out to a short note — Watch */
.sec-head--ruled {
  display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap;
}

.sec-head__note {
  font-size: .875rem; line-height: 1.7; color: var(--muted);
  max-width: 34ch; margin-bottom: .35rem;
}
.sec-head__note--inline {
  flex: none; margin-bottom: 0;
  font-size: .6875rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--gilt);
}

/* ══ REVEAL ══════════════════════════════════════════════════════════
   Declared before the components on purpose. `.reveal.is-in` and rules like
   `.cover:hover` have equal specificity, so whichever comes last wins — with
   the reveal at the bottom of the file its `transform: none` silently
   cancelled every hover lift on the page. */
.reveal { opacity: 0; transform: translateY(16px); }
.js .reveal { transition: opacity .7s var(--ease) var(--d, 0ms), transform .7s var(--ease) var(--d, 0ms); }
.reveal.is-in { opacity: 1; transform: none; }

/* Framed things (the story portrait, the press cover) settle rather than rise:
   a different entrance for a different kind of object. */
.reveal--frame { transform: scale(.985); }
.js .reveal--frame { transition: opacity .9s var(--ease) var(--d, 0ms), transform .9s var(--ease) var(--d, 0ms); }

/* No JS, no IntersectionObserver, or reduced motion: nothing is ever hidden. */
html:not(.js) .reveal { opacity: 1; transform: none; }

/* Failure floor for the motion layer: if a vendored lib 404s or motion.js
   throws, it sets html.motion-fallback and this un-hides everything. :where()
   pins the rule to specificity (0,1,1) — below .cover:hover / .plate:hover
   (0,2,0) and below .reveal.is-in — so it can only reveal, never cancel a
   hover lift. (motion.js also re-adds .is-in directly as a belt-and-suspenders.) */
html.motion-fallback :where(.reveal, .reveal--frame) { opacity: 1; transform: none; }

/* ── Buttons ─────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .625rem;
  padding: .95rem 2rem;
  font-family: var(--sans); font-weight: 500;
  font-size: .75rem; letter-spacing: .24em; text-transform: uppercase;
  border: 1px solid var(--gilt);
  color: var(--gilt-hi);
  background: rgba(211, 174, 104, .07);
  cursor: pointer;
  transition: background .4s var(--ease), color .4s var(--ease), box-shadow .4s var(--ease);
}
.btn:hover, .btn:focus-visible {
  background: var(--gilt); color: var(--ink);
  box-shadow: 0 0 34px rgba(211, 174, 104, .3);
}
.btn--lg { padding: 1.15rem 2.5rem; font-size: .8125rem; }
.btn--block { width: 100%; padding-block: 1.15rem; }

.link-under {
  display: inline-flex; align-items: center; gap: .5em; min-height: 44px;
  font-size: .78125rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--cream);
  box-shadow: inset 0 -1px 0 rgba(244, 238, 227, .3);
  transition: color .3s var(--ease), box-shadow .3s var(--ease);
}
.link-under:hover, .link-under:focus-visible {
  box-shadow: inset 0 -1px 0 var(--gilt);
}
.link-under:hover, .link-under:focus-visible { color: var(--gilt-hi); }

/* ══ NAV ═════════════════════════════════════════════════════════ */
/* The nav overlays the hero via a negative bottom margin rather than the hero
   being pulled up with a negative top margin. Pulling the hero up scrolls its
   first `--nav-h` pixels out of the document, which silently clipped the top of
   her head. This way the hero starts at y=0 and the whole frame is visible. */
.nav {
  position: sticky; top: 0; z-index: var(--z-sticky);
  margin-bottom: calc(var(--nav-h) * -1);
  background: transparent;
  transition: background .4s var(--ease), border-color .4s var(--ease), backdrop-filter .4s var(--ease);
  border-bottom: 1px solid transparent;
}
/* Over the hero the nav sits on bright greenhouse glass, so it carries its own
   gradient bed. It fades out once the solid stuck background takes over. */
.nav::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 200%;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(6, 5, 3, .82) 0%, rgba(6, 5, 3, .42) 46%, rgba(6, 5, 3, 0) 100%);
  transition: opacity .4s var(--ease);
}
.nav.is-stuck::before { opacity: 0; }

.nav.is-stuck {
  background: rgba(11, 8, 6, .88);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border-bottom-color: rgba(211, 174, 104, .2);
}

.nav__inner {
  position: relative;
  height: var(--nav-h);
  display: flex; align-items: center; gap: 1.5rem;
}

.nav__mark {
  display: inline-flex; align-items: center; min-height: 44px;
  font-family: var(--serif); font-weight: 600;
  font-size: 1.375rem; letter-spacing: .12em;
  color: var(--gilt-hi);
  flex: none;
}

.nav__tabs { display: flex; gap: .25rem; margin-inline: auto; }
.nav__tabs a {
  position: relative;
  display: inline-flex; align-items: center; min-height: 44px;
  padding: .5rem .875rem;
  font-size: .6875rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--muted);
  transition: color .3s var(--ease);
}
.nav__tabs a::after {
  content: ""; position: absolute; left: .875rem; right: .875rem; bottom: .1rem;
  height: 1px; background: var(--gilt);
  transform: scaleX(0); transform-origin: left;
  transition: transform .35s var(--ease);
}
.nav__tabs a:hover, .nav__tabs a:focus-visible { color: var(--cream); }
.nav__tabs a.is-active { color: var(--gilt-hi); }
.nav__tabs a.is-active::after { transform: scaleX(1); }

.nav__cta { flex: none; min-height: 44px; padding: .7rem 1.25rem; font-size: .625rem; letter-spacing: .2em; }

.nav__burger {
  display: none; flex: none;
  width: 44px; height: 44px; margin-left: auto;
  background: none; border: 0; cursor: pointer;
  flex-direction: column; align-items: center; justify-content: center; gap: 5px;
}
.nav__burger span {
  width: 22px; height: 1px; background: var(--gilt-hi);
  transition: transform .3s var(--ease), opacity .2s var(--ease);
}
.nav__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.nav__drawer {
  background: rgba(11, 8, 6, .97);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom: 1px solid rgba(211, 174, 104, .2);
  padding: .5rem var(--rail) 1.25rem;
}
.nav__drawer a {
  display: flex; align-items: center; min-height: 48px; padding: .5rem 0;
  border-bottom: 1px solid rgba(211, 174, 104, .12);
  font-size: .8125rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cream-2);
}
.nav__drawer-cta { color: var(--gilt-hi) !important; border-bottom: 0 !important; }

/* ══ HERO ════════════════════════════════════════════════════════ */
.hero {
  position: relative;
  /* Width-independent height cap => the wider the viewport, the harder cover
     zooms and the less of the portrait survives (44% at 1440, 26% at 2560,
     20% at 3440). Raising the cap buys the photograph back on big screens
     and changes nothing at or below 1170px tall, where 94svh still binds. */
  min-height: min(94svh, 1100px);
  display: flex; align-items: flex-end;
  overflow: hidden;
  background: var(--em-900);
}

/* A portrait source in a landscape frame crops vertically only, and how much
   it zooms depends on viewport width — so the framing is anchored near the top
   of the plate. Her head is a few percent down in every green-shoot file, so a
   low y keeps face and shoulders in frame at every width instead of drifting
   down to a torso crop on wide screens. */
.hero__img {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 3%;
}

/* Left-weighted scrim so the type always has a bed, plus a floor gradient
   that hands off into the emerald band below. */
.hero__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(96deg, rgba(8, 6, 4, .9) 0%, rgba(8, 6, 4, .55) 34%, rgba(8, 6, 4, 0) 66%),
    linear-gradient(180deg, rgba(8, 6, 4, .7) 0%, rgba(8, 6, 4, 0) 24%, rgba(8, 6, 4, .3) 58%, rgba(11, 8, 6, .96) 100%);
}
/* A single warm emerald bloom — the "depth and joy" note, not a flat wash. */
.hero__glow {
  position: absolute; inset: 0; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(58% 46% at 74% 42%, rgba(22, 68, 48, .38) 0%, rgba(22, 68, 48, 0) 70%);
}

/* Shares the page rail (declared with .wrap above). It previously carried its
   own `calc(var(--max) + var(--gut) * 2)` measure, which hung the headline a
   full gutter left of every heading below it at any width over 1432px. */
.hero__body {
  position: relative;
  padding: 0 0 clamp(3rem, 7vw, 5.5rem);
  display: flex; flex-direction: column; align-items: flex-start;
  gap: clamp(.875rem, 1.6vw, 1.375rem);
}

/* The deck ran this at 148–150px. Pulled back to a 120px ceiling: still the
   dominant object in the fold, but it stops crowding her face on wide screens
   and stops overflowing at the 900–1100px range. */
.hero__name {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(3.25rem, .5rem + 9vw, 7.5rem);
  line-height: .88;
  letter-spacing: -.012em;
  text-wrap: balance;
}
.hero__name em { font-style: italic; }

.hero__line {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.25rem, .9rem + 1.4vw, 1.75rem);
  line-height: 1.35;
  color: var(--cream);
  max-width: 22ch;
}

.hero__cta {
  display: flex; align-items: center; gap: clamp(1.25rem, 3vw, 2rem);
  flex-wrap: wrap; margin-top: .5rem;
}

/* ══ BANDS — the colour ladder that keeps the page luxe to the floor ══ */
.band { position: relative; padding-block: var(--band); }
.band--tight { padding-top: 0; }
/* Gallery bands breathe less than the reading bands — four of them now sit in
   the ladder, and a full --band above and below each would put a screen of
   empty ink between every wall. */
.band--gal { padding-block: clamp(3rem, 5.5vw, 6.5rem); }

.band--ink {
  background: var(--ink);
}
/* Ink bands get an emerald vignette so they read rich, never plain. */
.band--ink::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(80% 50% at 8% 0%,  rgba(18, 55, 38, .5) 0%, rgba(18, 55, 38, 0) 62%),
    radial-gradient(70% 46% at 96% 100%, rgba(18, 55, 38, .42) 0%, rgba(18, 55, 38, 0) 60%);
}
.band--tight::before { display: none; }

.band--emerald {
  background:
    radial-gradient(120% 92% at 50% 0%, var(--em-700) 0%, var(--em-800) 52%, var(--em-900) 100%);
}
.band--deep {
  background:
    radial-gradient(110% 88% at 50% 12%, var(--em-800) 0%, var(--em-900) 58%, #050D09 100%);
}

/* ══ Dragon-scale brocade ═══════════════════════════════════════════
   Echoes Kitty's OWN ink — the phoenix across her back is built from rows of
   scalloped feather-scales, and she wears foo dogs on both arms — rather than
   stamping on a generic cultural motif. Kept to the emerald bands and the
   footer so it reads as watermarked silk and never becomes wallpaper; the ink
   bands (portfolio, watch, inquiries) stay clean. ~5% gilt, so it is felt more
   than seen and cannot affect text contrast. */
.band--emerald::before,
.foot::before {
  content: ""; position: absolute; inset: 0;
  pointer-events: none; z-index: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='26' viewBox='0 0 44 26'%3E%3Cg fill='none' stroke='%23D3AE68' stroke-width='1.1'%3E%3Cpath d='M0 26C0 11 22 11 22 26'/%3E%3Cpath d='M22 26C22 11 44 11 44 26'/%3E%3Cpath d='M-11 13C-11 -2 11 -2 11 13'/%3E%3Cpath d='M11 13C11 -2 33 -2 33 13'/%3E%3Cpath d='M33 13C33 -2 55 -2 55 13'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 44px 26px;
  opacity: .055;
  /* fade at the seams so the tiling never hard-edges into the next band */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 22%, #000 78%, transparent);
          mask-image: linear-gradient(180deg, transparent, #000 22%, #000 78%, transparent);
}
/* keep content above the watermark */
.band--emerald > .wrap,
.foot__inner { z-index: 1; }
/* Gilt hairline at every band seam — the thread that ties the ladder together */
.band + .band::after,
.band + .band::before { }
.band::after {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(211, 174, 104, .34) 22%, rgba(211, 174, 104, .34) 78%, transparent);
  transform: scaleX(var(--seam, 1)); transform-origin: 50% 50%;
}
.hero + .band::after { display: none; }

.band > .wrap { position: relative; }

/* ══ STORY ═══════════════════════════════════════════════════════ */
/* Three beats down the page, each its own frame + its own passage. The frame
   side alternates left / right / left, so the eye crosses the page as the
   story turns instead of settling on one side. Generous space between beats —
   they are separate moments, and the motion layer needs room to fade one out
   before the next arrives. */
.story-seq { display: grid; gap: clamp(4rem, 9vw, 8rem); }

.beat {
  display: grid;
  grid-template-columns: minmax(0, clamp(340px, 24vw, 560px)) minmax(0, 1fr);
  gap: clamp(2.5rem, 6vw, 5.5rem);
  align-items: center;
}
/* Frame right: the columns swap width as well as order, so the picture keeps
   its size on either side instead of stretching into the text column. */
.beat--right { grid-template-columns: minmax(0, 1fr) minmax(0, clamp(340px, 24vw, 560px)); }
.beat--right .story__shot { grid-column: 2; grid-row: 1; }
/* Pushed to the end of its column so the passage sits beside its own picture
   rather than stranded at the far page edge. The paragraphs are already capped
   at 56ch, so the block is narrower than the column and without this it would
   hug the left rail with a gap the width of the copy between it and the frame.
   The words stay left-aligned — it is the block that moves, not the ragging. */
.beat--right .beat__text  { grid-column: 1; grid-row: 1; justify-self: end; }

.story__shot { position: relative; margin: 0; }
.story__shot img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  border: 1px solid rgba(211, 174, 104, .26);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .5);
}
/* Gold rule inset inside each story frame. Brighter than the hairlines
   elsewhere on the page on purpose: it sits over a lit photograph rather than
   a dark plate, and at .18 it was invisible the moment the frame dropped below
   full opacity. It has no fade of its own — it is inside .story__shot, so it
   rides that frame's fade exactly. */
.frame-tick {
  position: absolute; inset: .75rem;
  border: 1px solid rgba(211, 174, 104, .55);
  pointer-events: none;
}

.beat__text p { color: var(--cream-2); line-height: 1.95; max-width: 56ch; }
.beat__text p + p { margin-top: 1.125rem; }
/* The label is the beat's own heading, so it sits tighter to its passage than
   the shared .group-label rhythm (which spaces groups apart, not lines). */
.beat__text .group-label { margin-top: 0; margin-bottom: .75rem; }

.pull { margin: clamp(2rem, 4vw, 2.75rem) 0 0; padding: 0; }
.pull p {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.5rem, 1.1rem + 1.5vw, 2rem);
  line-height: 1.32;
  color: var(--gilt-hi);
}
.pull cite {
  display: block; margin-top: .875rem;
  font-family: var(--sans); font-style: normal;
  font-size: .625rem; letter-spacing: .3em; text-transform: uppercase;
  color: var(--muted);
}
.pull cite::before { content: "— "; }

/* ══ PORTFOLIO RAILS ═════════════════════════════════════════════════
   Each set is its own band — green, red, yellow, black — split apart by the
   press wall, the interviews and the links hub, so the page reads as a
   sequence rather than one long contact sheet. Every wall is a single
   fixed-height row scrolled sideways: a set costs about one screen of height
   instead of five, and the frames keep their scale.

   Head shape: the set name left, the count tracked out to the right, the
   arrow pair after it — a fourth section-head shape, not a repeat of the
   other three. */
.sec-head--rail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: end;
  gap: .5rem 2rem;
  margin-bottom: 0;
}
.sec-head--rail .eyebrow { grid-column: 1 / -1; }
.sec-head--rail .h2 { grid-column: 1; }
.sec-head--rail .sec-head__note {
  grid-column: 2; justify-self: end;
  max-width: none; margin-bottom: .5rem;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .3em; text-transform: uppercase;
  white-space: nowrap;
}

/* Per-set photographer credit (Kitty's ask, 2026-08-02) — one quiet line
   under the title row, full grid width so it never fights the arrows. */
.sec-head__credit {
  font-size: .6875rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted);
}
.sec-head--rail .sec-head__credit { grid-column: 1 / -1; margin-top: .4rem; }
/* A hairline in the set's own colour, carried through to the scroll bar under
   the rail — the site's existing rule vocabulary, tinted per wall. */
.set-chip {
  display: inline-block; width: 1.5rem; height: 1px;
  margin-inline-end: .75rem; vertical-align: middle;
  background: var(--set, var(--gilt));
}

.rail__nav { grid-column: 3; display: flex; gap: 8px; margin-bottom: .25rem; }
/* An author `display` beats the UA's [hidden] rule, so say it here — the
   arrows ship hidden and the motion layer hides them again once it takes the
   rail over. */
.rail__nav[hidden] { display: none; }
.rail__arrow {
  width: 44px; height: 44px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid rgba(211, 174, 104, .32);
  background: transparent; color: var(--gilt-hi);
  font-size: 1.5rem; line-height: 0; cursor: pointer;
  transition: background .35s var(--ease), border-color .35s var(--ease),
              color .35s var(--ease), opacity .35s var(--ease);
}
.rail__arrow:hover:not(:disabled), .rail__arrow:focus-visible {
  background: var(--gilt); border-color: var(--gilt); color: var(--ink);
}
.rail__arrow:disabled { opacity: .28; cursor: default; }

/* The rail bleeds the full width of the band. --edge lines its first frame up
   with the page rail (and the section heading above it) at every width, and
   leaves the same gutter after the last frame. */
.rail-wrap {
  --edge: max(var(--rail), (100% - var(--max)) / 2);
  position: relative;
  margin-top: clamp(1.5rem, 3vw, 2.5rem);
}
.rail {
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity;
  scroll-padding-inline-start: var(--edge);
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  /* Visible by default, in the palette rather than the browser's grey: with no
     JS this scrollbar is the only control the wall has. */
  scrollbar-width: thin;
  scrollbar-color: var(--gilt-lo) transparent;
}
/* Once the controller is running it provides better affordances — the arrow
   pair and the position hairline — so the native track comes off the
   photographs. main.js adds this class. */
.rail.has-controls { scrollbar-width: none; }
.rail.has-controls::-webkit-scrollbar { display: none; }
.rail:focus-visible { outline: 2px solid var(--gilt-hi); outline-offset: 3px; }
/* While the motion layer pans the rail off the page scroll, snap has to go —
   the browser would keep pulling the strip back to the nearest frame. */
.rail.is-scrubbed { scroll-snap-type: none; }

.rail__track {
  display: flex; gap: 10px; width: max-content;
  padding-inline: var(--edge);
}

/* One row, one height. Portrait frames stay 3:4; landscape frames run wide
   (the grid was cropping them to portrait); features take a little more width.
   Rhythm along the strip instead of seventeen identical boxes. */
.rail .tile { flex: none; height: var(--rail-h); aspect-ratio: 3 / 4; scroll-snap-align: start; }
.rail .tile--feature { aspect-ratio: 4 / 5; }
.rail .tile--wide { aspect-ratio: 4 / 3; }

/* Scroll position, in the set's colour. JS drives --w/--x; with JS off the bar
   stays empty and the rail still scrolls natively. */
.rail__bar {
  height: 1px; margin: clamp(1rem, 2vw, 1.5rem) var(--edge) 0;
  background: rgba(211, 174, 104, .14);
}
.rail__bar span {
  display: block; height: 100%;
  width: calc(var(--w, 0) * 1%); margin-inline-start: calc(var(--x, 0) * 1%);
  background: var(--set, var(--gilt));
}

/* ── Serpentine flow ──────────────────────────────────────────────────
   The 1st and 3rd walls read RIGHT to LEFT, the 2nd and 4th left to right, so
   the eye turns back at every band instead of resetting to the same edge four
   times over. `direction: rtl` on the wrapper is the whole mechanism, and it
   is doing four jobs at once: the flex items lay out from the right, the
   scroll container's initial position IS the right edge (so the wall is
   correct with no JavaScript at all), snap alignment resolves to the right,
   and the position hairline fills from the right. Tile CONTENT is pinned back
   to ltr — only the ordering flips, never the frames or their labels. */
.band--flow-rtl .rail-wrap { direction: rtl; }
.band--flow-rtl .rail .tile { direction: ltr; }

/* The head does NOT mirror. Every wall keeps the same head shape — title left,
   count and arrows right — so the four bands read as one series; only the
   frames themselves change direction. */

.tile {
  position: relative; margin: 0; overflow: hidden;
  aspect-ratio: 3 / 4;
  border: 1px solid rgba(211, 174, 104, .16);
  background: var(--em-900);
}
/* Same inset gold rule the story frames carry (.frame-tick), as a pseudo
   rather than 58 hand-placed spans. Absolute + z-index 1 on purpose: .tile__open
   is a positioned descendant, so a static pseudo would paint underneath it and
   the photograph would cover the rule. pointer-events: none keeps the whole
   tile clickable through it. The empty "next shoot" plate is excluded — it has
   its own label treatment and no photograph to frame.

   It does not move on hover. The picture scales inside it, which is the frame
   holding still while the image breathes rather than both zooming together. */
.tile:not(.tile--empty)::after {
  content: ""; position: absolute; inset: .75rem; z-index: 1;
  border: 1px solid rgba(211, 174, 104, .55);
  pointer-events: none;
}

/* The thumbnail is a link (full image with JS off, lightbox with JS on). */
.tile__open {
  display: block; position: absolute; inset: 0;
  cursor: zoom-in;
}
.tile__open::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(60% 60% at 50% 50%, rgba(0,0,0,0) 55%, rgba(6,10,8,.35) 100%);
  opacity: 0; transition: opacity .4s var(--ease);
}
.tile:hover .tile__open::after,
.tile__open:focus-visible::after { opacity: 1; }
.tile__open:focus-visible { outline: 2px solid var(--gilt-hi); outline-offset: -3px; }

.tile img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.1s var(--ease), filter .6s var(--ease);
}
.tile:hover img,
.tile__open:focus-visible img { transform: scale(1.045); filter: saturate(1.08); }


.tile--empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .625rem;
  background: rgba(18, 55, 38, .3);
}
.tile--empty::before {
  content: ""; position: absolute; inset: 10px;
  border: 1px dashed rgba(211, 174, 104, .24);
}
.tile__num {
  font-family: var(--serif); font-weight: 600; font-size: 2rem;
  letter-spacing: .08em; color: rgba(235, 213, 154, .45);
}
.tile__label {
  font-size: .5625rem; font-weight: 500;
  letter-spacing: .28em; text-transform: uppercase; color: var(--muted);
}

.teaser {
  margin-top: 10px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
  padding: clamp(1.5rem, 3vw, 2.25rem) clamp(1.5rem, 3vw, 2.5rem);
  border: 1px dashed rgba(211, 174, 104, .28);
  background:
    radial-gradient(90% 160% at 12% 50%, rgba(122, 26, 26, .34) 0%, rgba(122, 26, 26, 0) 62%),
    rgba(18, 55, 38, .26);
}
.teaser__line {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.25rem, 1rem + 1vw, 1.625rem);
  color: var(--cream); margin-top: .5rem;
}
.teaser__soon {
  font-size: .625rem; font-weight: 500;
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--gilt); white-space: nowrap;
}

/* ══ PRESS — deliberately "print": tall plate, corner ticks, serif ══ */
.cover {
  display: block; position: relative;
  max-width: 780px; margin-inline: auto;
  padding: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 5vw, 4rem);
  text-align: center;
  border: 1px solid rgba(211, 174, 104, .4);
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(22, 68, 48, .75) 0%, rgba(8, 21, 14, .6) 66%),
    rgba(5, 13, 9, .5);
  transition: border-color .45s var(--ease), box-shadow .45s var(--ease), transform .45s var(--ease);
}
.cover:hover, .cover:focus-visible {
  border-color: var(--gilt);
  box-shadow: 0 0 46px rgba(211, 174, 104, .18);
  transform: translateY(-3px);
}

.cover__tick { position: absolute; width: 14px; height: 14px; pointer-events: none; }
.cover__tick--tl { top: 9px; left: 9px;  border-top: 1px solid var(--gilt); border-left: 1px solid var(--gilt); }
.cover__tick--tr { top: 9px; right: 9px; border-top: 1px solid var(--gilt); border-right: 1px solid var(--gilt); }
.cover__tick--bl { bottom: 9px; left: 9px;  border-bottom: 1px solid var(--gilt); border-left: 1px solid var(--gilt); }
.cover__tick--br { bottom: 9px; right: 9px; border-bottom: 1px solid var(--gilt); border-right: 1px solid var(--gilt); }

.cover__masthead {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(1rem, .9rem + .5vw, 1.25rem);
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--gilt-hi);
}
.cover__masthead span { font-weight: 400; opacity: .6; }

.cover__kicker {
  margin-top: .625rem;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .3em; text-transform: uppercase; color: var(--muted);
}

.cover__title {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(2.25rem, 1.2rem + 4.4vw, 4rem);
  line-height: 1.02;
  color: var(--cream);
  margin-top: clamp(1.5rem, 3vw, 2rem);
  text-wrap: balance;
}
.cover__deck {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.125rem, 1rem + .7vw, 1.5rem);
  color: var(--gilt-hi); margin-top: .5rem;
}

.cover__rule {
  width: 3rem; height: 0; margin: clamp(1.75rem, 3.5vw, 2.5rem) auto;
  border: 0; border-top: 1px solid rgba(211, 174, 104, .55);
}

.cover__quote { margin: 0; }
.cover__quote p {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.125rem, 1rem + .9vw, 1.5rem);
  line-height: 1.5;
  color: var(--cream-2);
  max-width: 34ch; margin-inline: auto;
  text-wrap: balance;
}
.cover__quote p::before { content: "\201C"; }
.cover__quote p::after  { content: "\201D"; }

.cover__read {
  display: inline-block; margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
  font-size: .6875rem; font-weight: 500;
  letter-spacing: .26em; text-transform: uppercase;
  color: var(--gilt);
}

/* ══ PRESS masthead wall — "featured in" coverage under the marquee ══
   Publication wordmark + gilt rule + headline: an editorial/print vocabulary,
   deliberately unlike the Watch section's video stills and play rings. Hustler
   is a wide banner (the mainstream name); the three trades sit in a row below,
   so the wall reads as a hierarchy, not another set of identical boxes. */
.group-label--centred { text-align: center; }

.masthead {
  display: flex; flex-direction: column;
  padding: clamp(1.5rem, 2.8vw, 2.125rem) clamp(1.375rem, 2.6vw, 2rem);
  border: 1px solid rgba(211, 174, 104, .24);
  background: rgba(18, 55, 38, .42);
  transition: border-color .45s var(--ease), background .45s var(--ease), transform .45s var(--ease);
}
.masthead:hover, .masthead:focus-visible {
  border-color: var(--gilt);
  background: rgba(22, 68, 48, .72);
  transform: translateY(-2px);
}

.masthead--wide {
  align-items: center; text-align: center;
  padding-block: clamp(2rem, 3.5vw, 2.75rem);
  border-color: rgba(211, 174, 104, .34);
  background:
    radial-gradient(120% 150% at 50% 0%, rgba(22, 68, 48, .72) 0%, rgba(14, 37, 25, .5) 70%),
    rgba(8, 21, 14, .35);
}

.masthead__name {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(1.5rem, 1.2rem + 1.1vw, 2rem);
  letter-spacing: .04em; line-height: 1; color: var(--cream);
}
.masthead--wide .masthead__name {
  font-size: clamp(2.25rem, 1.4rem + 3.4vw, 3.5rem);
  letter-spacing: .06em;
}

.masthead__rule { width: 2.25rem; height: 1px; background: var(--gilt); margin: .875rem 0; }
.masthead--wide .masthead__rule { margin-inline: auto; }

.masthead__headline {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.0625rem, .95rem + .5vw, 1.375rem);
  line-height: 1.35; color: var(--cream-2); text-wrap: pretty;
}
.masthead--wide .masthead__headline {
  font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem); max-width: 24ch;
}

.masthead__read {
  margin-top: auto; padding-top: 1.125rem;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .24em; text-transform: uppercase; color: var(--gilt);
}

/* The five trades keep their grouping — three industry-news, two interviews —
   but as ONE item per line rather than a 3-up and a 2-up of tall cards. The
   two rows survive as the grouping (and the gap between them); the columns are
   gone. See .press-wall for why. */
.masthead-row { display: grid; gap: 12px; margin-top: 12px; grid-template-columns: minmax(0, 1fr); }

/* ══ PRESS wall — the coverage list under the marquee ══
   Seven stacked plates made this the tallest section on the page: 1641px at
   1080 wide, nearly a full portrait screen, for seven links. The fix is the
   plates, not the stacking — each trade is now a horizontal ROW (wordmark, the
   gilt rule turned on its end as a divider, then headline over kind) instead of
   a tall card, which is about a third of the height for the same content and
   the same vocabulary.

   The wall sits on the marquee's own 780px measure. Left full-rail it would run
   to 1613px at 2560, where a two-word wordmark and a six-word headline sitting
   at opposite ends of the screen stop reading as one item; matching the cover
   also makes the section read as one plate over one list. */
.press-wall { max-width: 780px; margin-inline: auto; }

.press-wall .masthead-row .masthead {
  display: grid;
  grid-template-columns: minmax(4.5rem, 9rem) 1px minmax(0, 1fr);
  align-items: center;
  column-gap: clamp(.875rem, 1.8vw, 1.25rem);
  padding: clamp(.875rem, 1.6vw, 1.125rem) clamp(1rem, 2vw, 1.375rem);
}
.press-wall .masthead-row .masthead__name {
  grid-column: 1; grid-row: 1 / span 2;
  font-size: clamp(1rem, .9rem + .4vw, 1.25rem);
  text-wrap: balance;
}
/* Same 1px gilt hairline, stood upright: it still separates the wordmark from
   the headline, which is the job it did as a horizontal rule in the card. */
.press-wall .masthead-row .masthead__rule {
  grid-column: 2; grid-row: 1 / span 2;
  width: 1px; height: 100%; margin: 0; align-self: stretch;
  background: rgba(211, 174, 104, .45);
}
.press-wall .masthead-row .masthead__headline {
  grid-column: 3; grid-row: 1;
  font-size: clamp(.9375rem, .9rem + .25vw, 1.0625rem);
}
.press-wall .masthead-row .masthead__read {
  grid-column: 3; grid-row: 2;
  margin-top: 0; padding-top: .3125rem;
}

/* Hustler keeps the banner treatment — it is the mainstream name and the
   hierarchy is the point — trimmed so it does not tower over the rows it now
   heads. The 24ch headline cap goes: at the wall's measure it only forced
   "Who's That Girl: Kitty Chow" onto two lines. */
.press-wall .masthead--wide { padding-block: clamp(1.25rem, 2.2vw, 1.75rem); }
.press-wall .masthead--wide .masthead__name { font-size: clamp(1.75rem, 1.2rem + 1.8vw, 2.5rem); }
.press-wall .masthead--wide .masthead__rule { margin-block: .625rem; }
.press-wall .masthead--wide .masthead__headline {
  font-size: clamp(1.0625rem, .95rem + .5vw, 1.3125rem);
  max-width: none;
}
.press-wall .masthead--wide .masthead__read { padding-top: .75rem; }

/* ══ WATCH — deliberately "screen": landscape stills, play rings ══ */
.reel { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(1rem, 2.5vw, 1.75rem); }

.vid { display: block; }

.vid__still {
  display: block; position: relative; overflow: hidden;
  aspect-ratio: 16 / 9;
  background: #05100B;
  border: 1px solid rgba(211, 174, 104, .18);
  transition: border-color .45s var(--ease);
}
.vid__still img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.72) brightness(.66);
  transition: transform 1s var(--ease), filter .5s var(--ease);
}
.vid:hover .vid__still img,
.vid:focus-visible .vid__still img { transform: scale(1.05); filter: saturate(1) brightness(.82); }
.vid:hover .vid__still, .vid:focus-visible .vid__still { border-color: var(--gilt); }

.vid__play {
  position: absolute; inset: 0; margin: auto;
  width: clamp(52px, 7vw, 76px); height: clamp(52px, 7vw, 76px);
  border: 1px solid rgba(235, 213, 154, .7);
  border-radius: 50%;
  background: rgba(11, 8, 6, .3);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  transition: background .4s var(--ease), border-color .4s var(--ease), transform .4s var(--ease);
}
.vid__play::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 0; height: 0;
  border-top: 8px solid transparent; border-bottom: 8px solid transparent;
  border-left: 14px solid var(--gilt-hi);
  transform: translateX(2px);
  transition: border-left-color .4s var(--ease);
}
.vid:hover .vid__play, .vid:focus-visible .vid__play {
  background: var(--gilt); border-color: var(--gilt); transform: scale(1.06);
}
.vid:hover .vid__play::after, .vid:focus-visible .vid__play::after { border-left-color: var(--ink); }

.vid__meta { display: block; padding-top: 1.125rem; }
.vid__host {
  display: block;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .26em; text-transform: uppercase; color: var(--gilt);
}
.vid__title {
  display: block; margin-top: .5rem;
  font-family: var(--sans); font-weight: 400;
  font-size: clamp(1rem, .95rem + .35vw, 1.1875rem);
  line-height: 1.4; color: var(--cream);
  transition: color .3s var(--ease);
}
.vid:hover .vid__title, .vid:focus-visible .vid__title { color: var(--gilt-hi); }

/* ══ LINKS HUB ═══════════════════════════════════════════════════ */
.plate {
  position: relative;
  display: flex; flex-direction: column; justify-content: center;
  padding: clamp(1.25rem, 2.6vw, 1.75rem) clamp(1.25rem, 2.6vw, 1.75rem);
  border: 1px solid rgba(211, 174, 104, .22);
  background: rgba(18, 55, 38, .5);
  transition: background .45s var(--ease), border-color .45s var(--ease), box-shadow .45s var(--ease), transform .45s var(--ease);
}
.plate:hover, .plate:focus-visible {
  background: rgba(22, 68, 48, .78);
  border-color: var(--gilt);
  box-shadow: 0 0 30px rgba(211, 174, 104, .16);
  transform: translateY(-2px);
}

.plate__title {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(1.25rem, 1.1rem + .6vw, 1.5rem);
  line-height: 1.15; color: var(--cream);
  display: flex; align-items: center; gap: .625rem; flex-wrap: wrap;
}
.plate__sub { font-size: .8125rem; color: var(--muted); margin-top: .25rem; }
.plate__arrow {
  position: absolute; top: clamp(1.25rem, 2.6vw, 1.75rem); right: clamp(1.25rem, 2.6vw, 1.75rem);
  font-size: .9375rem; color: var(--gilt);
  transition: transform .4s var(--ease);
}
.plate:hover .plate__arrow, .plate:focus-visible .plate__arrow { transform: translate(2px, -2px); }

/* OnlyFans is one of three equal boxes now, so its emphasis has to come from
   things that do not change the box: the brighter border, the warmer fill, the
   corner ticks and the Free tag. Same padding, same type scale, same arrow as
   Instagram and X. The .plate--hero marquee (its own full-width row with an
   "It's Chow Time" button) and the .plate--wide 1.9fr/1fr pairing are gone —
   the CTA wording still appears in the nav and the hero. */
.plate--gilt {
  border-color: rgba(211, 174, 104, .45);
  background:
    radial-gradient(110% 190% at 18% 0%, rgba(22, 68, 48, .95) 0%, rgba(14, 37, 25, .65) 68%),
    rgba(8, 21, 14, .4);
}

.plate__tick { position: absolute; width: 12px; height: 12px; pointer-events: none; }
.plate__tick--tl { top: 8px; left: 8px; border-top: 1px solid rgba(211, 174, 104, .7); border-left: 1px solid rgba(211, 174, 104, .7); }
.plate__tick--br { bottom: 8px; right: 8px; border-bottom: 1px solid rgba(211, 174, 104, .7); border-right: 1px solid rgba(211, 174, 104, .7); }

.tag {
  font-family: var(--sans); font-weight: 600;
  font-size: .5625rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink); background: var(--gilt);
  padding: .25rem .5rem; line-height: 1;
}

/* --gilt-lo only reached ~3.2:1 on the emerald plate; these are 10px labels. */
.group-label {
  margin: clamp(2rem, 4vw, 2.75rem) 0 .875rem;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .34em; text-transform: uppercase; color: var(--gilt);
}

/* The destinations: equal columns, equal rows. `1fr` rather than auto so a
   longer handle can never make one card wider than another, and the grid's
   default stretch keeps them all the same height whatever the copy does. */
.plates {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 11px;
}
.plates .plate { padding-block: clamp(1.5rem, 3vw, 2rem); }
/* The arrow sits top-right, so the title needs to stop short of it. */
.plates .plate__title { padding-right: 1.5rem; }

/* A card needs ~215px or its wordmark wraps under its own arrow and the row
   grows from 102px tall to 129px. The gutter is 5vw here, so four across is
   (0.9w - 33) / 4. The arithmetic says ~1000, but measuring showed the row
   still taller there than at 1080 — the OnlyFans card's Free tag needs more
   room than a bare wordmark — so the switch sits at 1080, measured rather
   than derived: 227px a card still wraps, 231px does not. Two across clears it far below anything that matters. So:
   four in a row, then a 2x2, then a stack —
   always EQUAL cards, just not always in one row. Scoped here rather than in
   the page's shared breakpoints because the limit comes from this component's
   own content. */
@media (max-width: 1079px) {
  .plates { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 559px) {
  .plates { grid-template-columns: minmax(0, 1fr); }
}

/* Tier 3 — the tips. Still hairline chips with no fill, so they stay lighter
   than the three cards above them, but centred under that row and at twice
   the size: two links this easy to act on were reading as a footnote. */
.chips { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; }
#links .group-label { text-align: center; }
.chip {
  display: inline-flex; align-items: baseline; gap: .75rem;
  padding: 1.5rem 2.75rem;
  border: 1px solid rgba(211, 174, 104, .3);
  font-size: 1.0625rem; letter-spacing: .06em;
  color: var(--cream-2);
  transition: border-color .4s var(--ease), color .4s var(--ease), background .4s var(--ease);
}
.chip em { font-style: normal; color: var(--muted); font-size: .9375rem; }
.chip:hover, .chip:focus-visible {
  border-color: var(--gilt); color: var(--gilt-hi); background: rgba(211, 174, 104, .07);
}
.chip:hover em, .chip:focus-visible em { color: var(--gilt); }

/* ══ WIDE-MEASURE INSETS ═════════════════════════════════════════════
   The page measure is now fluid to 1660px, which is right for photography and
   headings and wrong for these. Each insets from the shared rail rather than
   fighting it. */
#links .plates,
#links .chips,
#links .group-label { max-width: 1100px; margin-inline: auto; }

.inq__form { max-width: 700px; }

/* ══ INQUIRIES ═══════════════════════════════════════════════════ */
.inq {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(2.5rem, 6vw, 5.5rem);
  align-items: start;
}
.inq__intro .h2 { margin-top: 1.25rem; }
.inq__direct {
  margin-top: clamp(2rem, 4vw, 2.75rem);
  font-size: .875rem; line-height: 1.9; color: var(--muted);
}
.inq__direct a { color: var(--gilt-hi); border-bottom: 1px solid rgba(211, 174, 104, .4); }
.inq__direct a:hover { border-bottom-color: var(--gilt); }

.row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1rem, 2.5vw, 1.75rem); }
.field { display: block; margin-bottom: clamp(1.25rem, 2.5vw, 1.75rem); }
.field__label {
  display: block; margin-bottom: .5rem;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .26em; text-transform: uppercase; color: var(--muted);
}
.field input, .field select, .field textarea {
  width: 100%;
  background: transparent;
  border: 0; border-bottom: 1px solid rgba(211, 174, 104, .3);
  padding: .7rem .125rem;
  font-size: 1rem; color: var(--cream);
  outline: none; resize: none;
  transition: border-color .35s var(--ease);
}
.field input:focus, .field select:focus, .field textarea:focus { border-bottom-color: var(--gilt); }
.field input:user-invalid, .field textarea:user-invalid { border-bottom-color: #C9695C; }
.field select option { background: var(--em-900); color: var(--cream); }

.field__error {
  margin: -.5rem 0 1rem;
  font-size: .8125rem; color: #E0897B;
}

.sent {
  border: 1px solid rgba(211, 174, 104, .34);
  background: rgba(18, 55, 38, .4);
  padding: clamp(2.5rem, 6vw, 3.75rem) 1.5rem;
  text-align: center;
}
.sent__line {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.75rem);
  color: var(--gilt-hi);
}
.sent__sig {
  margin-top: .875rem;
  font-size: .625rem; letter-spacing: .3em; text-transform: uppercase; color: var(--muted);
}

/* ══ FOOTER — an emerald plate, not a bare hairline ══════════════ */
.foot {
  position: relative;
  padding-block: clamp(3.5rem, 7vw, 5rem) clamp(2.5rem, 5vw, 3.5rem);
  background:
    radial-gradient(120% 120% at 50% 0%, var(--em-700) 0%, var(--em-800) 40%, #050D09 100%);
  /* The motion layer starts .foot__figure off the left edge and slides her in,
     so for the length of that tween she sits outside the plate. `clip` in
     preference to `hidden` because hidden would make the footer a scroll
     container. */
  overflow-x: hidden;
  overflow-x: clip;
}
.foot::after {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(211, 174, 104, .45) 22%, rgba(211, 174, 104, .45) 78%, transparent);
  transform: scaleX(var(--seam, 1)); transform-origin: 50% 50%;
}
.foot__inner { position: relative; display: grid; gap: clamp(2rem, 4vw, 2.75rem); }

/* ── Footer figure ───────────────────────────────────────────────────
   Kitty's own stance from the green set, traced to a single filled path. She
   stands ON the footer's baseline (align-self: end, and the SVG's own
   preserveAspectRatio is xMidYMax) so the shape sits on the same line the
   legal copy ends on rather than floating in the plate.

   Held back to a watermark: at full strength a gilt cutout competes with the
   wordmark right next to it, which is the one thing in the footer that should
   read first. */
.foot__figure { display: none; }

@media (min-width: 861px) {
  /* Rows are declared explicitly (brand / links / legal) so the figure can span
     them with `1 / -1`: that keyword only reaches the end of the EXPLICIT grid,
     so with auto-placed rows it silently collapses to row 1 and she floats in
     the top corner. */
  .foot__inner {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: repeat(3, auto);
    column-gap: clamp(1.75rem, 4vw, 3.5rem);
  }
  .foot__figure {
    display: block;
    grid-column: 1; grid-row: 1 / -1; align-self: end;
    width: auto; height: clamp(230px, 26vw, 380px);
    opacity: .58;
    /* It is a flat shape on a dark plate; a little glow stops it reading as a
       sticker cut out of the background. */
    filter: drop-shadow(0 0 22px rgba(211, 174, 104, .2));
  }

  /* ── Her entrance ──────────────────────────────────────────────────
     She starts off the left edge and slides to the spot she occupies in the
     layout when the footer arrives. This rides the site's own .reveal hook —
     whatever is running adds .is-in (ScrollTrigger.batch with the motion
     layer armed, main.js's observer without it) — so it degrades the same way
     every other entrance on the page does.

     It is CSS rather than a GSAP tween because the tween would not run:
     created inside gsap.matchMedia() it sat at progress 0 with its from-state
     applied, unpaused, and ignored an explicit .play().

     `-100%` clears her own width and the vw term clears the page gutter,
     which is wider than the rail on big screens because .wrap is centred; the
     footer's overflow-x: clip catches whatever is left over.

     Both rules restate opacity: .58 — she is a watermark, and .reveal.is-in
     would otherwise take her to full strength. Same specificity as
     .reveal.is-in (0,2,0), so these must stay below it in the file. */
  .foot__figure.reveal { opacity: .58; transform: translateX(calc(-100% - 24vw)); }
  .foot__figure.reveal.is-in { opacity: .58; transform: none; }
  .js .foot__figure.reveal { transition: transform 1.15s var(--ease); }
  /* No JS, or the motion layer bailed: she is simply in place, never stranded
     off-canvas waiting for an .is-in that is not coming. Opacity is restated
     here too — the generic `html:not(.js) .reveal` un-hide is (0,2,1) and would
     otherwise take her to full strength, which is what the legal pages did:
     they ship no JS at all, so she rendered solid there and as a watermark on
     the home page. */
  html:not(.js) .foot__figure.reveal,
  html.motion-fallback .foot__figure.reveal { opacity: .58; transform: none; }
  .foot__brand, .foot__links, .foot__legal { grid-column: 2; }
}

.foot__mark {
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3rem);
  line-height: 1;
}
.foot__tag {
  margin-top: .625rem;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .34em; text-transform: uppercase; color: var(--muted);
}

.foot__links {
  display: flex; flex-wrap: wrap; gap: .5rem 1.75rem;
  padding-block: clamp(1.25rem, 3vw, 1.75rem);
  border-block: 1px solid rgba(211, 174, 104, .16);
}
/* 44px hit target on both axes. min-width matters for the single-glyph "X"
   link, which was only 9px wide before; centring keeps its label in place. */
.foot__links a {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px;
  font-size: .6875rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--muted);
  transition: color .3s var(--ease);
}
.foot__links a:hover, .foot__links a:focus-visible { color: var(--gilt-hi); }

.foot__legal { font-size: .75rem; line-height: 1.8; color: var(--muted); max-width: 68ch; }
.foot__legal strong { color: var(--gilt); font-weight: 600; letter-spacing: .04em; }
.foot__copy { margin-top: .875rem; opacity: .78; }
/* Photographer credit. Sits with the copyright rather than in the "Elsewhere"
   row: it is an attribution, not somewhere to go. Tighter above than .foot__copy
   because it belongs to the line before it. */
.foot__credit { margin-top: .5rem; opacity: .78; }

/* Privacy / Terms. Separate from the "Elsewhere" row above, which is her
   profiles — these are the site's own pages and read as a quieter line. */
.foot__meta {
  margin-top: .5rem;
  display: flex; align-items: center; gap: .75rem;
  font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase;
}
.foot__meta a {
  display: inline-flex; align-items: center;
  min-height: 44px;
  color: var(--muted);
  transition: color .3s var(--ease);
}
.foot__meta a:hover, .foot__meta a:focus-visible { color: var(--gilt-hi); }
.foot__meta a[aria-current="page"] { color: var(--gilt); }
.foot__meta span { opacity: .5; }

/* ══ DOCUMENT PAGES (privacy, terms) ═══════════════════════════════════
   The legal pages carry the site's chrome and none of its machinery: no motion
   layer, no rails, no JavaScript at all. They reuse the bands, the seams, the
   brocade and the footer plate, so they read as part of the site rather than
   as the bare-HTML afterthought most sites bolt on. */

/* No hero to sit over, so the nav drops its overlay gradient and its negative
   margin and wears the stuck treatment from the start. */
.nav--doc {
  margin-bottom: 0;
  background: rgba(11, 8, 6, .88);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border-bottom-color: rgba(211, 174, 104, .2);
}
.nav--doc::before { display: none; }
.nav__back {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: .6875rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--muted);
  transition: color .3s var(--ease);
}
.nav__back:hover, .nav__back:focus-visible { color: var(--gilt-hi); }

/* A title plate and a reading band, both tighter than a full content band: a
   legal page should open at the words, not after a screen of empty emerald. */
.band--doc-head { padding-block: clamp(3rem, 6vw, 5rem); }
.band--doc-body { padding-block: clamp(2.75rem, 5vw, 4.5rem) clamp(4rem, 8vw, 7rem); }

.doc-title {
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(2.25rem, 1.5rem + 2.8vw, 3.25rem);
  line-height: 1.08; letter-spacing: -.005em;
  color: var(--cream); text-wrap: balance;
  margin: 0;
}
.doc-head .eyebrow { margin-bottom: .875rem; }
.doc-head__meta {
  margin-top: 1.25rem;
  font-size: .625rem; font-weight: 500;
  letter-spacing: .3em; text-transform: uppercase; color: var(--muted);
}

/* One measure for reading, insetting from the page rail rather than stretching
   to the full 1660px ceiling. */
.doc { max-width: 74ch; }
.doc > * + * { margin-top: 1.125rem; }
.doc p, .doc li { color: var(--cream-2); line-height: 1.9; }
.doc h2 {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(1.375rem, 1.1rem + 1vw, 1.75rem);
  line-height: 1.25; color: var(--gilt-hi);
}
.doc h2 + p, .doc h2 + ul { margin-top: .875rem; }
.doc h3 {
  margin-top: 1.75rem;
  font-family: var(--sans); font-weight: 600;
  font-size: .8125rem; letter-spacing: .06em;
  color: var(--cream);
}
.doc ul { margin: 0; padding-left: 1.25rem; }
.doc li + li { margin-top: .625rem; }
.doc li::marker { color: var(--gilt-lo); }
.doc strong { color: var(--cream); font-weight: 600; }
.doc a:not(.btn) {
  color: var(--gilt-hi);
  border-bottom: 1px solid rgba(211, 174, 104, .4);
  transition: border-color .3s var(--ease), color .3s var(--ease);
}
.doc a:not(.btn):hover, .doc a:not(.btn):focus-visible {
  color: var(--cream); border-bottom-color: var(--gilt);
}

/* "The short version" plate: the honest summary up top, in the site's framed
   vocabulary so it reads as a considered element and not a callout box. */
.doc__summary {
  padding: clamp(1.5rem, 3vw, 2rem) clamp(1.5rem, 3vw, 2.25rem);
  border: 1px solid rgba(211, 174, 104, .28);
  background: rgba(18, 55, 38, .26);
}
.doc__summary .eyebrow { display: block; margin-bottom: .875rem; }
.doc__summary ul { margin-top: .75rem; }

/* Section index. Hairline-separated rows, in the site's own list language. */
.doc__toc { margin-top: clamp(2rem, 4vw, 2.5rem); }
.doc__toc ol {
  margin: .75rem 0 0; padding: 0; list-style: none;
  columns: 2; column-gap: 2.5rem;
}
.doc__toc li { break-inside: avoid; }
.doc__toc a {
  display: block; padding: .5rem 0;
  border-bottom: 1px solid rgba(211, 174, 104, .12) !important;
  font-size: .8125rem; color: var(--muted) !important;
}
.doc__toc a:hover, .doc__toc a:focus-visible { color: var(--gilt-hi) !important; }

/* Anything the site owner still has to confirm before launch is marked in the
   source AND on the page, so a placeholder can never ship silently. */
.doc mark {
  background: rgba(211, 174, 104, .16);
  color: var(--gilt-hi);
  padding: .05em .3em;
  border: 1px dashed rgba(211, 174, 104, .5);
}

.nowrap { white-space: nowrap; }

@media (max-width: 560px) {
  .doc__toc ol { columns: 1; }
}

/* ══ LIGHTBOX ════════════════════════════════════════════════════════
   One native <dialog>, opened with showModal() so the browser gives the focus
   trap, Escape-to-close, and background inertness for free. The image contains
   itself; chrome (close, prev/next, count) is fixed to the viewport so it holds
   position independent of the image's size. */
.lightbox {
  position: fixed; inset: 0;
  width: 100%; height: 100%; max-width: 100%; max-height: 100%;
  margin: 0; padding: 0; border: 0;
  background: transparent; color: var(--cream);
  overflow: hidden;
}
.lightbox:not([open]) { display: none; }
.lightbox[open] { display: grid; place-items: center; }
.lightbox::backdrop {
  background: rgba(6, 10, 8, .94);
  -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px);
}

.lightbox__img {
  max-width: min(92vw, 1400px);
  max-height: 86dvh;
  object-fit: contain;
  border: 1px solid rgba(211, 174, 104, .22);
  box-shadow: 0 30px 90px rgba(0, 0, 0, .6);
  background: var(--em-900);
  /* Hidden until JS confirms the frame is decoded, then `.is-in` reveals it.
     Toggled on every open AND every prev/next, so navigation re-animates.
     JS reveals via decode().then/​catch, so a decode failure still shows it. */
  opacity: 0; transform: scale(.96);
  transition: opacity .3s var(--ease), transform .45s var(--ease);
}
.lightbox__img.is-in { opacity: 1; transform: none; }

.lightbox__btn {
  position: fixed; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px;
  border: 1px solid rgba(211, 174, 104, .35);
  background: rgba(11, 8, 6, .55);
  color: var(--gilt-hi);
  font-size: 2rem; line-height: 0; font-family: var(--sans);
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: background .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease);
}
.lightbox__btn:hover, .lightbox__btn:focus-visible {
  background: var(--gilt); color: var(--ink); border-color: var(--gilt);
}
.lightbox__close { top: clamp(1rem, 3vw, 2rem); right: clamp(1rem, 3vw, 2rem); font-size: 1.75rem; }
.lightbox__nav { top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { left: clamp(.75rem, 3vw, 2rem); }
.lightbox__nav--next { right: clamp(.75rem, 3vw, 2rem); }

.lightbox__count {
  position: fixed; bottom: clamp(1rem, 3vw, 1.75rem); left: 50%; transform: translateX(-50%);
  margin: 0; font-size: .625rem; font-weight: 500;
  letter-spacing: .28em; text-transform: uppercase; color: var(--muted);
}

/* Backdrop fades in on open (image entrance is the JS `.is-in` toggle above). */
.lightbox[open]::backdrop { animation: lbFade .35s var(--ease) both; }
@keyframes lbFade { from { opacity: 0; } to { opacity: 1; } }

@media (max-width: 560px) {
  .lightbox__btn { width: 46px; height: 46px; }
  .lightbox__img { max-height: 80dvh; }
  .lightbox__nav { top: auto; bottom: clamp(1rem, 3vw, 1.75rem); transform: none; }
  .lightbox__count { bottom: calc(clamp(1rem, 3vw, 1.75rem) + 58px); }
}

/* ══ AMBIENT (motion layer) ══════════════════════════════════════════
   Adds tactility and a sense of "alive" without touching the layout or the
   reveal ordering. Both overlays are decorative and pointer-events:none. */

/* Film grain: a fixed monochrome-noise wash at ~4%. Oversized + translated so
   the drift never exposes an edge. Sits above content but BELOW the nav (100)
   and the <dialog> top layer, and never affects text contrast at this opacity.
   Animated only when the motion layer is armed (html.gsap); otherwise static. */
.grain {
  position: fixed; inset: -20%;
  z-index: 90; pointer-events: none;
  opacity: .04;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
  will-change: transform;
}
html.gsap .grain { animation: grain 1.4s steps(6) infinite; }
@keyframes grain {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-5%, 3%); }
  40%  { transform: translate(4%, -5%); }
  60%  { transform: translate(-3%, 5%); }
  80%  { transform: translate(5%, -3%); }
  100% { transform: translate(0, 0); }
}

/* Scroll progress: a 1px gilt hairline at the very top, in the site's own
   hairline vocabulary. scaleX is driven by motion.js; 0 (invisible) without JS. */
.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 1px;
  z-index: 120; pointer-events: none;
  transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--gilt-lo), var(--gilt), var(--gilt-hi));
}

/* ══ RESPONSIVE ══════════════════════════════════════════════════ */
@media (max-width: 1024px) {
  /* One column: the frame sits above its passage for every beat, so the
     left/right alternation stops mattering and the reading order stays
     frame-then-words all the way down. */
  .beat, .beat--right { grid-template-columns: minmax(0, 1fr); }
  .beat--right .story__shot { grid-column: 1; grid-row: auto; }
  .beat--right .beat__text  { grid-column: 1; grid-row: auto; }
  .story__shot { max-width: 420px; }
  .story-seq { gap: clamp(3rem, 8vw, 5rem); }
  .inq { grid-template-columns: 1fr; }
}

@media (max-width: 860px) {
  .nav__tabs, .nav__cta { display: none; }
  .nav__burger { display: flex; }
  .nav__inner { gap: .75rem; }

  /* Head stacks; the arrows give way to the swipe. */
  .sec-head--rail { grid-template-columns: minmax(0, 1fr); }
  .sec-head--rail .sec-head__note {
    grid-column: 1; justify-self: start; margin-bottom: 0;
    white-space: normal;
  }
  .rail__nav { display: none; }

  .reel { grid-template-columns: 1fr; }
  .sec-head--split { align-items: flex-start; }
}

@media (max-width: 560px) {
  :root { --nav-h: 60px; }

  .hero { min-height: min(92svh, 760px); }
  .hero__img { object-position: 50% 0%; }

  .eyebrow { font-size: .625rem; letter-spacing: .2em; }
  .eyebrow--rule::before { width: 1.25rem; }
  .hero__scrim {
    background:
      linear-gradient(180deg, rgba(8, 6, 4, .72) 0%, rgba(8, 6, 4, 0) 26%, rgba(8, 6, 4, .42) 54%, rgba(11, 8, 6, .97) 100%);
  }
  .hero__cta { flex-direction: column; align-items: stretch; width: 100%; }
  .hero__cta .link-under { text-align: center; }

  .row { grid-template-columns: 1fr; gap: 0; }
  .chips { flex-direction: column; }
  .teaser { flex-direction: column; align-items: flex-start; }
}

/* ══ MOTION / PRINT ══════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
  /* Progress hairline is decorative; drop it. Grain is frozen by the rule
     above but stays as a static texture. */
  .scroll-progress { display: none; }
}

@media print {
  .nav, .hero__scrim, .hero__glow, .teaser, .grain, .scroll-progress { display: none; }
  .rail__nav, .rail__bar { display: none; }
  /* Rails unroll into a wrapped sheet — nothing hides past a scroll edge. */
  .rail { overflow: visible; }
  .rail__track { flex-wrap: wrap; width: auto; padding-inline: 0; }
  .rail .tile { height: auto; width: 30%; aspect-ratio: 3 / 4; }
  body { background: #fff; color: #000; }
}
