/* ============================================================================
   MIDNIGHT — mock-up theme layer
   ----------------------------------------------------------------------------
   Loaded after style.css and overrides it. Designed around Gray's Midnight
   Estate reference: a product floating in near-black navy, a glowing amber
   crescent, gold piping, soft mist, and wide-tracked serif capitals.

   This is a presentation layer only. It changes no copy, no markup semantics
   and no behaviour, so it can be dropped by deleting this file and its <link>.
   ========================================================================== */

:root {
  /* Deeper and warmer than the base palette. The reference bottoms out close
     to black and lets the gold do all the lifting. */
  --night-0: #04070d;
  --night-1: #080e1a;
  --night-2: #0d1626;
  --night-3: #142039;

  --amber: #f4ddae;
  --amber-2: #e8c184;
  --amber-3: #c69b52;
  --gold-hair: rgba(232, 193, 132, 0.34);
  --gold-hair-soft: rgba(232, 193, 132, 0.16);

  --navy: var(--night-1);
  --navy-deep: var(--night-0);
  --navy-soft: var(--night-3);
  --navy-line: rgba(244, 221, 174, 0.14);
  --gold: var(--amber-2);
  --gold-bright: var(--amber);
}

body {
  background: var(--night-1);
  color: rgba(246, 241, 231, 0.82);
}

/* ---------------------------------------------------------------- the moon */
/* A crescent: a warm disc with an offset disc masked out of it, plus a wide
   bloom behind. Pure CSS, so it costs no request and scales with the hero. */
.moon {
  position: absolute;
  /* Above the hero photograph and its scrim, below the copy. */
  z-index: 0;
  pointer-events: none;
  width: clamp(12rem, 24vw, 23rem);
  aspect-ratio: 1;
  top: clamp(-4rem, -2vw, -1rem);
  right: clamp(-2rem, 5vw, 9rem);
  left: auto;
}
/* The copy sits in front of it. */
.hero-inner,
.me-hero-inner {
  position: relative;
  z-index: 1;
}
.moon::before,
.moon::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
}
/* The bloom. Sits behind and spreads well past the disc. */
.moon::before {
  inset: -42%;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(244, 221, 174, 0.34) 0%,
    rgba(232, 193, 132, 0.17) 32%,
    rgba(198, 155, 82, 0.05) 52%,
    rgba(198, 155, 82, 0) 70%
  );
}
/* The crescent itself. */
.moon::after {
  background: radial-gradient(
    circle at 32% 28%,
    #fffaf0 0%,
    #fdedc9 26%,
    var(--amber) 48%,
    var(--amber-2) 70%,
    rgba(198, 155, 82, 0.5) 88%,
    rgba(198, 155, 82, 0) 100%
  );
  -webkit-mask-image: radial-gradient(circle at 66% 38%, #0000 48%, #000 49.6%);
  mask-image: radial-gradient(circle at 66% 38%, #0000 48%, #000 49.6%);
  /* Let the limb bleed into the scene rather than sitting on top of it. */
  filter: drop-shadow(0 0 34px rgba(244, 221, 174, 0.42))
          drop-shadow(0 0 90px rgba(232, 193, 132, 0.22));
}

/* ---------------------------------------------------------------- the hero */
.hero {
  background: var(--night-0);
}
.hero-h {
  text-shadow: 0 0 60px rgba(4, 7, 13, 0.8);
}
.hero-facts {
  border-top: 1px solid transparent;
  border-image: linear-gradient(90deg, var(--gold-hair), transparent 72%) 1;
}

/* Wide-tracked serif capitals, as on the mattress border. */
.kicker {
  font-family: var(--font-display);
  letter-spacing: 0.3em;
  font-size: var(--text-xs);
  /* The base sheet colours this for a cream ground (--ink-soft), which is all
     but invisible on a dark section. Only .kicker-gold was restated before. */
  color: rgba(246, 241, 231, 0.66);
}
.kicker-gold {
  color: var(--amber-2);
}

/* ------------------------------------------------------------ stock figure */
.stock-num {
  color: var(--amber);
  text-shadow: 0 0 26px rgba(232, 193, 132, 0.4);
}
.stock-dot {
  background: var(--amber);
}

/* --------------------------------------------------------------- sections */
/* The cream sections become night. This is the shift that takes the site from
   flat to the reference's mood, so every child that assumed a light ground is
   restated below. */
.section-cream {
  background: var(--night-2);
  color: rgba(246, 241, 231, 0.74);
  position: relative;
}
.section-cream h1,
.section-cream h2,
.section-cream h3 {
  color: var(--cream);
}
.section-navy-deep {
  background: var(--night-0);
}

/* A hairline of gold light along the top of each band, brightest at the
   centre — the piping on the mattress edge. */
.section-cream::before,
.section-navy-deep::before,
.band::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-hair) 50%, transparent);
}
.section-navy-deep,
.band {
  position: relative;
}

/* Mist pooling at the foot of the dark feature band. */
.section-navy-deep::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 42%;
  pointer-events: none;
  background: radial-gradient(
    60% 100% at 50% 100%,
    rgba(232, 193, 132, 0.09),
    transparent 70%
  );
}

/* ------------------------------------------------------------------ cards */
.card {
  background: linear-gradient(180deg, rgba(244, 221, 174, 0.055), rgba(244, 221, 174, 0.015));
  border: 1px solid var(--gold-hair-soft);
  position: relative;
  transition: border-color 0.4s var(--ease), transform 0.4s var(--ease);
}
/* Gold piping across the top edge of every card. */
.card::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-hair), transparent);
}
.card:hover {
  border-color: rgba(232, 193, 132, 0.3);
  transform: translateY(-2px);
}
.section-cream .card,
.section-cream .card-h {
  color: rgba(246, 241, 231, 0.74);
}
.section-cream .card-h {
  color: var(--cream);
}
.card-plain {
  background: none;
  border: 0;
  border-top: 1px solid var(--gold-hair-soft);
}
.card-plain::before {
  display: none;
}
.card-dark {
  background: linear-gradient(180deg, rgba(244, 221, 174, 0.05), rgba(244, 221, 174, 0.012));
}

/* ------------------------------------------------- text on the dark ground */
.section-cream .lede,
.section-cream .prose,
.section-cream p,
.section-cream li {
  color: rgba(246, 241, 231, 0.74);
}
.section-cream .note {
  color: rgba(246, 241, 231, 0.5);
}
.section-cream .link,
.section-cream a:not(.btn) {
  color: var(--amber-2);
}
.lede {
  color: rgba(246, 241, 231, 0.78);
}

/* chips, checklists, steps and the category list all drew their rules from
   the ink palette; move them onto gold. */
.chips li {
  border-color: var(--gold-hair-soft);
  color: rgba(246, 241, 231, 0.74);
}
.who-row {
  border-top-color: var(--gold-hair-soft);
}
.checklist li::before,
.mini-list li::before {
  color: var(--amber-2);
}
.cat {
  border-top-color: var(--gold-hair-soft);
}
.cat-index span {
  color: var(--amber-3);
  opacity: 0.85;
}
.step-num {
  background: linear-gradient(180deg, rgba(244, 221, 174, 0.12), rgba(244, 221, 174, 0.03));
  border: 1px solid var(--gold-hair);
  color: var(--amber);
}
.faq {
  border-top-color: var(--gold-hair-soft);
}
.faq summary {
  color: var(--cream);
}
.pull {
  border-left-color: var(--amber-3);
  color: var(--cream);
}

/* ---------------------------------------------------------------- buttons */
.btn-gold {
  background: linear-gradient(180deg, var(--amber) 0%, var(--amber-2) 55%, var(--amber-3) 100%);
  color: #19120a;
  border: 0;
  box-shadow: 0 0 0 1px rgba(255, 246, 226, 0.35) inset, 0 8px 30px -14px rgba(232, 193, 132, 0.8);
}
.btn-gold:hover {
  box-shadow: 0 0 0 1px rgba(255, 246, 226, 0.5) inset, 0 10px 36px -12px rgba(232, 193, 132, 0.95);
}
.btn-ghost {
  border-color: var(--gold-hair);
  color: var(--cream);
}
.btn-ghost:hover {
  border-color: var(--amber-2);
  background: rgba(244, 221, 174, 0.06);
}
.btn-navy {
  background: transparent;
  border: 1px solid var(--gold-hair);
  color: var(--cream);
}
.btn-navy:hover {
  border-color: var(--amber-2);
  background: rgba(244, 221, 174, 0.06);
}

/* -------------------------------------------------------- header & footer */
.site-header {
  background: rgba(4, 7, 13, 0.76);
  border-bottom: 1px solid var(--gold-hair-soft);
  backdrop-filter: blur(14px);
}
.site-footer {
  background: var(--night-0);
  border-top: 1px solid var(--gold-hair-soft);
}
.footer-cta,
.footer-bottom {
  border-top-color: var(--gold-hair-soft);
}

/* ------------------------------------------------------------ image frames */
/* A thin gold edge, like the piping around the mattress panel. */
.split-media img,
.me-hero-media img {
  border: 1px solid var(--gold-hair-soft);
}
.split-media {
  position: relative;
}

/* --------------------------------------------------- the Midnight page */
/* The reference image is the product shot for this line, so the page it
   belongs to leads with it rather than with a crop of bedding. */
.me-hero {
  background: var(--night-0);
}
.me-hero-media img {
  opacity: 1;
  border: 0;
  object-fit: cover;
  object-position: 54% 40%;
}
/* The reference photograph carries its own crescent, so the CSS one would be
   a second moon in the same sky. */
.me-hero .moon {
  display: none;
}
/* Darken behind the copy specifically, rather than the whole left edge, so
   the photograph's own crescent still reads in the top corner. */
.me-hero-media::after {
  background:
    radial-gradient(78% 52% at 20% 66%, rgba(4, 7, 13, 0.93) 0%, rgba(4, 7, 13, 0.62) 52%, rgba(4, 7, 13, 0) 82%),
    linear-gradient(180deg, rgba(4, 7, 13, 0.1) 0%, rgba(4, 7, 13, 0.18) 46%, rgba(4, 7, 13, 0.86) 90%, var(--night-1) 100%);
}
.display-hero {
  text-shadow: 0 0 70px rgba(4, 7, 13, 0.85);
}
.tagline {
  color: var(--amber-2);
}

/* --------------------------------------------------------------- the band */
.band {
  background: var(--night-2);
}
.band-inner {
  position: relative;
}

/* ------------------------------------------------------------- contact form */
.form-card {
  background: linear-gradient(180deg, rgba(244, 221, 174, 0.05), rgba(244, 221, 174, 0.012));
  border: 1px solid var(--gold-hair-soft);
  color: rgba(246, 241, 231, 0.78);
}
.form-card label,
.info-h,
.form-h {
  color: var(--cream);
}
.form-card input,
.form-card select,
.form-card textarea {
  background: rgba(4, 7, 13, 0.55);
  border: 1px solid var(--gold-hair-soft);
  color: var(--cream);
}
.form-card input:focus,
.form-card select:focus,
.form-card textarea:focus {
  border-color: var(--amber-2);
  outline-color: var(--amber-2);
}
.form-card ::placeholder {
  color: rgba(246, 241, 231, 0.38);
}
.form-note,
.optional {
  color: rgba(246, 241, 231, 0.52);
}
.info-card {
  background: linear-gradient(180deg, rgba(244, 221, 174, 0.045), rgba(244, 221, 174, 0.012));
  border: 1px solid var(--gold-hair-soft);
}
.phone-big {
  color: var(--amber);
}

/* ------------------------------------------------------------ page heads */
.page-head {
  background: var(--night-0);
  position: relative;
  overflow: hidden;
}
.page-head::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-hair) 50%, transparent);
}

/* ------------------------------------------------------------ legal pages */
.legal-body h2,
.legal-body h3 {
  color: var(--cream);
}
.legal-body {
  color: rgba(246, 241, 231, 0.76);
}
.evidence-table th {
  color: var(--amber-2);
  border-bottom-color: var(--gold-hair);
}
.evidence-table td {
  border-bottom-color: var(--gold-hair-soft);
}

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

/* ============================================================================
   The one orchestrated moment
   ----------------------------------------------------------------------------
   Everything else on the page stays still until a person acts. The entrance
   runs once, on load, and only in the hero: the photograph settles, then the
   three lines arrive in turn, then the supporting copy. Scattering the same
   effect over every section is what makes a page feel machine-made.
   ========================================================================== */

/* Gray's product shot is landscape and the hero is tall, so hold the mattress
   and its moon rather than letting cover crop to the middle. */
.hero-media img {
  opacity: 1;
  filter: none;
  object-position: 52% 38%;
  animation: settle 1.6s var(--ease) both;
}
.hero-media::after {
  background:
    radial-gradient(74% 50% at 22% 72%, rgba(4, 7, 13, 0.92) 0%, rgba(4, 7, 13, 0.58) 54%, rgba(4, 7, 13, 0) 84%),
    linear-gradient(180deg, rgba(4, 7, 13, 0.14) 0%, rgba(4, 7, 13, 0.2) 44%, rgba(4, 7, 13, 0.88) 90%, var(--night-1) 100%);
}

.hero-h {
  display: grid;
  gap: 0.06em;
}
.hero-h .rise {
  display: block;
  animation: rise 0.9s var(--ease) both;
  animation-delay: calc(0.35s + var(--i) * 0.13s);
}
.hero-sub,
.hero .btn-row,
.hero .stock-live,
.hero-facts {
  animation: rise 0.9s var(--ease) both;
  animation-delay: 0.82s;
}
.hero .btn-row { animation-delay: 0.92s; }
.hero .stock-live { animation-delay: 1s; }
.hero-facts { animation-delay: 1.08s; }

@keyframes settle {
  from { opacity: 0; transform: scale(1.05); }
  to   { opacity: 1; transform: none; }
}
@keyframes rise {
  from { opacity: 0; transform: translateY(0.8rem); }
  to   { opacity: 1; transform: none; }
}

/* The scroll reveals inherited from the base site slide as well as fade, which
   is the generic default. Fade only, and quicker. */
.reveal {
  transform: none;
  transition: opacity 0.6s var(--ease);
}
.reveal.is-visible {
  transform: none;
}

/* ------------------------------------------------- the crescent as a mark */
/* Replaces the 01-05 numbering on the category list. Five categories are not
   a sequence, so numbering them asserted an order that does not exist. */
.cat-index {
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  color: var(--amber-3);
}
.crescent {
  width: 1.5rem;
  height: 1.5rem;
  opacity: 0.9;
  filter: drop-shadow(0 0 12px rgba(232, 193, 132, 0.45));
}

@media (prefers-reduced-motion: reduce) {
  .hero-media img,
  .hero-h .rise,
  .hero-sub,
  .hero .btn-row,
  .hero .stock-live,
  .hero-facts {
    animation: none;
  }
}

/* The headline is the thing people repeat, so give it the room to land. */
.hero-h {
  font-size: clamp(2.9rem, 6.4vw, 5.1rem);
  line-height: 0.98;
  letter-spacing: -0.025em;
  max-width: 16ch;
}

/* The category subtitle carried real information but wore the tracked-out
   all-caps label costume. Sentence case in the display italic says the same
   thing and sounds like a person. */
.cat-sub {
  text-transform: none;
  letter-spacing: 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-base);
  color: var(--amber-2);
  opacity: 0.92;
}

/* At phone width the landscape shot crops hard and loses the crescent, which
   is the whole point of the picture. Shift the framing left to keep it. */
@media (max-width: 40rem) {
  .hero-media img {
    object-position: 24% 32%;
  }
}

/* Five categories in a three-column grid orphaned a slot on the second row.
   Six columns: the first three take two each, the last two take three each,
   so both rows fill and the wider pair reads as a deliberate pairing rather
   than a gap. */
.grid-cats {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: repeat(6, 1fr);
}
.grid-cats > * {
  grid-column: span 2;
}
.grid-cats > *:nth-child(4),
.grid-cats > *:nth-child(5) {
  grid-column: span 3;
}
@media (max-width: 62rem) {
  .grid-cats {
    grid-template-columns: repeat(2, 1fr);
  }
  .grid-cats > *,
  .grid-cats > *:nth-child(4),
  .grid-cats > *:nth-child(5) {
    grid-column: span 1;
  }
  .grid-cats > *:nth-child(5) {
    grid-column: span 2;
  }
}
@media (max-width: 38rem) {
  .grid-cats {
    grid-template-columns: 1fr;
  }
  .grid-cats > *,
  .grid-cats > *:nth-child(5) {
    grid-column: span 1;
  }
}

/* The heading sat at 60% width with nothing to its right. Setting the
   heading against the paragraph uses the full measure and gives the eye two
   things to land on instead of one and a void. */
.head-split {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: var(--space-6) clamp(var(--space-8), 6vw, var(--space-16));
  align-items: end;
}
.head-split .section-h {
  max-width: 13ch;
  margin: 0;
}
.head-split .lede {
  margin: 0;
  max-width: 52ch;
}
@media (max-width: 54rem) {
  .head-split {
    grid-template-columns: 1fr;
    align-items: start;
  }
  .head-split .section-h {
    max-width: 20ch;
  }
}

/* ============================================================================
   The rail — eight colourways, scrolled sideways
   ----------------------------------------------------------------------------
   On a wide screen the section pins and the track travels horizontally as you
   scroll down. On a phone, or under reduced motion, it degrades to an ordinary
   swipeable strip with scroll snapping: same content, no pinning, nothing to
   fight the user's thumb.
   ========================================================================== */
.rail {
  position: relative;
  background: var(--night-0);
  overflow: hidden;
}
.rail::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-hair) 50%, transparent);
}
.rail-viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-block: clamp(var(--space-16), 10vw, var(--space-24));
}
.rail-track {
  display: flex;
  align-items: center;
  gap: clamp(var(--space-5), 2.4vw, var(--space-10));
  padding-inline: clamp(var(--space-5), 5vw, var(--space-12));
  width: max-content;
}
.rail-lead,
.rail-end {
  flex: 0 0 auto;
  width: min(78vw, 26rem);
  scroll-snap-align: center;
}
.rail-h {
  font-family: var(--font-display);
  font-size: clamp(2.3rem, 4.6vw, 3.6rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--cream);
  margin: 0 0 var(--space-5);
}
.rail-lead p {
  color: rgba(246, 241, 231, 0.7);
  font-size: var(--text-sm);
  max-width: 34ch;
}
.rail-end-h {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  color: var(--cream);
  margin-bottom: var(--space-6);
}
.rail-card {
  flex: 0 0 auto;
  width: min(80vw, 30rem);
  margin: 0;
  scroll-snap-align: center;
}
.rail-card img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 1px solid var(--gold-hair-soft);
  border-radius: var(--radius);
}
.rail-card figcaption {
  margin-top: var(--space-4);
  font-size: var(--text-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber-2);
}

/* When GSAP drives the track, the browser must stop scrolling it as well. */
.rail.is-pinned .rail-viewport {
  overflow: hidden;
  scroll-snap-type: none;
}

/* Once SplitText owns the headline, the CSS entrance must stop fighting it. */
.hero-h.is-split .rise {
  animation: none;
  opacity: 1;
  transform: none;
}
.hero-h .hero-line {
  overflow: hidden;
}

/* --------------------------------------------------------- hero background
   The still is the LCP element and paints immediately; the video fades in on
   top only once it can actually play, so a slow connection shows a sharp
   photograph rather than a black box. */
.hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 52% 38%;
}
.hero-video {
  opacity: 0;
  transition: opacity 1.1s var(--ease);
  pointer-events: none;
}
.hero-video.is-playing {
  opacity: 1;
}
@media (max-width: 40rem) {
  .hero-bg {
    object-position: 34% 32%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .hero-video {
    display: none;
  }
}

/* The Midnight band on the home page carries the real product render, which
   is landscape. The 3/4 portrait slot was shaped for the stock crop it
   replaced and would cut the moon and most of the lettering off. */
.section-navy-deep .split-media img {
  aspect-ratio: 16 / 11;
  object-position: 50% 42%;
}

/* ============================================================================
   Softer picture edges
   ----------------------------------------------------------------------------
   Gray: the hard rectangles read as boxy. Corners are rounded throughout, the
   hairline borders come off, and where a photograph is shot on a dark ground
   the edges are masked so it dissolves into the page instead of sitting in a
   frame.
   ========================================================================== */
:root {
  --radius-img: clamp(0.75rem, 1.4vw, 1.25rem);
}

.split-media img,
.rail-card img,
.me-hero-media img,
.info-card,
.form-card {
  border-radius: var(--radius-img);
}

/* The hairline around photographs was what made them read as boxes. */
.split-media img,
.rail-card img {
  border: 0;
}

/* Where the photograph's own background is near-black, let it dissolve. The
   mask is generous in the middle and only eats the last few per cent at the
   edge, so nothing in the subject is lost. */
.rail-card img {
  -webkit-mask-image: radial-gradient(118% 118% at 50% 50%, #000 62%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
  mask-image: radial-gradient(118% 118% at 50% 50%, #000 62%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
}

/* The Midnight band is the one Gray was looking at: no frame at all, a wider
   dissolve, and a warm bloom behind so the product sits in light rather than
   on a rectangle. */
.section-navy-deep .split-media {
  position: relative;
}
/* The glow below is inset -12%, so it is 124% of the figure's width. In a
   narrow viewport that spilled past the edge and gave the page a horizontal
   scroll. clip (not hidden) contains it without making a scroll container,
   which would break the pinned rail. */
.section-navy-deep {
  overflow-x: clip;
}
.section-navy-deep .split-media::before {
  content: "";
  position: absolute;
  inset: -12%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    55% 55% at 50% 52%,
    rgba(232, 193, 132, 0.14),
    rgba(198, 155, 82, 0.05) 45%,
    transparent 72%
  );
}
/* The Midnight photograph carries its own feather — its edges are already
   composited onto the band's colour — so it takes no CSS mask and no frame. */
.section-navy-deep .split-media img {
  border-radius: 0;
  border: 0;
}

/* ------------------------------------------------------- Midnight tier cards
   Each tier now leads with its own photograph. The image runs to the card's
   edges, so the card's own padding moves onto the text. */
.card-tier {
  padding: 0;
  overflow: hidden;
}
/* The tier images are cut-outs on transparency, so there is no edge to soften
   and nothing to crop — the mattress simply sits on the card. Contain rather
   than cover, since the three photographs are different shapes. */
.card-tier img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  object-position: center 58%;
  border: 0;
  border-radius: 0;
  padding: var(--space-5) var(--space-5) 0;
  filter: drop-shadow(0 18px 28px rgba(0, 0, 0, 0.45));
}
.card-tier-body {
  padding: var(--space-6) var(--space-6) var(--space-7);
}
.card-tier .card-h {
  margin-bottom: var(--space-2);
}

/* ---------------------------------------------------- Midnight tier details
   The specification is the thing a dealer reads first, so it sits above the
   size list and carries the weight. */
.tier-spec {
  margin: 0 0 var(--space-2);
  color: var(--amber-2);
  font-size: var(--text-base);
}
.tier-spec strong {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 400;
  color: var(--amber);
}
.tier-sizes {
  margin: 0;
  font-size: var(--text-sm);
  color: rgba(246, 241, 231, 0.62);
}
.tier-flag {
  display: inline-block;
  margin-left: var(--space-2);
  padding: 0.15em 0.6em;
  border: 1px solid var(--gold-hair);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--amber-2);
  vertical-align: middle;
}

/* Four feature cards must never land on three columns: auto-fit does that
   between ~900 and ~1100px and strands the fourth card on its own row. */
#build .grid-4 { grid-template-columns: repeat(2, 1fr); }
@media (min-width: 70rem) { #build .grid-4 { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 34rem)  { #build .grid-4 { grid-template-columns: 1fr; } }

/* ===================================================================
   Light bands.

   The night theme had painted every one of the layout's cream sections
   navy, which left the whole site a single hue from the hero to the
   footer — monotone, and the reason the page read flat. The cream
   ground comes back here so the scroll alternates dark and light, and
   the pricing band goes warm so the dark stretches differ too.

   This block sits last on purpose: it has to outrank the dark-ground
   rules above it without having to restate them.
   =================================================================== */
.section-cream {
  background: var(--cream);
  color: var(--ink-soft);
}
.section-cream .section-h,
.section-cream h1,
.section-cream h2,
.section-cream h3,
.section-cream .cat-h,
.section-cream .step-h,
.section-cream .info-h,
.section-cream .form-h,
.section-cream strong { color: var(--ink); }

.section-cream .lede,
.section-cream .lede-light,
.section-cream .prose,
.section-cream p,
.section-cream li,
.section-cream .cat-body,
.section-cream .cat-sub,
.section-cream figcaption { color: var(--ink-soft); }

.section-cream .note,
.section-cream .form-note,
.section-cream .legal-updated,
.section-cream .optional,
.section-cream .info-line { color: #4d5766; }

.section-cream .kicker,
.section-cream .kicker-gold,
.section-cream .cat-index span,
.section-cream .step-num { color: var(--gold-ink); }

.section-cream .link,
.section-cream a:not(.btn) { color: var(--gold-ink); }

/* Cards and panels sit on paper here, so the gold-on-black treatment
   above is replaced rather than tinted. */
.section-cream .card,
.section-cream .info-card,
.section-cream .form-card,
.section-cream .legal-callout {
  background: rgba(255, 255, 255, 0.58);
  border: 1px solid rgba(23, 32, 47, 0.13);
  color: var(--ink-soft);
}
.section-cream .card-h { color: var(--ink); }
.section-cream .card::before,
.section-cream::before {
  background: linear-gradient(90deg, transparent, rgba(122, 96, 38, 0.3), transparent);
}
.section-cream .card:hover { border-color: rgba(122, 96, 38, 0.42); }
.section-cream .card-plain {
  background: none;
  border: 0;
  border-top: 1px solid rgba(23, 32, 47, 0.16);
}
.section-cream .checklist li::before,
.section-cream .mini-list li::before,
.section-cream .crescent { color: var(--gold-ink); }
.section-cream .chips li,
.section-cream .who-row { border-color: rgba(23, 32, 47, 0.14); }
.section-cream .pull { color: var(--ink); }

/* Form controls on paper. */
.section-cream .form-card label,
.section-cream .field label { color: var(--ink); }
.section-cream .form-card input,
.section-cream .form-card select,
.section-cream .form-card textarea {
  background: #fff;
  border: 1px solid rgba(23, 32, 47, 0.22);
  color: var(--ink);
}
.section-cream .form-card input::placeholder,
.section-cream .form-card textarea::placeholder { color: #7a8494; }
.section-cream .btn-ghost {
  border-color: rgba(23, 32, 47, 0.3);
  color: var(--ink);
}
.section-cream .btn-ghost:hover {
  border-color: var(--ink);
  background: rgba(23, 32, 47, 0.05);
}
.section-cream .phone-big { color: var(--ink); }
.section-cream .evidence-table th,
.section-cream .evidence-table td {
  color: var(--ink-soft);
  border-color: rgba(23, 32, 47, 0.14);
}
.section-cream .evidence-table th { color: var(--ink); }

/* The pricing band goes warm, so the run of dark sections is not all
   the same blue either. */
.band { background: #17110b; }
/* btn-navy is a transparent, cream-on-dark outline above; on paper that is an
   invisible button, so it goes back to the solid navy the base sheet drew. */
.section-cream .btn-navy {
  background: var(--navy);
  border: 1px solid var(--navy);
  color: var(--cream);
}
.section-cream .btn-navy:hover {
  background: var(--navy-soft);
  border-color: var(--navy-soft);
}

/* ===== build diagrams ===== */
/* The cutaways are drawn on white, so they sit on their own panel rather than
   on the cream directly, and the panel is rounded and soft-edged so the
   artwork merges into the page instead of being a hard white rectangle. */
.builds { display: grid; gap: clamp(var(--space-8), 4vw, var(--space-16)); }
.build { margin: 0; }
.build-media {
  background: #fff;
  border-radius: clamp(1rem, 2vw, 1.75rem);
  padding: clamp(var(--space-4), 2.5vw, var(--space-10));
  box-shadow: 0 1px 0 rgba(23, 32, 47, 0.07), 0 18px 48px -32px rgba(23, 32, 47, 0.5);
  overflow: hidden;
}
.build-media img { display: block; width: 100%; height: auto; }
.build-cap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3) var(--space-5);
  margin-top: var(--space-4);
  padding-inline: clamp(0rem, 1vw, var(--space-4));
}
.build-name {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.2vw, 1.9rem);
  line-height: 1.1;
  color: var(--ink);
}
.build-spec { font-size: var(--text-sm); letter-spacing: 0.04em; color: #4d5766; }
.build-spec strong { color: var(--ink); }
@media (min-width: 60rem) {
  .builds { grid-template-columns: 1fr; }
  .build { display: grid; grid-template-columns: minmax(0, 1fr) 14rem; gap: var(--space-8); align-items: center; }
  .build-cap { margin-top: 0; display: block; }
  .build-spec { display: block; margin-top: var(--space-2); }
}
/* ===== end build diagrams ===== */

/* ===== photos =====
   A shared strip for the photo groups added to the inventory band and the
   furniture band. Same language as .rail-card: rounded, no hairline, and the
   outermost few per cent of the frame dissolved so the picture sits on the
   ground rather than in a box. */
.photo-strip {
  display: grid;
  grid-template-columns: repeat(var(--photo-cols, 3), minmax(0, 1fr));
  gap: clamp(var(--space-4), 2vw, var(--space-8));
  margin-top: clamp(var(--space-10), 5vw, var(--space-16));
}
.photo-shot {
  margin: 0;
  min-width: 0;
}
.photo-shot img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border: 0;
  border-radius: var(--radius-img);
  -webkit-mask-image: radial-gradient(126% 126% at 50% 50%, #000 74%, rgba(0, 0, 0, 0.6) 91%, transparent 100%);
  mask-image: radial-gradient(126% 126% at 50% 50%, #000 74%, rgba(0, 0, 0, 0.6) 91%, transparent 100%);
}
.photo-shot figcaption {
  margin-top: var(--space-4);
  font-size: var(--text-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber-2);
}
/* On the paper bands the caption takes the accessible gold-family ink the
   rest of the cream sections use, not the bright gold meant for dark ground. */
.section-cream .photo-shot figcaption {
  color: var(--gold-ink);
}
/* The inventory strip sits under the category cards, so it wants a little
   more air above it than the furniture strip, which follows a photograph. */
#distribute .photo-strip {
  margin-bottom: clamp(var(--space-8), 4vw, var(--space-12));
}
/* Three is the whole thought here, so the row stays three until it cannot,
   rather than dropping to two and orphaning the third. */
@media (max-width: 40rem) {
  .photo-strip {
    --photo-cols: 1;
    gap: var(--space-8);
  }
  .photo-shot img {
    aspect-ratio: 4 / 3;
  }
}
/* ===== end photos ===== */

/* ===== motion =====
   ============================================================================
   MOTION LAYER
   ----------------------------------------------------------------------------
   Owned by the motion pass. Every rule below states the FINAL, at-rest look of
   the thing it touches, so the page is correct with JavaScript off, with GSAP
   missing, and with motion turned down. app.js only ever moves a value away
   from the resting state and puts it back.

   Nothing here may hide content on its own. Where a value could hide something
   (the card piping, the seam wash) the default is the visible end of the range.
   ========================================================================== */

/* --------------------------------------------------- registered properties
   A plain custom property is ALWAYS inherited, so writing one on a <section>
   invalidates the computed style of everything inside it. Measured on a
   6x-throttled phone, driving the seams through unregistered properties cost
   ~6ms per frame on a full-page flick — about 5ms of it style recalculation
   over the sections' subtrees, and barely 1ms of actual painting.

   Registering them with inherits:false says what is already true — nothing
   below a section reads these — and lets the engine skip the subtree. Same
   pixels, a twelfth of the cost. Anything the gradients reference must be
   declared here, and only on the element that both sets and uses it. */
@property --seam-p    { syntax: "<percentage>"; inherits: false; initial-value: -30%; }
@property --seamo-p   { syntax: "<percentage>"; inherits: false; initial-value: 70%; }
@property --seam-glow { syntax: "<number>";     inherits: false; initial-value: 0; }
@property --seamo-glow{ syntax: "<number>";     inherits: false; initial-value: 0; }
@property --seam-h    { syntax: "<length>";     inherits: false; initial-value: 0px; }
@property --seamo-h   { syntax: "<length>";     inherits: false; initial-value: 0px; }

/* ------------------------------------------------------------- the seams
   Section grounds used to meet at a hard edge: cream stopped and navy started
   on one pixel row. The seam replaces that edge with a dissolve that the
   scroll drives — the incoming ground floods up through the junction behind a
   travelling line of gold light, and settles into a soft blend rather than a
   cut.

   It is painted as a background-image on the two sections themselves, so it
   sits behind everything, adds no element and changes no layout. Each strip is
   --seam-h tall and --seam-h is always shorter than a section's own block
   padding, so NO TEXT EVER SITS ON AN INTERMEDIATE COLOUR: the whole
   transition happens in the whitespace above the first line and below the
   last. The contrast audit therefore holds at every frame, not only at the
   ends.

   Four layers: a light edge and a ground wash for the strip at the top of the
   incoming section, and the same pair for the strip at the foot of the
   outgoing one. They are two windows onto ONE continuous colour function, and
   --seamo-p is always --seam-p plus 100%, which is what keeps them joined
   across the junction with no step.

   --seam-p is where the colour boundary sits inside the top strip, as a
   percentage of it. It is allowed to run outside 0–100%, which is how the
   boundary travels on past the strip and into the one above. The resting
   values below are the no-JavaScript, motion-off look: the outgoing section's
   last few pixels dissolve into the incoming one and nothing else happens.
   Colours are read off the rendered page at runtime, so there is no table of
   hexes here to drift out of step with the design. */
.has-seam {
  --seam-p: -30%;
  --seamo-p: 70%;
  --seam-glow: 0;
  --seamo-glow: 0;
  --seam-h: clamp(2.5rem, 6vw, 5.5rem);
  --seamo-h: clamp(2.5rem, 6vw, 5.5rem);
  --seam-from: transparent;
  --seam-to: transparent;
  --seamo-from: transparent;
  --seamo-to: transparent;
  background-image:
    linear-gradient(
      to bottom,
      rgba(232, 193, 132, 0) calc(var(--seam-p) - 20%),
      rgba(232, 193, 132, var(--seam-glow)) var(--seam-p),
      rgba(232, 193, 132, 0) calc(var(--seam-p) + 12%)
    ),
    /* No stop is pinned at 0%: --seam-p runs negative once the boundary has
       travelled past this strip, and a 0% stop in front of it would be clamped
       over the top of it and crush the dissolve into a hard line. A gradient's
       first colour already extends backwards on its own. */
    linear-gradient(
      to bottom,
      var(--seam-from) var(--seam-p),
      var(--seam-to) calc(var(--seam-p) + 58%),
      var(--seam-to) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(232, 193, 132, 0) calc(var(--seamo-p) - 20%),
      rgba(232, 193, 132, var(--seamo-glow)) var(--seamo-p),
      rgba(232, 193, 132, 0) calc(var(--seamo-p) + 12%)
    ),
    linear-gradient(
      to bottom,
      var(--seamo-from) var(--seamo-p),
      var(--seamo-to) calc(var(--seamo-p) + 58%),
      var(--seamo-to) 100%
    );
  background-repeat: no-repeat;
  background-position: left top, left top, left bottom, left bottom;
  background-size:
    100% var(--seam-h),
    100% var(--seam-h),
    100% var(--seamo-h),
    100% var(--seamo-h);
}

/* --------------------------------------------------------- the gold piping
   The hairline across the top of every card already existed. It now draws
   itself in from the left as the card lands. Default 1 — fully drawn — so a
   card that is never animated still wears its piping. */
.card::before {
  transform: scaleX(var(--pipe, 1));
  transform-origin: left center;
}

/* ------------------------------------------------------- the section rule
   A gold hairline under each section heading, drawn left to right as the
   heading arrives. Created by app.js, so it does not exist at all without
   JavaScript and cannot leave a stray line behind. */
.head-rule {
  display: block;
  height: 1px;
  margin-top: clamp(var(--space-5), 2.5vw, var(--space-8));
  background: linear-gradient(90deg, var(--gold-hair), rgba(232, 193, 132, 0.04));
  transform: scaleX(var(--rule, 1));
  transform-origin: left center;
}
.section-cream .head-rule {
  background: linear-gradient(90deg, rgba(122, 96, 38, 0.38), rgba(122, 96, 38, 0.04));
}

/* ---------------------------------------------------------- the rail meter
   A gold progress hairline along the foot of the pinned rail, so the sideways
   travel has a readable length. Only drawn while the rail is pinned. */
.rail-meter {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--amber-3), var(--amber));
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
}

/* ------------------------------------------------------------ the CTA band
   Warm light rises into the pricing band as it comes up the screen.

   This was a pseudo-element whose radial gradient was repositioned through a
   custom property every frame — which repaints the gradient every frame and,
   because the property sat on .band, restyled the band's whole subtree with
   it. It is now a real element that app.js inserts, carrying a STATIC
   gradient that is moved by transform and faded by opacity: both of those are
   compositor work, so the frame cost is nil.

   It exists only when motion is welcome — app.js removes it otherwise — so
   with no JavaScript, or motion turned down, the band is exactly as it was.
   The gradient is capped low enough that the band's cream text stays above
   4.5:1 against the lightened ground at the glow's peak: measured off the
   rendered pixels, not assumed. */
.band {
  /* The glow is taller than the band so it can travel without showing an
     edge; the band has to crop it rather than bleed into its neighbours. */
  overflow: hidden;
}
.band-glow {
  position: absolute;
  left: 0;
  right: 0;
  top: -25%;
  bottom: -25%;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  will-change: transform, opacity;
  background: radial-gradient(
    64% 46% at 50% 72%,
    rgba(232, 193, 132, 0.14),
    rgba(232, 193, 132, 0) 62%
  );
}
.band-inner {
  position: relative;
  z-index: 1;
}

/* ------------------------------------------------------------- the tilt
   Product photographs lean toward the pointer. The perspective has to live on
   the parent; the transform itself is written by app.js and cleared on leave. */
.tilt-stage {
  perspective: 1100px;
}

/* ---------------------------------------------------------------- hygiene
   The card carries a transform transition for its hover lift. While GSAP is
   writing a transform every frame that transition fights it, so the entrance
   turns it off for its own duration and hands it straight back. */
.is-animating {
  transition: none !important;
}

/* ------------------------------------------------------- motion turned off
   Everything above already describes the resting state, so there is nothing
   to undo. These are belt and braces: if any inline value were ever left
   behind, the page still reads correctly. */
@media (prefers-reduced-motion: reduce) {
  .has-seam {
    --seam-p: -30%;
    --seamo-p: 70%;
    --seam-glow: 0;
    --seamo-glow: 0;
  }
  .card::before {
    transform: none;
  }
  .head-rule {
    transform: none;
  }
  .band-glow {
    display: none;
  }
  .rail-meter {
    display: none;
  }
}
/* ===== end motion ===== */

/* ===== photo aspect ===== */
/* The furniture shots are upright pieces photographed close up; 3:2 letterboxes
   them and object-fit then crops the arms and backs off again. 4:3 contains the
   whole piece, and matches the frame rail elsewhere on the page. */
#furniture .photo-shot img { aspect-ratio: 4 / 3; }
/* ===== end photo aspect ===== */

/* ===== motion: home =====
   =====================================================================
   HOMEPAGE MOTION LAYER
   ----------------------------------------------------------------------------
   Owned by the homepage motion pass. Same contract as the block above: every
   rule here states the FINAL, at-rest look of the thing it touches, so the
   page is correct with JavaScript off, with GSAP missing, and with motion
   turned down. app.js pushes values away from this resting state and lets
   them come back.

   Two kinds of thing live here:

   -  DECORATION that app.js inserts and removes (the hero light, the card
      spotlight, the rail glow, the rake). These rest at opacity 0 because
      they are not content — they do not exist at all without JavaScript, and
      with motion turned down app.js never creates them. This is the same
      pattern .band-glow already uses.

   -  CONTENT, which rests VISIBLE and finished. Nothing in here can hide a
      word of copy or a photograph on its own.
   ========================================================================== */

/* --------------------------------------------------- registered properties
   Scroll-driven work in this layer is transform and opacity on real inserted
   elements, so it needs no custom properties at all. These five drive
   ONE-SHOT ENTRANCES ONLY — a hairline drawing itself in under half a second,
   once — and each is read by a ::before or ::after.

   A pseudo-element inherits from its originating element, so inherits:false
   would hide the value from the only thing that reads it. These therefore
   inherit, deliberately, and the cost the block above warns about does not
   apply: that was about restyling a whole section's subtree every frame for
   the length of a page. These touch two text nodes for 500ms, once. */
@property --fact    { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --cap     { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --tick    { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --edge    { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --horizon { syntax: "<number>"; inherits: true; initial-value: 1; }

/* ------------------------------------------------------- page progress
   A gold hairline along the foot of the header reading how far down the page
   you are. Inserted by app.js, so it does not exist without JavaScript and
   cannot leave a stray rule behind. */
.page-meter {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg, var(--amber-3), var(--amber));
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
  z-index: 1;
}

/* ============================================================== the hero ===
   The homepage hero is a pinned set piece. It needs a full viewport to hold
   the pin without the next section showing underneath it, and it only ever
   pins on a wide screen — so the height and the pin share one breakpoint.
   Stated in the stylesheet rather than added by script, so the page is laid
   out correctly at first paint and nothing shifts when app.js arrives. */
@media (min-width: 64rem) and (prefers-reduced-motion: no-preference) {
  .hero-setpiece {
    min-height: 100vh;
  }
}

/* The rail is pinned on the same terms, and was shorter than the screen — so
   the hold showed half a viewport of the NEXT section underneath it, which
   reads as the page having stuck rather than as a set piece. Giving it the
   screen is what makes the pin land. Stated here, under the same two
   conditions that decide whether it pins at all, so there is no layout change
   when the script arrives and none at all for a visitor with motion off. */
@media (min-width: 64rem) and (prefers-reduced-motion: no-preference) {
  .rail {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  .rail-viewport {
    width: 100%;
  }
}

/* The light that follows the pointer across the mattress.

   Clipped to the product half of the frame, which keeps it off the headline
   at every width. It cannot be kept off ALL the hero copy — the facts row is
   a flex row that spans the frame at any size — so the contrast guarantee is
   measured rather than geometric: the gold alpha below is set from the
   rendered pixels with the light parked behind each piece of hero copy at
   full strength and the type hidden, so the background underneath could be
   sampled directly. See the measurement in the motion report.

   It blends with `screen` inside .hero-media, which is its own stacking
   context, so it can only brighten the photograph and can never composite
   over a glyph. */
.hero-spot-clip {
  position: absolute;
  inset: 0 0 0 52%;
  overflow: hidden;
  pointer-events: none;
}
.hero-spot {
  position: absolute;
  left: 0;
  top: 0;
  width: 40rem;
  height: 40rem;
  margin: -20rem 0 0 -20rem;
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  will-change: transform, opacity;
  background: radial-gradient(
    circle closest-side,
    rgba(232, 193, 132, 0.17),
    rgba(232, 193, 132, 0.06) 46%,
    rgba(232, 193, 132, 0) 72%
  );
}

/* Handing the hero's footing rows from the stylesheet's load-in to the set
   piece.

   .hero-sub, .btn-row, .stock-live and .hero-facts are played in by a CSS
   `animation` with fill-mode `both`, and an animation's computed value beats
   an inline style — so while that animation is still attached, nothing GSAP
   writes to transform or opacity on these elements has any effect at all.
   app.js adds .is-setpiece the moment the entrance finishes; from then on the
   animation is off them and the inline styles land. The declarations below
   are the state the entrance left them in, so the instant of handover is
   invisible, and inline style outranks them from that point on. */
.hero-setpiece.is-setpiece .hero-sub,
.hero-setpiece.is-setpiece .btn-row,
.hero-setpiece.is-setpiece .stock-live,
.hero-setpiece.is-setpiece .hero-facts,
.hero-setpiece.is-setpiece .hero-h .rise {
  animation: none;
  opacity: 1;
  transform: none;
}

/* The veil that deepens as the hero hands over. It sits inside .hero-media,
   which is its own stacking context below every word in the hero, so it darkens
   the photograph behind the copy and never composites over a glyph. Rests fully
   transparent — the hero at rest is exactly as the sheet above draws it. */
.hero-veil {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
  /* Near-flat, not a gradient: the copy travels UPWARD across this exit, so
     a veil that thinned toward the top would hand the copy a brighter ground
     the further it went — which is the one thing this must never do. */
  background: linear-gradient(
    to top,
    rgba(4, 7, 13, 0.93) 0%,
    rgba(4, 7, 13, 0.9) 50%,
    rgba(4, 7, 13, 0.88) 100%
  );
}

/* Columns of light that rise through the hero as it hands over to the page.
   They only ever appear in the last stretch of the pin, by which point the
   copy has already travelled away, so they are never over readable text. */
.hero-blind {
  position: absolute;
  inset: 0;
  display: flex;
  gap: clamp(0.5rem, 1.4vw, 1.5rem);
  z-index: 2;
  pointer-events: none;
}
.hero-blind > span {
  flex: 1 1 0;
  min-width: 0;
  opacity: 0;
  transform: scaleY(0);
  transform-origin: bottom center;
  background: linear-gradient(
    to top,
    rgba(232, 193, 132, 0.3),
    rgba(232, 193, 132, 0.07) 52%,
    rgba(232, 193, 132, 0) 100%
  );
}

/* A drawn hairline under each fact in the hero's footing row. Default 1 —
   fully drawn — so a fact that is never animated still wears its rule. */
.hero-facts > div {
  position: relative;
}
.hero-facts > div::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.55rem;
  height: 1px;
  background: linear-gradient(90deg, var(--gold-hair), rgba(232, 193, 132, 0.02));
  transform: scaleX(var(--fact, 1));
  transform-origin: left center;
}

/* ========================================================= the pictures ===
   The strip and split photographs now sit in a .shot-frame, which is the
   fixed box; the picture travels inside it. The frame takes the rounding and
   the edge dissolve that used to be on the image, so the image can move
   without dragging its own soft edge around with it. */
.shot-frame {
  display: block;
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-img);
}
.photo-shot .shot-frame {
  -webkit-mask-image: radial-gradient(126% 126% at 50% 50%, #000 74%, rgba(0, 0, 0, 0.6) 91%, transparent 100%);
  mask-image: radial-gradient(126% 126% at 50% 50%, #000 74%, rgba(0, 0, 0, 0.6) 91%, transparent 100%);
}
.photo-shot .shot-frame img,
.split-media .shot-frame img {
  border-radius: 0;
  -webkit-mask-image: none;
  mask-image: none;
  will-change: transform;
}

/* A line of light rakes down a photograph once as it arrives. Rests at
   opacity 0: it is a one-shot, so "finished" and "never ran" are the same
   picture, and the watchdog clearing its inline styles lands it here. */
.frame-scan {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 42%;
  opacity: 0;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(232, 193, 132, 0) 0%,
    rgba(232, 193, 132, 0.1) 62%,
    rgba(255, 240, 214, 0.42) 88%,
    rgba(232, 193, 132, 0) 100%
  );
}

/* The caption rule under each picture in a strip. */
.cap-rule {
  position: relative;
  padding-bottom: 0.7rem;
}
.cap-rule::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--gold-hair), rgba(232, 193, 132, 0.02));
  transform: scaleX(var(--cap, 1));
  transform-origin: left center;
}
.section-cream .cap-rule::after {
  background: linear-gradient(90deg, rgba(122, 96, 38, 0.34), rgba(122, 96, 38, 0.03));
}

/* ============================================================== the cards ===
   A soft gold light inside the category cards that follows the pointer. A
   real element moved by transform and faded by opacity — compositor work,
   nothing to repaint — and it sits BEHIND the card's own text, which is why
   the copy is lifted onto its own layer. These cards are on the paper
   sections, so the light makes the ground lighter and the ink's contrast goes
   UP, never down. */
.card.lit {
  overflow: hidden;
}
.card.lit > *:not(.card-lit) {
  position: relative;
  z-index: 1;
}
.card-lit {
  position: absolute;
  left: 0;
  top: 0;
  width: 26rem;
  height: 26rem;
  margin: -13rem 0 0 -13rem;
  border-radius: 50%;
  z-index: 0;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  background: radial-gradient(
    circle closest-side,
    rgba(214, 170, 84, 0.2),
    rgba(214, 170, 84, 0.07) 44%,
    rgba(214, 170, 84, 0) 72%
  );
}

/* Cards recede as a group when the grid leaves the screen, so give the
   rotation somewhere to go. */
.grid-cats,
#service-area .grid-3 {
  perspective: 1400px;
}

/* The drawn diamond and lead-in rule on each checklist claim. Default 1. */
.checklist li.ticked::before {
  transform: rotate(45deg) scale(var(--tick, 1));
}
.checklist li.ticked::after {
  content: "";
  position: absolute;
  left: 0.95rem;
  top: 0.85em;
  width: 0.65rem;
  height: 1px;
  background: var(--gold-hair);
  transform: scaleX(var(--tick, 1));
  transform-origin: left center;
}

/* The drawn left edge on the service-area cards. Default 1. */
.card-plain.edged {
  position: relative;
}
.card-plain.edged::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: linear-gradient(to bottom, rgba(122, 96, 38, 0.42), rgba(122, 96, 38, 0.04));
  transform: scaleY(var(--edge, 1));
  transform-origin: top center;
}

/* The horizon under "who we sell to". The row already carries a border; this
   is a gold line that draws along it as the section crosses. Default 1. */
.who-row.horizoned::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -1px;
  height: 1px;
  background: linear-gradient(90deg, rgba(122, 96, 38, 0.5), rgba(122, 96, 38, 0.06));
  transform: scaleX(var(--horizon, 1));
  transform-origin: left center;
}
.who-row.horizoned {
  position: relative;
}

/* ============================================================== the rail ===
   Each frame comes to attention as it reaches the middle of the pinned
   viewport. The rotation needs somewhere to go, and the cards need to be able
   to lift clear of one another. */
.rail.is-focus .rail-track {
  perspective: 1500px;
}
.rail.is-focus .rail-card {
  will-change: transform;
}
.rail-card figcaption {
  position: relative;
}

/* A broad gold wash that travels across the rail as you scroll through the
   colourways, so the pinned stretch has light moving in it and not only
   cards. Behind everything in the rail. */
.rail-spot {
  position: absolute;
  left: -20%;
  right: -20%;
  top: 0;
  bottom: 0;
  z-index: 0;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  background: radial-gradient(
    30% 62% at 50% 52%,
    rgba(232, 193, 132, 0.12),
    rgba(232, 193, 132, 0.03) 52%,
    rgba(232, 193, 132, 0) 78%
  );
}
.rail-viewport {
  position: relative;
  z-index: 1;
}

/* ========================================================== the house label
   #midnight holds while light moves across the product: a bloom behind it
   and a raking highlight along the piping. The copy does not move far and
   never changes opacity — it stays readable for the whole hold. */
.mid-bloom {
  position: absolute;
  inset: -16%;
  z-index: -1;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  background: radial-gradient(
    52% 52% at 50% 50%,
    rgba(232, 193, 132, 0.2),
    rgba(198, 155, 82, 0.07) 44%,
    rgba(232, 193, 132, 0) 74%
  );
}
.mid-rake {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 1;
  pointer-events: none;
  /* The Midnight photograph has no frame — it is composited onto the band and
     its edges dissolve. A rectangle of raking light would hand it the frame
     back, so the light carries the same feather the picture does and fades out
     before it reaches an edge. */
  -webkit-mask-image: radial-gradient(74% 74% at 50% 50%, #000 42%, rgba(0, 0, 0, 0.45) 72%, transparent 100%);
  mask-image: radial-gradient(74% 74% at 50% 50%, #000 42%, rgba(0, 0, 0, 0.45) 72%, transparent 100%);
}
.mid-rake > i {
  position: absolute;
  top: -12%;
  bottom: -12%;
  left: 0;
  width: 26%;
  opacity: 0;
  transform: skewX(-13deg);
  mix-blend-mode: screen;
  will-change: transform, opacity;
  background: linear-gradient(
    90deg,
    rgba(232, 193, 132, 0) 0%,
    rgba(232, 193, 132, 0.12) 40%,
    rgba(255, 243, 219, 0.5) 52%,
    rgba(232, 193, 132, 0.1) 64%,
    rgba(232, 193, 132, 0) 100%
  );
}

/* ============================================================== the band ===
   A gold rule that draws across the head of the pricing band as it arrives. */
.band-rule {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  z-index: 2;
  background: linear-gradient(90deg, rgba(232, 193, 132, 0.04), var(--amber), rgba(232, 193, 132, 0.04));
  transform: scaleX(0);
  transform-origin: center;
  pointer-events: none;
}

/* ============================================================ the footer === */
.footer-h {
  position: relative;
}

/* ------------------------------------------------------- motion turned off
   Everything above already describes the resting state, so there is nothing
   to undo. These are belt and braces: if an inline value were ever left
   behind, the page still reads correctly, and every piece of inserted
   decoration is forced out of the way. */
@media (prefers-reduced-motion: reduce) {
  .page-meter,
  .hero-spot-clip,
  .hero-veil,
  .hero-blind,
  .card-lit,
  .rail-spot,
  .mid-bloom,
  .mid-rake,
  .frame-scan,
  .band-rule {
    display: none !important;
  }
  .hero-facts > div::after,
  .cap-rule::after,
  .checklist li.ticked::before,
  .checklist li.ticked::after,
  .card-plain.edged::after,
  .who-row.horizoned::before {
    transform: none;
  }
  .checklist li.ticked::before {
    transform: rotate(45deg);
  }
}
/* ===== end motion: home ===== */

/* ===== hero legibility ===== */
/* The headline sits at roughly 21-49% of the viewport, and the photograph's
   crescent fell right across the left edge of those three lines at 1.43:1 —
   far under the 3:1 large-text floor. Darkening enough to fix that in place
   erased the crescent, which is the Midnight motif, so the frame is shifted
   instead: the crescent moves clear of the copy column into the open right of
   the frame, and the scrim only has to cover ordinary background. The display
   face keeps a shadow so a viewport that moves the crescent back cannot
   silently reopen the problem. */
.hero-media .hero-bg {
  object-position: 34% 46%;
}
.hero-media::after {
  background:
    radial-gradient(82% 70% at 24% 54%,
      rgba(4, 7, 13, 0.93) 0%,
      rgba(4, 7, 13, 0.78) 42%,
      rgba(4, 7, 13, 0.34) 74%,
      rgba(4, 7, 13, 0) 96%),
    linear-gradient(180deg, rgba(4, 7, 13, 0.14) 0%, rgba(4, 7, 13, 0.2) 44%, rgba(4, 7, 13, 0.88) 90%, var(--night-1) 100%);
}
.hero-h,
.hero-sub {
  text-shadow: 0 1px 30px rgba(4, 7, 13, 0.9), 0 0 8px rgba(4, 7, 13, 0.55);
}
/* ===== end hero legibility ===== */
/* ===== motion: trade =====
   ============================================================================
   MOTION LAYER — the trade pages
   ----------------------------------------------------------------------------
   wholesale.html, contact.html, and the three legal pages (privacy, terms,
   sms). Everything here is scoped under `main.mt`, a class app.js adds only on
   those five pages, so with JavaScript off the class is absent, none of this
   applies, and the pages are byte-for-byte the design they were.

   Same three standing rules as the block above:

   1. Every rule states the FINAL, at-rest value. A decoration's resting state
      is its VISIBLE end — a ring is closed, a hairline is drawn, a circle is
      lit. app.js only ever pushes a value away from that and lets it return,
      so a dead script, a failed tween or motion turned down all land on the
      finished page rather than on a blank one.

   2. Nothing below can hide reading matter. Every value driven here belongs to
      furniture this layer invented — rings, hairlines, washes, ticks, sheens.
      The pages' own words are moved by transform only, never faded from zero
      on a scrub, and never on the legal pages at all.

   3. No pseudo-element is driven. A property registered `inherits: false` does
      not reach ::before or ::after any more than it reaches a child, so every
      animated decoration here is a real element app.js inserts and removes.
   ========================================================================== */

/* --------------------------------------------------- registered properties
   Two, and each is set AND read on the same element: --ignite on the step
   numeral itself, --ring on the ring span that overlays it. Both are driven
   on a scrub, i.e. every frame, so both are registered with inherits:false to
   keep the invalidation off their subtrees — the pattern the seams use. */
@property --ring   { syntax: "<angle>";  inherits: false; initial-value: 360deg; }
@property --ignite { syntax: "<number>"; inherits: false; initial-value: 1; }

/* Static tokens. Plain inherited custom properties on purpose: they are
   written once at parse time and never animated, so there is nothing for an
   inherits:false to save. The cream override is the whole reason they exist —
   the same hairline has to be gold-on-black in one section and gold-on-paper
   in the next. */
.mt {
  --mt-hair: rgba(232, 193, 132, 0.30);
  --mt-hair-soft: rgba(232, 193, 132, 0.16);
  --mt-ring: rgba(244, 221, 174, 0.95);
  --mt-lit: rgba(232, 193, 132, 1);
  --mt-gutter: clamp(0.875rem, 2.2vw, 1.875rem);
}
.mt .section-cream {
  --mt-hair: rgba(122, 96, 38, 0.34);
  --mt-hair-soft: rgba(122, 96, 38, 0.16);
  --mt-ring: rgba(122, 96, 38, 0.92);
  --mt-lit: rgba(122, 96, 38, 1);
}

/* A drawn hairline, in flow. Same idea as .head-rule above: it is a design
   element at rest and only its drawing is animated. */
.mt .mt-rule {
  display: block;
  height: 1px;
  margin-top: clamp(var(--space-5), 2.5vw, var(--space-6));
  background: linear-gradient(90deg, var(--mt-hair), rgba(232, 193, 132, 0));
  transform: scaleX(var(--mt-draw, 1));
  transform-origin: left center;
}
.mt .section-cream .mt-rule {
  background: linear-gradient(90deg, var(--mt-hair), rgba(122, 96, 38, 0));
}

/* ============================================================== page heads
   The one block every trade page shares, and until now the only one that did
   nothing at all on these pages. It gets a raking light on arrival, a wash
   that separates from the type as the head leaves, and a bright rule that
   draws along the hairline the theme already closes it with. */
.mt .page-head > .shell {
  position: relative;
  z-index: 2;
}
.mt .ph-wash,
.mt .ph-rake {
  position: absolute;
  z-index: 0;
  pointer-events: none;
  will-change: transform, opacity;
}
.mt .ph-wash {
  inset: -18% -12%;
  background: radial-gradient(62% 56% at 16% 4%, rgba(201, 169, 97, 0.13), rgba(201, 169, 97, 0) 64%);
}
.mt .ph-rake {
  inset: -40% -60%;
  opacity: 0;
  background: linear-gradient(
    102deg,
    rgba(232, 193, 132, 0) 40%,
    rgba(232, 193, 132, 0.15) 50%,
    rgba(232, 193, 132, 0) 60%
  );
}
/* Rides on top of .page-head::after, which stays exactly as it was — so if
   this never draws, the theme's own hairline is still closing the head. */
.mt .ph-line {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--amber-2) 50%, transparent);
  transform: scaleX(1);
  transform-origin: center;
}

/* ========================================================= the four steps
   The numbered sequence on wholesale.html. A ring closes around each numeral
   and the numeral lights, in order, driven by the wheel — so scrolling back
   up un-draws them 4, 3, 2, 1. The ring is a real element because a property
   with inherits:false would never reach a pseudo. */
.mt .step { position: relative; }
.mt .step-num { position: relative; }
.mt .steps.st-live .step-num {
  background-image:
    radial-gradient(
      136% 136% at 50% 122%,
      rgba(232, 193, 132, calc(0.46 * var(--ignite))),
      rgba(232, 193, 132, 0) 72%
    ),
    linear-gradient(180deg, rgba(244, 221, 174, 0.12), rgba(244, 221, 174, 0.03));
  box-shadow: 0 0 calc(16px * var(--ignite)) rgba(232, 193, 132, calc(0.3 * var(--ignite)));
}
.mt .section-cream .steps.st-live .step-num {
  background-image:
    radial-gradient(
      136% 136% at 50% 122%,
      rgba(201, 169, 97, calc(0.55 * var(--ignite))),
      rgba(201, 169, 97, 0) 72%
    ),
    linear-gradient(180deg, rgba(244, 221, 174, 0.12), rgba(244, 221, 174, 0.03));
  box-shadow: 0 0 calc(14px * var(--ignite)) rgba(122, 96, 38, calc(0.22 * var(--ignite)));
}
.mt .st-ring {
  position: absolute;
  inset: -5px;
  border-radius: 999px;
  pointer-events: none;
  background: conic-gradient(
    from -90deg,
    var(--mt-ring) 0deg,
    var(--mt-ring) var(--ring),
    rgba(0, 0, 0, 0) var(--ring)
  );
  -webkit-mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 2.5px), #000 calc(100% - 2.5px));
          mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 2.5px), #000 calc(100% - 2.5px));
}
/* The ladder between the circles. Only where the steps are a single column —
   stacked, 1 above 2 above 3 — because in the two-column layout the step
   below a circle is not the next step and a thread there would lie. */
.mt .st-thread {
  position: absolute;
  left: 1.25rem;
  top: 2.85rem;
  bottom: calc(-1 * var(--space-8));
  width: 1px;
  pointer-events: none;
  background: linear-gradient(180deg, var(--mt-hair), rgba(232, 193, 132, 0));
  transform: scaleY(1);
  transform-origin: top center;
}
.mt .section-cream .st-thread {
  background: linear-gradient(180deg, var(--mt-hair), rgba(122, 96, 38, 0));
}
@media (min-width: 56rem) {
  .mt .st-thread { display: none; }
}

/* ===================================================== the FAQ disclosures
   The row rules are drawn, in order, on the scroll. They are real spans after
   each <details> rather than its border, because a child of <details> other
   than <summary> is its answer and must not be anything else. The 1px the
   span occupies is pulled straight back off again, so the layout is identical
   to the border it replaces. */
.mt .faq { border-bottom-color: transparent; }
.mt .fq-rule {
  display: block;
  height: 1px;
  margin-top: -1px;
  background: var(--mt-hair-soft);
  transform: scaleX(1);
  transform-origin: left center;
}
/* The summary leans toward the pointer and toward a keyboard. CSS, so it
   needs no script and the reduced-motion block below switches it off. */
.mt .faq summary {
  transition: color 0.25s var(--ease), padding-left 0.3s var(--ease);
}
.mt .faq summary:hover,
.mt .faq summary:focus-visible {
  padding-left: 0.5rem;
  color: var(--amber);
}
.mt .section-cream .faq summary:hover,
.mt .section-cream .faq summary:focus-visible {
  color: var(--gold-ink);
}

/* ========================================================== the lead form
   Entrance choreography and a focus affordance, and nothing else: no motion
   on this card ever competes with somebody typing into it.

   The ink is a free-floating 2px rule that app.js parks under whichever
   control has focus, measured at the moment of focus so it is right at every
   width. It is the only thing that moves. The control itself is never
   transformed, never scrolled, and keeps the outline the theme gives it. */
.mt .field { position: relative; }
.mt .fld-ink {
  position: absolute;
  height: 2px;
  border-radius: 2px;
  pointer-events: none;
  background: linear-gradient(90deg, var(--amber-2), var(--amber));
  transform: scaleX(0);
  transform-origin: left center;
}
.mt .section-cream .fld-ink {
  background: linear-gradient(90deg, var(--gold-ink), rgba(122, 96, 38, 0.45));
}
.mt .form-card input:focus-visible,
.mt .form-card select:focus-visible,
.mt .form-card textarea:focus-visible {
  box-shadow: 0 0 0 3px rgba(232, 193, 132, 0.18);
  transition: box-shadow 0.25s var(--ease);
}
.mt .section-cream .form-card input:focus-visible,
.mt .section-cream .form-card select:focus-visible,
.mt .section-cream .form-card textarea:focus-visible {
  box-shadow: 0 0 0 3px rgba(122, 96, 38, 0.16);
}

/* The info column's rules draw in sequence beside the form. */
.mt .info-card { position: relative; }
.mt .ic-rule {
  position: absolute;
  top: -1px;
  left: -1px;
  right: -1px;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, var(--mt-lit), rgba(232, 193, 132, 0));
  opacity: 0.55;
  transform: scaleX(1);
  transform-origin: left center;
}
.mt .section-cream .ic-rule {
  background: linear-gradient(90deg, var(--mt-lit), rgba(122, 96, 38, 0));
  opacity: 0.4;
}

/* =========================================================== the legal pages
   A ruled margin down the side of the document, filling as you read and
   emptying as you scroll back, with a tick opposite each heading that lights
   as you reach it. Dignified is the brief: nothing bounces, nothing fades up
   from nothing, and the words themselves only ever rise a few pixels.

   The spine lives in the shell's own gutter — it adds no padding, moves no
   text, and is switched off below 48rem where that gutter is too narrow to
   hold it without crowding the measure. */
.mt .legal { position: relative; }
.mt .lg-spine {
  position: absolute;
  left: calc(-1 * var(--mt-gutter));
  top: 0;
  bottom: 0;
  width: 1px;
  pointer-events: none;
  background: var(--mt-hair-soft);
}
.mt .lg-fill {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(122, 96, 38, 0.55), rgba(122, 96, 38, 0.2));
  transform: scaleY(1);
  transform-origin: top center;
}
.mt .lg-tick {
  position: absolute;
  left: -3px;
  width: 7px;
  height: 7px;
  margin-top: -3px;
  border-radius: 999px;
  background: var(--cream);
  border: 1px solid rgba(122, 96, 38, 0.55);
  pointer-events: none;
}
@media (max-width: 47.999rem) {
  .mt .lg-spine { display: none; }
}

/* The callout's gold edge draws down, and the dateline's rule draws across. */
.mt .legal-callout { position: relative; }
.mt .lg-edge {
  position: absolute;
  left: -2px;
  top: 0;
  bottom: 0;
  width: 2px;
  pointer-events: none;
  background: var(--gold);
  transform: scaleY(1);
  transform-origin: top center;
}

/* ============================================================== the CTA band
   One pass of warm light across the gold button as the band arrives. The
   sheen only ever LIGHTENS a light button carrying dark text, so the contrast
   through the sweep is higher than at rest, not lower. */
.mt .band .btn-gold {
  position: relative;
  overflow: hidden;
}
.mt .bd-sheen {
  position: absolute;
  top: -60%;
  bottom: -60%;
  width: 45%;
  left: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    102deg,
    rgba(255, 250, 238, 0) 0%,
    rgba(255, 250, 238, 0.5) 50%,
    rgba(255, 250, 238, 0) 100%
  );
}

/* A scanline that passes down the dealer-portal cards once, as they arrive. */
.mt .pf-stage { position: relative; }
.mt .pf-scan {
  position: absolute;
  left: -2%;
  right: -2%;
  height: 46%;
  top: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    180deg,
    rgba(232, 193, 132, 0) 0%,
    rgba(232, 193, 132, 0.1) 55%,
    rgba(232, 193, 132, 0) 100%
  );
}
/* The scanline passes BEHIND the cards, never over them: a wash across a
   dark card would lighten its ground and cost the body copy contrast. */
.mt .pf-stage > *:not(.pf-scan) {
  position: relative;
  z-index: 1;
}

/* ------------------------------------------------------- motion turned off
   Every rule above already describes the finished state, so there is nothing
   here to undo. These are belt and braces, for the case where an inline value
   is somehow left behind. */
@media (prefers-reduced-motion: reduce) {
  .mt .st-ring { --ring: 360deg; }
  .mt .steps.st-live .step-num { --ignite: 1; }
  .mt .mt-rule,
  .mt .fq-rule,
  .mt .ic-rule,
  .mt .ph-line,
  .mt .st-thread,
  .mt .lg-fill,
  .mt .lg-edge {
    transform: none;
  }
  .mt .ph-rake,
  .mt .bd-sheen,
  .mt .pf-scan {
    display: none;
  }
  .mt .faq summary { transition: none; }
  .mt .faq summary:hover,
  .mt .faq summary:focus-visible { padding-left: 0; }
  .mt .form-card input:focus-visible,
  .mt .form-card select:focus-visible,
  .mt .form-card textarea:focus-visible { transition: none; }
}
/* ===== end motion: trade ===== */

/* ===== motion: label ===== */
/* ============================================================================
   MOTION — Midnight Legacy and the catalogue
   ----------------------------------------------------------------------------
   Page-scoped layer for midnight-legacy.html and products.html. Same contract
   as the block above: every rule here states the FINAL, at-rest look of the
   thing it touches, so both pages are correct with JavaScript off, with GSAP
   missing, and with motion turned down. app.js only ever pushes a value away
   from rest and lets it come back.

   Nothing here may hide content. Where a value could, the default is the
   visible end of the range.
   ========================================================================== */

/* --------------------------------------------------- registered properties
   inherits:false for the same reason the seams above are registered: a plain
   custom property is inherited, so writing one on a container every frame
   invalidates the computed style of its entire subtree. Each of these is set
   and read on one element, and saying so lets the engine skip the subtree. */
@property --spine   { syntax: "<number>";     inherits: false; initial-value: 1; }
@property --ignite  { syntax: "<number>";     inherits: false; initial-value: 1; }

/* ======================================================= the cutaway stage
   The three exploded diagrams are the centre of this page and were, until
   now, three flat pictures.

   Each is ONE .webp: the stack of layers drawn on the left, the leader lines
   and their names on the right, and a column of pure white between the two
   that runs the full height of the file (x=652 to x=711 of 1600, in all
   three). That gutter is the whole trick. The motion layer stops treating the
   file as one picture and starts treating it as a set of windows onto the
   same picture — the artwork through one window, and each label through a
   window of its own, cut on rows that are white edge to edge. The windows
   tile the file exactly, so with all of them in place the composite is the
   original image, pixel for pixel.

   No artwork is redrawn, recut, re-rendered or traced, and no label is
   edited: the one file is simply looked at through several windows, and the
   windows are then moved. What moves is a clip-path inset and a transform.

   At rest — no JavaScript, no GSAP, motion turned down — none of this exists.
   app.js builds the clones inside the motion branch only and removes them on
   cleanup, and the original <img> is left completely alone. Everything below
   is inert until something is put inside it. */
.build-media.bd-stage {
  /* The same padding the panel already had, named, so the clones can be laid
     on the picture rather than on the panel. An absolutely positioned child is
     placed against the PADDING box, so a clone insetting to 0 would sit a mat
     width above and to the left of the photograph it is a copy of — and, worse,
     clip-path resolves its percentages against the element's own border box,
     so every band would be cut in the wrong place. Insetting by the padding
     instead makes each clone's box exactly the original image's box, which is
     what makes the percentages below mean the same thing for all of them. */
  --bd-pad: clamp(var(--space-4), 2.5vw, var(--space-10));
  padding: var(--bd-pad);
  position: relative;
}
/* Selector deliberately heavier than `.build-media img`, which already sets
   width:100%/height:auto on everything in the panel and would otherwise win
   on specificity and blow the clone up to the full panel width -- measured,
   that is what put every label about 40px right and 6px low of its leader
   line, because the band percentages were then resolving against the wrong
   box. The clone must be the ORIGINAL IMAGE'S box, exactly. */
.build-media img.bd-piece {
  position: absolute;
  left: var(--bd-pad);
  top: var(--bd-pad);
  /* Stated outright, not left to inset:0 with auto sizing. An absolutely
     positioned REPLACED element resolves width:auto to the file's intrinsic
     width, not to the box its offsets describe -- which would make every
     clone 1600px wide, and would resolve each band's percentages against a
     1600x1240 box instead of the box the original image actually occupies.
     Measured, that put the labels about 40px right and 6px low of where they
     belong. These two lines are exactly the original image's content box. */
  width: calc(100% - 2 * var(--bd-pad));
  height: calc(100% - 2 * var(--bd-pad));
  max-width: none;
  display: block;
  pointer-events: none;
  /* A clone is decoration. The original <img> keeps the alt text and is the
     only copy a screen reader, or a browser with images turned off, meets. */
}

/* The travelling light: a soft gold band that runs down the artwork column as
   the stack assembles, so the build has a leading edge instead of simply
   appearing. A real element carrying a STATIC gradient, moved by transform
   and faded by opacity — both compositor work, nothing to repaint per frame.
   The panel already clips, so it cannot spill. */
.bd-beam {
  position: absolute;
  left: var(--bd-pad);
  top: var(--bd-pad);
  width: 40%;
  height: 22%;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  will-change: transform, opacity;
  background: linear-gradient(
    to bottom,
    rgba(198, 155, 82, 0) 0%,
    rgba(232, 193, 132, 0.4) 40%,
    rgba(255, 246, 228, 0.8) 50%,
    rgba(232, 193, 132, 0.4) 60%,
    rgba(198, 155, 82, 0) 100%
  );
  /* The diagrams are drawn on white, so the light has to darken toward gold
     rather than add to a ground that is already at maximum. */
  mix-blend-mode: multiply;
}

/* ------------------------------------------------------------- the spine
   A gold hairline down the side of the layers section, and of the catalogue
   list, drawn as you pass it. It gathers three diagrams, or five categories,
   into one run instead of three or five separate arrivals.

   Built by app.js, so it does not exist without JavaScript and cannot leave a
   stray line behind. scaleY rests at 1 — fully drawn — so a spine that is
   created and never animated still reads as a design rule rather than a
   missing one. */
.mo-spine-host { position: relative; }
.mo-spine {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(232, 193, 132, 0.05),
    var(--gold-hair) 14%,
    var(--gold-hair) 86%,
    rgba(232, 193, 132, 0.05)
  );
  transform: scaleY(var(--spine, 1));
  transform-origin: top center;
}
.section-cream .mo-spine {
  background: linear-gradient(
    to bottom,
    rgba(122, 96, 38, 0.04),
    rgba(122, 96, 38, 0.3) 14%,
    rgba(122, 96, 38, 0.3) 86%,
    rgba(122, 96, 38, 0.04)
  );
}

/* ------------------------------------------------------- the crescent node
   The catalogue's five crescents light as the spine reaches them. --ignite
   rests at 1, so a crescent that is never animated wears exactly the bloom
   the stylesheet above already gave it, unchanged. */
.cat-index .crescent {
  filter: drop-shadow(
    0 0 calc(12px * var(--ignite, 1)) rgba(232, 193, 132, calc(0.45 * var(--ignite, 1)))
  );
}

/* --------------------------------------------------------- the light sweep
   A band of warm light that crosses a section once, as it arrives.

   Built the way .band-glow above is built, and for the same reason: driving a
   gradient's stop positions through a custom property repaints the gradient on
   every frame. Measured on the catalogue at 6x CPU throttle, that showed up in
   the tail -- the 95th-percentile frame went from 100ms to 121ms. Here the
   gradient is STATIC and oversized, and what moves is a transform on the
   element carrying it, with opacity doing the fade. Both are compositor work,
   so the per-frame cost is nil.

   The travelling element is wider than its frame, so the frame clips it: the
   clipping lives on .mo-sweep, which is itself inset to 0, and NOT on the
   host -- a host told to hide its overflow would crop its own decoration. No
   page can gain a sideways scroll from a sweep.

   Opacity rests at 0, so a sweep can only ever ADD light to a section that is
   already fully there, and never take any away.

   The three hosts are all near-black grounds, where a 0.16 wash is simply not
   visible -- it was built at that value first and measured as imperceptible,
   which is not worth the element. At 0.34 it reads. Because the sweep sits at
   z-index -1 inside the host's own stacking context it passes BEHIND every
   card and every panel, so the only type it can ever light is the type
   sitting straight on the section ground -- which carries 17.9:1 of headroom.
   Measured on the rendered pixels at the brightest point of its travel, the
   worst reading anywhere under a sweep is well clear of the 4.5:1 required.
   The hero photograph gets no sweep at all -- see the note above. */
.mo-sweep {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
}
.mo-sweep > i {
  position: absolute;
  top: -12%;
  bottom: -12%;
  left: -62%;
  width: 224%;
  display: block;
  will-change: transform;
  background: linear-gradient(
    104deg,
    rgba(232, 193, 132, 0) 36%,
    rgba(198, 155, 82, 0.16) 44%,
    rgba(244, 221, 174, 0.34) 50%,
    rgba(198, 155, 82, 0.16) 56%,
    rgba(232, 193, 132, 0) 64%
  );
}

/* ------------------------------------------------------------- perspective
   The tier cards and the feature cards tip a few degrees as they arrive and
   again as they leave. The perspective has to live on the parent; the
   rotation itself is written by app.js and cleared when it is finished. */
.mo-deck {
  perspective: 1400px;
  perspective-origin: 50% 50%;
}

/* ------------------------------------------------------- motion turned off
   Everything above already describes the resting state, so there is nothing
   to undo. Belt and braces: if an inline value were ever left behind, or a
   clone somehow outlived a cleanup, both pages still read correctly — the
   clones go, the original image stays, the hairlines stay drawn. */
@media (prefers-reduced-motion: reduce) {
  .build-media img.bd-piece,
  .bd-beam,
  .mo-sweep {
    display: none;
  }
  .mo-spine {
    transform: none;
  }
  .cat-index .crescent {
    filter: drop-shadow(0 0 12px rgba(232, 193, 132, 0.45));
  }
  .mo-deck {
    perspective: none;
  }
}
/* ===== end motion: label ===== */

/* ===== hero legibility: midnight + tablet ===== */
/* Same defect as the homepage hero, found by the same image-aware check: the
   Midnight scrim is a radial centred at 20% 66%, and the copy block sits above
   and left of that core, so the tagline landed on the photograph's lit quilting
   at 1.00:1 and the kicker at 1.18:1. Widened and re-centred onto the copy. */
.me-hero-media::after {
  background:
    radial-gradient(96% 86% at 26% 46%,
      rgba(4, 7, 13, 0.95) 0%,
      rgba(4, 7, 13, 0.88) 36%,
      rgba(4, 7, 13, 0.56) 66%,
      rgba(4, 7, 13, 0.14) 88%,
      rgba(4, 7, 13, 0) 100%),
    linear-gradient(180deg, rgba(4, 7, 13, 0.12) 0%, rgba(4, 7, 13, 0.2) 46%, rgba(4, 7, 13, 0.86) 90%, var(--night-1) 100%);
}
.display-hero,
.me-hero .tagline,
.me-hero .hero-sub,
.me-hero .kicker {
  text-shadow: 0 1px 30px rgba(4, 7, 13, 0.92), 0 0 9px rgba(4, 7, 13, 0.62);
}
/* Between about 52rem and 64rem the homepage copy column runs wider and its
   sub-heading reaches the mattress highlight, which the desktop ellipse does
   not cover. */
@media (min-width: 40rem) and (max-width: 64rem) {
  .hero-media::after {
    background:
      radial-gradient(118% 88% at 30% 52%,
        rgba(4, 7, 13, 0.95) 0%,
        rgba(4, 7, 13, 0.86) 44%,
        rgba(4, 7, 13, 0.5) 74%,
        rgba(4, 7, 13, 0) 98%),
      linear-gradient(180deg, rgba(4, 7, 13, 0.14) 0%, rgba(4, 7, 13, 0.2) 44%, rgba(4, 7, 13, 0.88) 90%, var(--night-1) 100%);
  }
}
/* ===== end hero legibility: midnight + tablet ===== */

/* Below 40rem the Midnight copy sits over the brightest part of the quilting,
   and the tagline measured 2.93:1 against a 3:1 floor. */
@media (max-width: 40rem) {
  .me-hero-media::after {
    background:
      radial-gradient(130% 78% at 42% 46%,
        rgba(4, 7, 13, 0.96) 0%,
        rgba(4, 7, 13, 0.9) 42%,
        rgba(4, 7, 13, 0.6) 72%,
        rgba(4, 7, 13, 0.1) 94%),
      linear-gradient(180deg, rgba(4, 7, 13, 0.14) 0%, rgba(4, 7, 13, 0.24) 46%, rgba(4, 7, 13, 0.86) 90%, var(--night-1) 100%);
  }
}

/* ===== hero alignment ===== */
/* Gray, on the preview: "move these title to right side of page" — the title
   only. The three headline lines go right; the paragraph, buttons, stock line
   and facts row stay where they were, on the left.

   That splits the copy across the frame, so the scrim has to cover the top
   right AND the middle left while leaving the mattress readable between them.
   One wide ellipse biased high does both; the values below are the ones that
   measured clean, not the ones that looked about right. */
@media (min-width: 60rem) {
  .hero-h {
    text-align: right;
    justify-items: end;
    margin-left: auto;
    max-width: min(52rem, 100%);
  }
  .hero-media .hero-bg { object-position: 50% 44%; }
  /* Two pools rather than one field: one under the headline top right, one
     under the paragraph and buttons on the left. Between and below them the
     photograph is left alone, so the mattress and the crescent still read. */
  .hero-media::after {
    background:
      radial-gradient(58% 46% at 74% 24%,
        rgba(4, 7, 13, 0.93) 0%, rgba(4, 7, 13, 0.74) 52%, rgba(4, 7, 13, 0) 88%),
      radial-gradient(52% 40% at 22% 62%,
        rgba(4, 7, 13, 0.92) 0%, rgba(4, 7, 13, 0.72) 54%, rgba(4, 7, 13, 0) 90%),
      linear-gradient(180deg, rgba(4, 7, 13, 0.16) 0%, rgba(4, 7, 13, 0.2) 44%, rgba(4, 7, 13, 0.88) 90%, var(--night-1) 100%);
  }
}
/* ===== end hero alignment ===== */

/* ===== pricing band colour ===== */
/* Gray, on the preview: "why is brown used here". It was mine — I warmed the
   band to espresso so the dark stretches were not all one blue. The cream and
   navy alternation already does that job, so the brown was belt and braces,
   and against navy and gold it reads muddy. The band drops to the deepest
   night instead: it still separates from the navy sections, by depth rather
   than by hue, and the gold call to action carries the warmth on its own. */
.band { background: var(--night-0); }
/* ===== end pricing band colour ===== */

/* ===== rail: auto-roll ===== */
/* The heading and the closing call to action moved out of the track, because a
   marquee would carry them past over and over. They sit above and below the
   strip now; only the colourways travel. */
.rail-lead {
  /* It was sized as a card slot (min(78vw, 26rem)) while it lived inside the
     track. Out here it is a section head and takes the shell's width. */
  width: auto;
  flex: initial;
  padding-block: clamp(var(--space-10), 5vw, var(--space-16)) var(--space-8);
}
.rail-lead p { max-width: 46ch; }
.rail-end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-5) var(--space-8);
  padding-block: var(--space-8) clamp(var(--space-10), 5vw, var(--space-16));
}
.rail-end-h { margin: 0; }
/* While it rolls, the strip is driven by transform, so the native scroller and
   its snap points are handed back only when the drift is off. */
.rail.is-rolling .rail-viewport {
  overflow-x: hidden;
  scroll-snap-type: none;
  padding-block: 0;
}
.rail.is-rolling .rail-track { width: max-content; }
/* The clones are decoration; nothing in them should be reachable or read. */
.rail-card.is-clone { pointer-events: none; }
/* The edges of the strip fade into the ground so cards enter and leave rather
   than being cut off by the viewport. */
.rail.is-rolling .rail-viewport {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
/* ===== end rail: auto-roll ===== */

/* ===== hero entrance (scripted) ===== */
/* The CSS entrance above uses animation-fill-mode: both, which outranks inline
   style for the properties it animates — so GSAP cannot drive these lines while
   it is on them. JS adds .is-scripted the moment it takes over, and only then.
   If the script never runs, the CSS entrance plays exactly as before. */
.hero.is-scripted .hero-h .rise,
.hero.is-scripted .hero-sub,
.hero.is-scripted .btn-row,
.hero.is-scripted .stock-live,
.hero.is-scripted .hero-facts {
  animation: none;
}
/* The shake moves the hero's own layers, never the document, so it cannot
   produce a scrollbar. .hero already clips. */
.hero-quake { will-change: transform; }
/* ===== end hero entrance (scripted) ===== */
