﻿/* ==========================================================================
   ULTIMATE CHESS â€” style.css
   Core design system: tokens, typography, layout, components.
   Animation lives in animation.css Â· breakpoints live in responsive.css
   ========================================================================== */

:root {
  --ink: #050506;
  --charcoal: #0c0c0f;
  --slate2: #141419;
  --smoke: #1d1d24;

  --gold: #c9a227;
  --gold-lite: #e8cf82;
  --gold-deep: #8a6d15;

  --silver: #c8ccd4;
  --silver-lt: #eef1f6;

  --line: rgba(255, 255, 255, 0.09);
  --line-soft: rgba(255, 255, 255, 0.05);

  --ease-luxe: cubic-bezier(0.19, 1, 0.22, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);

  --pad-x: clamp(20px, 4vw, 56px);
  --sec-y: clamp(32px, 4.4vw, 70.4px);

  /* ---------- Antique chessboard palette ----------
     Dark square = aged chocolate/rosewood, light square = worn boxwood gold.
     Kept deliberately low-contrast: the board is a backdrop, not a subject.
     At rest the two squares sit close together so the pattern never competes
     with copy; the 3D lift below re-introduces contrast only where the cursor
     is, which is the one place the board is meant to be looked at. */
  --board-dark: #241408;
  --board-light: #402711;
  --board-size: 128px;

  /* Face shading for the lifted squares. These are strong on purpose — they
     only ever apply to a raised square, never to the resting backdrop. */
  --board-dark-lit: #6a4018;
  --board-light-lit: #a8712d;
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* overflow-x on <body> alone is ignored while <html> stays scrollable, so
     the clip has to live here for decorative bleed to stop moving the page.
     Must be `clip`, not `hidden`: `hidden` turns this into a scroll container,
     which makes it the containing block for position:sticky and breaks the
     pinned materials/heritage scenes. `clip` blocks the bleed without that. */
  overflow-x: clip;
  max-width: 100%;
}
html.lenis,
html.lenis body {
  height: auto;
}
.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}
.lenis.lenis-stopped {
  overflow: hidden;
}

body {
  margin: 0;
  background: var(--board-dark);
  color: var(--silver-lt);
  overflow-x: clip;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---------- Site-wide chessboard backdrop ----------
   conic-gradient with hard 25% colour stops gives four exact quadrants, so a
   tile half the cell pitch produces crisp squares with no antialiased seams.
   (The older 45deg linear-gradient trick renders as soft triangles at these
   sizes — the diagonal edges never resolve cleanly.)
   position:fixed so it stays put while content scrolls over it — the board
   is the table the site sits on, not a scrolling element. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -10;
  pointer-events: none;
  background-color: var(--board-dark);
  background-image: conic-gradient(
    var(--board-light) 0 25%,
    var(--board-dark) 0 50%,
    var(--board-light) 0 75%,
    var(--board-dark) 0
  );
  background-size: var(--board-size) var(--board-size);
}

/* Warm lamplight over the board: gold bloom top-centre falling to near-black
   at the edges, so squares stay visible without ever fighting the copy. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -9;
  pointer-events: none;
  background:
    radial-gradient(
      120% 80% at 50% 0%,
      rgba(232, 207, 130, 0.1),
      transparent 55%
    ),
    radial-gradient(
      150% 120% at 50% 45%,
      rgba(18, 10, 4, 0.46),
      rgba(12, 7, 3, 0.72) 72%,
      rgba(8, 5, 2, 0.86)
    );
}

body.is-locked {
  overflow: hidden;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}
a {
  color: inherit;
  text-decoration: none;
}
button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}
:where(h1, h2, h3, h4) {
  margin: 0;
}
/* Headings stay in normal case site-wide. Small eyebrows, nav links, buttons
   and labels keep their uppercase treatment â€” this targets headings only. */
h1,
h2,
h3,
h4,
h5,
h6,
.section-title,
.product-name,
.card-title,
.hs-title,
.ms-title,
.foot-head {
  text-transform: none;
  overflow-wrap: break-word;
}
p {
  margin: 0;
}
ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---------- Focus / a11y ---------- */
:focus {
  outline: none;
}
:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 4px;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 400;
  transform: translateY(-200%);
  padding: 11.2px 19.2px;
  border-radius: 999px;
  background: var(--gold);
  color: var(--ink);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: transform 0.3s var(--ease-soft);
}
.skip-link:focus {
  transform: translateY(0);
}

/* ---------- Scrollbar ---------- */
::-webkit-scrollbar {
  width: 9px;
  height: 9px;
}
::-webkit-scrollbar-track {
  background: var(--ink);
}
::-webkit-scrollbar-thumb {
  background: linear-gradient(var(--gold-deep), var(--gold));
  border-radius: 9px;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--gold-lite);
}

/* ==========================================================================
   LAYOUT
   ========================================================================== */
.wrap {
  width: 100%;
  max-width: 1700px;
  margin-inline: auto;
  padding-inline: var(--pad-x);
}
.section-pad {
  padding-block: var(--sec-y);
  position: relative;
  /* Glow orbs are deliberately offset past the edges; clip them here so the
     bleed stays decorative instead of widening the document. */
  overflow-x: clip;
}

/* ---------- Texture & atmosphere ---------- */
.grain {
  pointer-events: none;
  opacity: 0.5;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}
.glow-orb {
  position: absolute;
  width: min(736px, 90vw);
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(120px);
  pointer-events: none;
  z-index: -1;
}
.glow-orb--gold {
  background: radial-gradient(
    circle,
    rgba(201, 162, 39, 0.17),
    transparent 68%
  );
}
.glow-orb--silver {
  background: radial-gradient(
    circle,
    rgba(200, 204, 212, 0.09),
    transparent 68%
  );
}

.video-sheen {
  background: linear-gradient(
    115deg,
    transparent 35%,
    rgba(255, 255, 255, 0.045) 50%,
    transparent 65%
  );
  background-size: 280% 100%;
}

/* ==========================================================================
   TYPOGRAPHY
   ========================================================================== */
.section-title {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 500;
  /* Cormorant's small x-height and long extenders want tighter leading than a
     sans at the same size, and no negative tracking. */
  line-height: 1.05;
  letter-spacing: 0;
  color: var(--silver-lt);
  font-size: clamp(33.6px, 5.4vw, 60.2px);
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 14.4px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.08px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--gold);
}
.eyebrow::before {
  content: "";
  width: 38.4px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold));
}
.text-gradient-gold {
  background: linear-gradient(
    100deg,
    var(--gold-deep),
    var(--gold-lite) 42%,
    var(--gold) 72%,
    var(--gold-lite)
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ==========================================================================
   HEADER / NAV
   ========================================================================== */
/* The hide/show slide is a compositor-only transform. `will-change` and the
   backface hint keep the bar on its own layer so the blur behind it is not
   re-rasterised every frame, which is what made the text shimmer during the
   slide. The transition lives on the base element, not on `.is-hidden`, so
   both directions are animated rather than only the hide. */
#siteHeader {
  transition: transform 0.42s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: transform;
  backface-visibility: hidden;
}
#siteHeader.is-solid {
  background: rgba(5, 5, 6, 0.72);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  border-bottom: 1px solid var(--line-soft);
}
#siteHeader.is-hidden {
  transform: translateY(-104%);
}

/* --- Sticky (condensed) header ---------------------------------------------
   The inner bar's padding comes from Tailwind utilities (py-5 / lg:py-7).
   Once #siteHeader picks up .is-solid on scroll we shrink that padding and the
   logo lockup so the bar loses roughly a third of its height. Everything stays
   in the same flex row, so menu/logo alignment is untouched. */
#siteHeader > div {
  transition: padding 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}
#siteHeader .logo-mark,
#siteHeader .logo-mark img {
  transition:
    height 0.45s cubic-bezier(0.4, 0, 0.2, 1),
    width 0.45s cubic-bezier(0.4, 0, 0.2, 1),
    transform 0.5s;
}
#siteHeader .logo-mark + span > span {
  transition: font-size 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}

#siteHeader.is-solid > div {
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}
#siteHeader.is-solid .logo-mark,
#siteHeader.is-solid .logo-mark img {
  height: 2rem;
  width: 2rem;
}

.nav-link {
  position: relative;
  font-size: 12.48px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(200, 204, 212, 0.7);
  transition: color 0.35s var(--ease-soft);
}
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -8px;
  width: 100%;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.45s var(--ease-luxe);
}
.nav-link:hover {
  color: var(--silver-lt);
}
.nav-link:hover::after {
  transform: scaleX(1);
  transform-origin: left;
}

.icon-btn {
  display: grid;
  place-items: center;
  width: 42.4px;
  height: 42.4px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--silver);
  transition:
    border-color 0.35s,
    color 0.35s,
    background 0.35s,
    transform 0.35s;
}
.icon-btn:hover {
  border-color: rgba(201, 162, 39, 0.55);
  color: var(--gold);
  background: rgba(201, 162, 39, 0.07);
  transform: translateY(-2px);
}

.burger {
  display: block;
  width: 16.8px;
}
.burger i {
  display: block;
  height: 1.4px;
  background: currentColor;
  border-radius: 2px;
  transition:
    transform 0.4s var(--ease-luxe),
    opacity 0.3s;
}
.burger i + i {
  margin-top: 4px;
}
#menuToggle.is-open .burger i:nth-child(1) {
  transform: translateY(5.4px) rotate(45deg);
}
#menuToggle.is-open .burger i:nth-child(2) {
  opacity: 0;
}
#menuToggle.is-open .burger i:nth-child(3) {
  transform: translateY(-5.4px) rotate(-45deg);
}

.mobile-link {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding-block: 13.6px;
  border-bottom: 1px solid var(--line-soft);
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 11.2px;
  letter-spacing: 0.24em;
  color: var(--gold);
  transition: padding-left 0.4s var(--ease-luxe);
}
.mobile-link span {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: clamp(25.6px, 7vw, 38.4px);
  letter-spacing: 0;
  color: var(--silver-lt);
}
.mobile-link:hover {
  padding-left: 14.4px;
}
.mobile-link:hover span {
  color: var(--gold-lite);
}

/* ==========================================================================
   BUTTONS
   ========================================================================== */
.btn-primary,
.btn-ghost,
.btn-line,
.btn-magnetic {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9.6px;
  border-radius: 999px;
  font-size: 12.16px;
  font-weight: 600;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  isolation: isolate;
  transition:
    transform 0.45s var(--ease-luxe),
    box-shadow 0.45s,
    color 0.4s,
    border-color 0.4s;
  will-change: transform;
}
.btn-primary {
  padding: 17.6px 38.4px;
  color: var(--ink);
  background: linear-gradient(
    100deg,
    var(--gold-deep),
    var(--gold) 45%,
    var(--gold-lite)
  );
  box-shadow: 0 10px 34px -14px rgba(201, 162, 39, 0.65);
}
.btn-primary::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    100deg,
    var(--gold-lite),
    var(--gold) 55%,
    var(--gold-deep)
  );
  opacity: 0;
  transition: opacity 0.5s var(--ease-soft);
}
.btn-primary:hover {
  transform: translateY(-3px);
  box-shadow: 0 20px 48px -14px rgba(201, 162, 39, 0.8);
}
.btn-primary:hover::before {
  opacity: 1;
}

.btn-ghost,
.btn-magnetic {
  padding: 17.6px 38.4px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: var(--silver-lt);
  background: rgba(255, 255, 255, 0.02);
  backdrop-filter: blur(8px);
}
.btn-magnetic {
  padding: 13.6px 27.2px;
  font-size: 11.2px;
}
.btn-ghost:hover,
.btn-magnetic:hover {
  transform: translateY(-3px);
  border-color: rgba(201, 162, 39, 0.6);
  color: var(--gold-lite);
  box-shadow: 0 16px 40px -20px rgba(201, 162, 39, 0.7);
}

.btn-line {
  padding: 14.4px 25.6px;
  border: 1px solid var(--line);
  color: var(--silver);
  background: transparent;
  font-size: 10.88px;
}
.btn-line:hover {
  border-color: var(--gold);
  color: var(--gold-lite);
  background: rgba(201, 162, 39, 0.06);
  transform: translateY(-2px);
}

.rail-btn {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--silver);
  transition: 0.4s var(--ease-soft);
}
.rail-btn:hover {
  background: var(--gold);
  color: var(--ink);
  border-color: var(--gold);
  transform: translateY(-2px);
}

/* ==========================================================================
   COLLECTION CARDS
   ========================================================================== */
.collection-card {
  position: relative;
  display: flex;
  min-height: 320px;
  overflow: hidden;
  border-radius: 24px;
  border: 1px solid var(--line);
  background: var(--slate2);
  transform-style: preserve-3d;
  transition:
    transform 0.7s var(--ease-luxe),
    box-shadow 0.7s,
    border-color 0.5s;
}
.collection-card:hover {
  border-color: rgba(201, 162, 39, 0.4);
  box-shadow:
    0 44px 90px -46px rgba(0, 0, 0, 0.95),
    0 0 60px -30px rgba(201, 162, 39, 0.5);
}
.card-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform: scale(1.02);
  transition:
    transform 1.3s var(--ease-luxe),
    filter 0.8s;
  filter: grayscale(0.42) brightness(0.72);
  -webkit-transition:
    transform 1.3s var(--ease-luxe),
    filter 0.8s;
  -moz-transition:
    transform 1.3s var(--ease-luxe),
    filter 0.8s;
  -ms-transition:
    transform 1.3s var(--ease-luxe),
    filter 0.8s;
  -o-transition:
    transform 1.3s var(--ease-luxe),
    filter 0.8s;
}
.collection-card:hover .card-img {
  transform: scale(1.14);
  filter: grayscale(0) brightness(0.88);
}
.card-veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(5, 5, 6, 0.15) 0%,
    rgba(5, 5, 6, 0.55) 45%,
    rgba(5, 5, 6, 0.96) 100%
  );
}
.card-border {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    130deg,
    transparent 30%,
    rgba(201, 162, 39, 0.75),
    transparent 70%
  );
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.55s var(--ease-soft);
}
.collection-card:hover .card-border {
  opacity: 1;
}

.card-body {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: clamp(24px, 3vw, 41.6px);
  width: 100%;
}
.card-index {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 10.4px;
  letter-spacing: 0.3em;
  color: var(--gold);
}
.card-title {
  margin-top: 11.2px;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(21.6px, 2.6vw, 35.2px);
  color: var(--silver-lt);
}
.card-copy {
  margin-top: 12px;
  max-width: 416px;
  font-size: 13.6px;
  line-height: 1.65;
  color: rgba(200, 204, 212, 0.62);
}
.card-cta {
  margin-top: 25.6px;
  display: inline-flex;
  align-items: center;
  gap: 8.8px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.56px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold-lite);
}
.card-cta i {
  font-style: normal;
  transition: transform 0.45s var(--ease-luxe);
}
.collection-card:hover .card-cta i {
  transform: translateX(8px);
}

/* ==========================================================================
   PRODUCT CARDS
   ========================================================================== */
.product-card {
  border: 1px solid var(--line);
  border-radius: 21.6px;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.035),
    rgba(255, 255, 255, 0)
  );
  overflow: hidden;
  transform-style: preserve-3d;
  transition:
    transform 0.7s var(--ease-luxe),
    border-color 0.5s,
    box-shadow 0.7s;
}
.product-card:hover {
  border-color: rgba(201, 162, 39, 0.42);
  box-shadow:
    0 40px 80px -44px rgba(0, 0, 0, 0.95),
    0 0 55px -34px rgba(201, 162, 39, 0.55);
}
.product-media {
  position: relative;
  aspect-ratio: 4/5;
  overflow: hidden;
  background: var(--slate2);
}
.product-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: grayscale(0.3) brightness(0.82);
  transition:
    transform 1.2s var(--ease-luxe),
    filter 0.7s;
}
.product-card:hover .product-img {
  transform: scale(1.11);
  filter: grayscale(0) brightness(1);
}

.badge-tag {
  position: absolute;
  top: 16px;
  left: 16px;
  padding: 6.4px 12.8px;
  border-radius: 999px;
  border: 1px solid rgba(201, 162, 39, 0.4);
  background: rgba(5, 5, 6, 0.62);
  backdrop-filter: blur(10px);
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 9.28px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold-lite);
}
.quick-view {
  position: absolute;
  left: 50%;
  bottom: 19.2px;
  transform: translate(-50%, 150%);
  padding: 12.8px 25.6px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(5, 5, 6, 0.72);
  backdrop-filter: blur(14px);
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.08px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--silver-lt);
  opacity: 0;
  transition:
    transform 0.55s var(--ease-luxe),
    opacity 0.45s,
    background 0.35s,
    color 0.35s;
  white-space: nowrap;
}
.product-card:hover .quick-view,
.quick-view:focus-visible {
  transform: translate(-50%, 0);
  opacity: 1;
}
.quick-view:hover {
  background: var(--gold);
  color: var(--ink);
  border-color: var(--gold);
}

.product-body {
  padding: 24px 22.4px 28.8px;
}
.product-cat {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 9.6px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(200, 204, 212, 0.45);
}
.product-name {
  margin-top: 9.6px;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 17.92px;
  color: var(--silver-lt);
  transition: color 0.4s;
}
.product-card:hover .product-name,
.arrival-card:hover .product-name,
.rail-card:hover .product-name {
  color: var(--gold-lite);
}

.product-meta {
  margin-top: 12px;
}
.stars {
  font-size: 12.8px;
  letter-spacing: 0.14em;
  color: var(--gold);
}
.stars em {
  font-style: normal;
  margin-left: 6.4px;
  font-size: 11.2px;
  color: rgba(200, 204, 212, 0.45);
}
.product-price {
  margin-top: 16px;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 16.32px;
  font-weight: 600;
  color: var(--silver-lt);
}
.product-price s {
  margin-left: 8.8px;
  font-size: 12.8px;
  font-weight: 400;
  /* Lifted from .38: the chessboard backdrop is busier than the flat
     charcoal this was tuned against, and the strike-through washed out. */
  color: rgba(200, 204, 212, 0.55);
}

/* ==========================================================================
   BEST SELLER RAIL
   ========================================================================== */
.rail {
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
/* The card is a flex column so that in an equal-height Slick slide the media
   keeps its ratio and the body absorbs the slack — prices then line up across
   cards regardless of how many lines a product name wraps to. */
.rail-card {
  position: relative;
  display: flex;
  flex-direction: column;
  scroll-snap-align: start;
  flex: 0 0 clamp(240px, 74vw, 352px);
  border: 1px solid var(--line);
  border-radius: 24px;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(180deg, var(--slate2) 0%, #101015 100%);
  transition:
    transform 0.65s var(--ease-luxe),
    border-color 0.5s,
    box-shadow 0.65s;
}

/* Gold hairline that traces the card edge on hover. Drawn as a mask-composited
   ring on a pseudo-element rather than a second border so it can fade
   independently of the resting border without shifting layout by a pixel. */
.rail-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    150deg,
    rgba(232, 207, 130, 0.75),
    rgba(201, 162, 39, 0.18) 42%,
    transparent 70%
  );
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.55s var(--ease-soft);
  pointer-events: none;
}
.rail-card:hover {
  transform: translateY(-12px);
  border-color: rgba(201, 162, 39, 0.28);
  box-shadow:
    0 48px 92px -48px rgba(0, 0, 0, 0.95),
    0 0 0 1px rgba(201, 162, 39, 0.06);
}
.rail-card:hover::after,
.rail-card:focus-within::after {
  opacity: 1;
}

/* ---- Media ---- */
.rail-media {
  position: relative;
  overflow: hidden;
  border-radius: 20px 20px 0 0;
}
/* Legacy markup puts .rail-img directly in the card; the radius and clipping
   then have to live on the image itself. */
.rail-img {
  display: block;
  width: 100%;
  aspect-ratio: 4/5;
  object-fit: contain;
  filter: grayscale(0.3) brightness(0.82) contrast(1.04);
  transform: scale(1.01);
  /*hidesthesub-pixeledgewhilescalingbackdown*/
  transition:
    transform 1.2s var(--ease-luxe),
    filter 0.7s;
  -webkit-filter: grayscale(0.3) brightness(0.82) contrast(1.04);
}
.rail-card:hover .rail-img {
  transform: scale(1.07);
  filter: grayscale(0) brightness(1) contrast(1);
}

/* Bottom scrim: keeps the body's top edge from reading as a hard seam against
   whatever tone the photo happens to end on. */
.rail-card .rail-img + .rail-body::before,
.rail-media::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 96px;
  pointer-events: none;
}
.rail-media::after {
  bottom: 0;
  background: linear-gradient(to top, rgba(16, 16, 21, 0.92), transparent);
}
.rail-card .rail-img + .rail-body::before {
  top: -96px;
  background: linear-gradient(to top, var(--slate2), transparent);
  z-index: 2;
}

/* ---- Body ---- */
.rail-body {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1 1 auto;
  padding: 24px 24px 28px;
}
.rail-body .product-cat {
  font-size: 9.28px;
  letter-spacing: 0.26em;
  color: rgba(201, 162, 39, 0.72);
  transition: color 0.4s;
}
.rail-body .product-name {
  margin-top: 0;
  font-size: clamp(19.2px, 1.5vw, 22.4px);
  line-height: 1.22;
  letter-spacing: 0.005em;
}
/* Price sits on its own rule so it stays anchored to the card foot even when a
   neighbouring name wraps to two lines. */
.rail-body .product-price {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--line-soft);
  font-size: 17.6px;
  color: var(--gold-lite);
  transition: border-color 0.5s;
}
.rail-card:hover .rail-body .product-price {
  border-color: rgba(201, 162, 39, 0.26);
}

/* ==========================================================================
   NEW ARRIVALS
   ========================================================================== */
/* The card is a flex column so that, inside an equal-height slider slide, the
   media stays a fixed ratio, the text block takes the slack, and every card's
   "Add to Bag" lands on the same baseline regardless of product-name length. */
/* One continuous surface: media and copy live inside a single bordered panel
   instead of a floating image with loose text under it. The panel itself
   lifts on hover; the gold hairline is painted by an ::after overlay so the
   colour change never nudges layout. */
.arrival-card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  border-radius: 24px;
  border: 1px solid var(--line);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.035),
    rgba(255, 255, 255, 0.012) 42%,
    rgba(0, 0, 0, 0.18)
  );
  transition:
    transform 0.7s var(--ease-luxe),
    box-shadow 0.7s,
    border-color 0.5s;
}
.arrival-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 1px solid rgba(201, 162, 39, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s;
}
.arrival-card:hover {
  transform: translateY(-8px);
  box-shadow: 0 46px 90px -48px rgba(0, 0, 0, 0.95);
}
.arrival-card:hover::after {
  opacity: 1;
}

.arrival-media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4/5;
  background: var(--slate2);
  flex: 0 0 auto;
}
/* Bottom fade so the image dissolves into the body rather than cutting off. */
.arrival-media::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 38%;
  background: linear-gradient(180deg, transparent, rgba(8, 9, 11, 0.55));
  pointer-events: none;
}
.arrival-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: grayscale(0.3) brightness(0.86);
  transition:
    transform 1.2s var(--ease-luxe),
    filter 0.8s;
}
.arrival-card:hover .arrival-img {
  transform: scale(1.07);
  filter: grayscale(0) brightness(1);
}

/* Text block: grows to absorb height differences; the button is pushed out of
   it by margin-top:auto so it pins to the card foot. */
.arrival-body {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  gap: 14px;
  padding: 26px 26px 28px;
}
.arrival-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}
.arrival-head .product-name {
  margin-top: 0;
  font-size: 23.04px;
  line-height: 1.18;
  letter-spacing: 0.005em;
}
.arrival-head .product-price {
  margin-top: 0;
  white-space: nowrap;
  font-size: 18.4px;
  color: var(--gold-lite);
}
/* Category reads as a small caps tag with a rule leading into it. */
.arrival-body .product-cat {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: 9.28px;
  letter-spacing: 0.26em;
}
.arrival-body .product-cat::before {
  content: "";
  width: 22px;
  height: 1px;
  flex: 0 0 auto;
  background: rgba(201, 162, 39, 0.55);
}
.arrival-body .btn-line {
  margin-top: auto;
  align-self: stretch;
  padding-block: 15px;
}

/* ==========================================================================
   CATEGORY TILES
   ========================================================================== */
.tile {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 21.6px;
  border: 1px solid var(--line);
  aspect-ratio: 4/3;
  background: var(--slate2);
  transition:
    border-color 0.5s,
    box-shadow 0.6s;
}
.tile:hover {
  border-color: rgba(201, 162, 39, 0.42);
  box-shadow:
    0 34px 70px -42px rgba(0, 0, 0, 0.95),
    0 0 50px -32px rgba(201, 162, 39, 0.45);
}
.tile-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: grayscale(0.5) brightness(0.66);
  transition:
    transform 1.3s var(--ease-luxe),
    filter 0.8s;
}
.tile:hover .tile-img {
  transform: scale(1.13);
  filter: grayscale(0) brightness(0.86);
}
.tile-veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 30%, rgba(5, 5, 6, 0.9));
}
.tile-label {
  position: absolute;
  left: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 11.2px;
  padding: clamp(19.2px, 2.6vw, 32px);
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: clamp(18.4px, 2.4vw, 28px);
  color: var(--silver-lt);
}
.tile-label i {
  font-style: normal;
  color: var(--gold);
  transition: transform 0.5s var(--ease-luxe);
}
.tile:hover .tile-label i {
  transform: translateX(9.6px);
}

/* ==========================================================================
   BRAND INTRODUCTION  (index → #brand)
   ==========================================================================
   Asymmetric editorial split rather than a centred stack: the statement holds
   the wide left column, the "eleven hands" score sits in a narrow right rail,
   and the stat ledger runs full width beneath both. Named grid areas so the
   single-column mobile order (statement → ledger → score) can differ from the
   desktop order without touching the markup. */
.brand-layout {
  display: grid;
  grid-template-areas: "lead" "ledger" "score";
  gap: 3.5rem 0;
}
.brand-lead {
  grid-area: lead;
}
.brand-score {
  grid-area: score;
}
.brand-ledger {
  grid-area: ledger;
}

/* forces the break before "We compose" */

.brand-copy {
  margin-top: 2.25rem;
  max-width: 46ch;
  font-size: 1rem;
  line-height: 1.75;
  color: rgba(200, 204, 212, 0.65);
}

/* Sign-off: a gold rule that runs into the wordmark. */
.brand-signature {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 2.5rem;
  font-size: 0.6875rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(201, 162, 39, 0.7);
}
.brand-signature-rule {
  width: 3.5rem;
  height: 1px;
  flex: none;
  background: linear-gradient(90deg, rgba(201, 162, 39, 0), var(--gold));
}

/* ---------- the eleven hands ---------- */
.brand-score {
  padding: 1.9rem 1.75rem 1.6rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 22px;
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, 0.05),
    rgba(255, 255, 255, 0.012)
  );
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
.brand-score-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1.1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(238, 241, 246, 0.72);
}
.brand-score-head span {
  color: rgba(201, 162, 39, 0.6);
  letter-spacing: 0.14em;
}

.brand-hands {
  margin: 0;
  padding: 0;
  list-style: none;
}
.brand-hands li {
  display: flex;
  align-items: baseline;
  gap: 1.1rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.055);
  transition: padding-left 0.45s var(--ease-luxe);
}
.brand-hands li:hover {
  padding-left: 0.5rem;
}
.bh-n {
  flex: none;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 0.95rem;
  color: rgba(201, 162, 39, 0.55);
}
.bh-name {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.375rem;
  color: var(--silver-lt);
}
.brand-score-foot {
  padding-top: 1.1rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: rgba(200, 204, 212, 0.45);
}

/* ---------- stat ledger ----------
   Cell dividers are borders on the items rather than a painted grid gap,
   because the row count changes between breakpoints and a painted gap would
   leave a stray rule hanging past the last cell. */
.brand-ledger {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.brand-ledger > div {
  padding: 2.25rem 1.5rem 2rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.055);
}

/* ==========================================================================
   COUNTERS & TIMELINE
   ========================================================================== */
.counter-num {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(36.8px, 5vw, 60.8px);
  line-height: 1;
  color: var(--gold);
}
.counter-cap {
  margin-top: 11.2px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 9.92px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(200, 204, 212, 0.45);
}

.timeline {
  position: relative;
  padding-left: 32px;
  border-left: 1px solid var(--line);
}
.tl-item {
  position: relative;
  padding-bottom: clamp(48px, 7vw, 88px);
}
.tl-item:last-child {
  padding-bottom: 0;
}
.tl-dot {
  position: absolute;
  left: -39.04px;
  top: 7.2px;
  width: 13.6px;
  height: 13.6px;
  border-radius: 999px;
  background: var(--ink);
  border: 1px solid var(--gold);
  box-shadow: 0 0 0 5px rgba(201, 162, 39, 0.09);
}
.tl-year {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.08px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold);
}
.tl-title {
  margin-top: 15.2px;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(20.8px, 3vw, 34.4px);
  line-height: 1.2;
  color: var(--silver-lt);
}
.tl-copy {
  margin-top: 14.4px;
  max-width: 704px;
  font-size: 15.04px;
  line-height: 1.75;
  color: rgba(200, 204, 212, 0.58);
}

/* Chapter figure in the static timeline. Floated so the copy wraps around it
   on wide screens; it drops above the text once the column gets narrow. */
.tl-figure {
  float: right;
  width: clamp(120px, 15vw, 208px);
  height: auto;
  margin: 0 0 16px 32px;
  object-fit: contain;
  filter: brightness(0.88) contrast(1.04) saturate(0.92)
    drop-shadow(0 18px 34px rgba(0, 0, 0, 0.5));
  mask-image: linear-gradient(180deg, #000 80%, transparent 99%);
  -webkit-mask-image: linear-gradient(180deg, #000 80%, transparent 99%);
}
/* The float has to be cleared or a short chapter lets the next one's dot ride
   up alongside the previous figure. */
.tl-item::after {
  content: "";
  display: block;
  clear: both;
}

/* ==========================================================================
   PROMO BANNER
   ========================================================================== */
.promo-banner {
  position: relative;
  overflow: hidden;
  border-radius: 32px;
  border: 1px solid rgba(201, 162, 39, 0.24);
  background: var(--slate2);
  box-shadow: 0 50px 110px -60px rgba(0, 0, 0, 0.98);
}
.promo-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0.34;
  filter: grayscale(0.3);
  transform: scale(1.05);
  transition: transform 1.6s var(--ease-luxe);
}
.promo-banner:hover .promo-img {
  transform: scale(1.13);
}
.promo-veil {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(
      ellipse at 50% 50%,
      rgba(201, 162, 39, 0.2),
      transparent 62%
    ),
    linear-gradient(180deg, rgba(5, 5, 6, 0.72), rgba(5, 5, 6, 0.9));
}
.promo-sweep {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    105deg,
    transparent 40%,
    rgba(232, 207, 130, 0.14) 50%,
    transparent 60%
  );
  background-size: 250% 100%;
}

/* ==========================================================================
   GLASS / TESTIMONIALS / NEWSLETTER
   ========================================================================== */
.glass-card {
  position: relative;
  border-radius: 28px;
  border: 1px solid rgba(255, 255, 255, 0.11);
  background: linear-gradient(
    150deg,
    rgba(255, 255, 255, 0.075),
    rgba(255, 255, 255, 0.018)
  );
  backdrop-filter: blur(26px);
  -webkit-backdrop-filter: blur(26px);
  box-shadow: 0 40px 90px -50px rgba(0, 0, 0, 0.95);
}
/* ==========================================================================
   PILLAR CARDS  (about → #introduction)
   ==========================================================================
   Three equal columns that read as one carved slab rather than three floating
   chips: the cards share a single hairline frame and are divided by the grid
   gap itself, which the parent paints gold-tinted. Each card is a flex column
   so the meta line pins to the bottom and the three baselines agree no matter
   how the copy wraps. */
.pillar-grid {
  display: grid;
  gap: 1px; /* the gap *is* the divider rule */
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 28px;
  overflow: hidden;
}

.pillar {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 3rem 2.25rem 2.5rem;
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, 0.055),
    rgba(255, 255, 255, 0.014)
  );
  transition: background 0.6s var(--ease-luxe);
}
/* Gold wick that draws in from the left along the card's top edge on hover. */
.pillar::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg, var(--gold), rgba(201, 162, 39, 0));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.7s var(--ease-luxe);
}
.pillar:hover {
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, 0.085),
    rgba(255, 255, 255, 0.02)
  );
}
.pillar:hover::before {
  transform: scaleX(1);
}

/* Oversized index sits behind the icon as a watermark, not as a label. */
.pillar-index {
  position: absolute;
  top: 1.5rem;
  right: 1.9rem;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 3.75rem;
  line-height: 1;
  color: rgba(201, 162, 39, 0.13);
  letter-spacing: -0.02em;
  pointer-events: none;
  transition: color 0.6s var(--ease-luxe);
}
.pillar:hover .pillar-index {
  color: rgba(201, 162, 39, 0.26);
}

.pillar-icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border: 1px solid rgba(201, 162, 39, 0.35);
  border-radius: 999px;
  color: var(--gold);
  font-size: 1.125rem;
  transition:
    border-color 0.5s var(--ease-luxe),
    background 0.5s var(--ease-luxe),
    transform 0.5s var(--ease-luxe);
}
.pillar:hover .pillar-icon {
  border-color: rgba(201, 162, 39, 0.7);
  background: rgba(201, 162, 39, 0.08);
  transform: translateY(-3px);
}

.pillar-title {
  margin-top: 1.75rem;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.5rem;
  color: var(--silver-lt);
}
.pillar-copy {
  margin-top: 1rem;
  font-size: 0.875rem;
  line-height: 1.7;
  color: rgba(238, 241, 246, 0.6);
}
/* Pushed to the bottom so the three meta lines align across the row. */
.pillar-meta {
  margin-top: auto;
  padding-top: 1.75rem;
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(201, 162, 39, 0.62);
}

.news-glow {
  position: absolute;
  left: -14%;
  top: -45%;
  width: 544px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(201, 162, 39, 0.24),
    transparent 66%
  );
  filter: blur(70px);
  pointer-events: none;
}

/* Flex column + auto-margin footer: quotes vary in length, so without this the
   avatar rows sit at six different heights across the carousel. */
.testi-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: clamp(28px, 3.2vw, 41.6px);
  border-radius: 24px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: linear-gradient(
    150deg,
    rgba(255, 255, 255, 0.06),
    rgba(255, 255, 255, 0.014)
  );
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  transform-style: preserve-3d;
  transition:
    transform 0.65s var(--ease-luxe),
    border-color 0.5s,
    box-shadow 0.65s;
}
.testi-card:hover {
  border-color: rgba(201, 162, 39, 0.38);
  box-shadow:
    0 40px 80px -46px rgba(0, 0, 0, 0.95),
    0 0 55px -34px rgba(201, 162, 39, 0.4);
}
.testi-card .stars {
  flex: 0 0 auto;
}
/* flex-grow absorbs the height difference between cards; the bottom margin is
   the minimum gap to the footer on the tallest card, where there is no slack
   left to grow into. */
.testi-quote {
  flex: 1 1 auto;
  margin: 0 0 32px;
  font-size: 16px;
  line-height: 1.8;
  color: rgba(238, 241, 246, 0.82);
}
.testi-foot {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 0 0 auto;
  margin-top: auto;
  padding-top: 25.6px;
  border-top: 1px solid var(--line-soft);
}
.testi-avatar {
  width: 48px;
  height: 48px;
  border-radius: 999px;
  object-fit: contain;
  border: 1px solid rgba(201, 162, 39, 0.35);
}
.testi-foot strong {
  display: block;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 15.68px;
  font-weight: 500;
  color: var(--silver-lt);
}
.testi-foot em {
  display: block;
  margin-top: 4px;
  font-style: normal;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.08px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(200, 204, 212, 0.45);
}

.luxe-input {
  width: 100%;
  padding: 16.8px 21.6px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.04);
  color: var(--silver-lt);
  font-size: 14.72px;
  transition:
    border-color 0.4s,
    box-shadow 0.4s,
    background 0.4s;
}
.luxe-input::placeholder {
  color: rgba(200, 204, 212, 0.34);
}
.luxe-input:focus {
  border-color: rgba(201, 162, 39, 0.65);
  background: rgba(201, 162, 39, 0.05);
  box-shadow: 0 0 0 4px rgba(201, 162, 39, 0.11);
}
.luxe-input[aria-invalid="true"] {
  border-color: #e06666;
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
/* Redesign: the footer reads as one lit plinth rather than a stack of boxes.
   A single gold seam opens it, an inline newsletter rail closes the content,
   and the columns sit on an auto-fit grid so the same markup reflows from a
   single stacked column up to five without any per-page breakpoint work. */
/* The wrap is ordered so the newsletter band leads and the columns follow —
   the markup keeps its original source order (columns, rail, bottom bar) for
   screen readers and for pages that load this CSS late. */
.site-footer > .wrap {
  display: flex;
  flex-direction: column;
}
.site-footer .foot-rail {
  order: 1;
}
.site-footer .foot-grid {
  order: 2;
}
.site-footer .foot-bottom {
  order: 3;
}

.site-footer {
  position: relative;
  isolation: isolate;
  margin-top: clamp(24px, 2vw, 24px);
  border-top: 1px solid var(--line);
  /* Three stacked washes instead of one flat fill: a warm gold bloom rising
     from the seam, a cool counter-light in the lower left so the plinth is not
     lit evenly, and the charcoal→ink ramp underneath them both. */
  background: linear-gradient(
    180deg,
    var(--charcoal) 0%,
    #08080a 42%,
    var(--ink) 100%
  );
  padding-top: clamp(60px, 6vw, 104px);
  overflow: hidden;
}
/* A single soft gold aura behind the newsletter band — the same blurred-orb
   treatment as .news-glow elsewhere on the site, so the footer belongs to the
   same visual family instead of inventing its own decoration. */
.site-footer::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 50%;
  top: -160px;
  width: min(1100px, 120vw);
  aspect-ratio: 2 / 1;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(
    ellipse,
    rgba(201, 162, 39, 0.16),
    transparent 62%
  );
  filter: blur(80px);
  pointer-events: none;
}
/* ---------- Chessboard plinth ----------
   The footer floor reads as a lit board seen in raking light. It is one
   pseudo-element carrying four stacked gradient passes, so it costs no extra
   markup and cannot receive pointer events:

     1. a warm top-left bevel highlight on each cell,
     2. a cool bottom-right shade on each cell — together these two are what
        give the squares their thickness,
     3. the checker pattern itself,
     4. a flat base tint so the pattern never sits directly on the ink ramp.

   The whole layer is masked to fade out upward and at both edges, so it is
   densest along the bottom bar where there is the least type, and gone by the
   time it reaches the newsletter headline. z-index:-1 keeps it under every
   text node while staying above the footer background. */
.site-footer::after {
  content: "";
  position: absolute;
  z-index: -1;
  left: -4%;
  right: -4%;
  bottom: 0;
  height: min(62%, 520px);
  pointer-events: none;
  /* One cell is half the tile: the tile carries a 2x2 checker. */
  --cell: clamp(34px, 4.6vw, 58px);
  --tile: calc(var(--cell) * 2);
  background-image:
    /* bevel: light catches the top-left lip of each raised square */
    linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0 14%, transparent 14%),
    /* shade: the opposite lip falls away into the board */
    linear-gradient(135deg, transparent 86%, rgba(0, 0, 0, 0.32) 86%),
    /* checker */
    repeating-conic-gradient(
        rgba(201, 162, 39, 0.055) 0% 25%,
        rgba(255, 255, 255, 0.014) 25% 50%
      ),
    linear-gradient(180deg, rgba(255, 255, 255, 0.012), transparent);
  background-size:
    var(--cell) var(--cell),
    var(--cell) var(--cell),
    var(--tile) var(--tile),
    100% 100%;
  background-position:
    0 100%,
    0 100%,
    0 100%,
    0 0;
  /* Anchor the pattern to the bottom edge so the board never shows a clipped
     half-row along the foot of the page. */
  /* Fade up and inward. -webkit- kept for Safari, which still needs it. */
  -webkit-mask-image:
    linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.55) 46%, #000 100%),
    linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
  mask-image:
    linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.55) 46%, #000 100%),
    linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  opacity: 0.9;
}
/* Browsers without mask support would show a hard-edged rectangle of board
   across the footer, which is worse than no effect at all. */
@supports not (
  (mask-image: linear-gradient(#000, #000)) or
    (-webkit-mask-image: linear-gradient(#000, #000))
) {
  .site-footer::after {
    display: none;
  }
}
/* Same intent as the body-board rule further down: on reduced-transparency
   setups the decoration goes away rather than competing with the copy. */
/* The bottom bar sits directly on the densest part of the board, so give its
   row a soft scrim to keep the copyright and legal links legible. */
/* z-index:0 on the row makes it its own stacking context, so the scrim's
   -1 is measured against the row rather than against the footer's board
   layer — the scrim lands above the board and below the text either way. */
.foot-bottom {
  z-index: 0;
}
.foot-bottom::before {
  content: "";
  position: absolute;
  inset: 0 -50vw;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    transparent,
    rgba(8, 8, 10, 0.62) 40%,
    rgba(8, 8, 10, 0.78)
  );
}

/* ---------- Column grid ----------
   auto-fit + minmax means the column count is driven by available width, so
   the footer is fluid between breakpoints instead of jumping 1 → 2 → 4. */
.foot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: clamp(36px, 3.6vw, 56px);
  padding-bottom: clamp(30px, 3vw, 44px);
  /* The tallest column sets the row height, so start the tracks at their
     content height rather than letting the grid stretch them. */
  align-items: start;
}
/* The brand block gets the widest track and leads the row on large screens. */
.foot-brand {
  /* grid-column:1 / -1;  */
  max-width: none;
}

/* No medallion, no frame — the mark simply sits at its natural size next to
   the wordmark, the way the site header carries it. Restraint reads as
   confidence; a bordered badge reads as a template. */
.foot-logo {
  display: inline-flex;
  align-items: center;
  gap: 13px;
  color: var(--silver-lt);
  transition: opacity 0.4s var(--ease-soft);
}
.foot-logo img {
  width: 38px;
  height: 38px;
  object-fit: contain;
}
.foot-logo:hover {
  opacity: 0.72;
}
/* Wordmark stays plain silver. The gold gradient competed with the gold
   accents everywhere else and cheapened both. */
.foot-logo span {
  color: var(--silver-lt);
}
.foot-brand__text {
  margin-top: 22px;
  max-width: 34ch;
  font-size: 14px;
  line-height: 1.75;
  color: rgba(200, 204, 212, 0.5);
}
.foot-social {
  margin-top: 28px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ---------- Column heads ----------
   A short gold tick under each head replaces the old all-caps-only treatment;
   it gives the columns a visual baseline without adding a full rule. */
/* Quiet silver labels, no underline ornament. Hierarchy comes from the
   colour gap between head and link, and from the space beneath — not from
   a decorative rule under every column. */
.foot-head {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--silver-lt);
}
.foot-list {
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

/* ---------- Links ----------
   One thing happens on hover: the label brightens to full silver. No slide,
   no pip, no underline wipe. Three simultaneous effects on a nav link is
   what made the old footer feel dated. */
.foot-link {
  display: inline-block;
  font-size: 14px;
  color: rgba(200, 204, 212, 0.52);
  transition: color 0.3s var(--ease-soft);
}
.foot-link:hover,
.foot-link:focus-visible {
  color: var(--silver-lt);
}

/* Icon links: bare glyphs on a fixed gutter, no tiles. The gutter alone
   aligns the labels, which is all the structure the column needs. */
.foot-link--icon {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.foot-link--icon i {
  width: 14px;
  flex: 0 0 14px;
  text-align: center;
  font-size: 12px;
  color: rgba(200, 204, 212, 0.32);
  transition: color 0.3s var(--ease-soft);
}
.foot-link--icon:hover i,
.foot-link--icon:focus-visible i {
  color: var(--gold);
}

/* ---------- Newsletter rail ----------
   Pulled out of the column grid into a full-width rail so the input has room
   to breathe on tablet, where a 4th narrow column used to squeeze it. */
/* The rail leads the footer: it sits above the columns as a full-bleed
   editorial band, not a boxed card tucked underneath them. No border, no
   glass panel — just a soft gold aura and a closing hairline. */
.foot-rail {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 3vw, 56px);
  align-items: end;
  padding-bottom: clamp(24px, 2.6vw, 68px);
  margin-bottom: clamp(24px, 2.6vw, 68px);
  border-bottom: 1px solid var(--line-soft);
}
.foot-eyebrow {
  display: inline-block;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold);
}
/* Editorial scale — this is the one piece of display type in the footer, and
   it is what makes the whole band read as designed rather than assembled. */
.foot-rail__title {
  margin-top: 18px;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 500;
  font-size: clamp(30px, 4vw, 52px);
  line-height: 1.04;
  letter-spacing: 0;
  color: var(--silver-lt);
}
.foot-rail__sub {
  margin-top: 16px;
  max-width: 42ch;
  font-size: 14px;
  line-height: 1.7;
  color: rgba(200, 204, 212, 0.5);
}
/* Pad the form down so its row lands level with the body copy on the left,
   instead of floating in the whitespace beside the headline. */
.foot-form__row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.foot-form__row .luxe-input {
  flex: 1 1 220px;
  min-width: 0;
}
.foot-form__row .btn-line {
  flex: 0 0 auto;
  min-width: 128px;
}
.foot-form__msg {
  margin-top: 12px;
  min-height: 16px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--gold);
}

/* ---------- Bottom bar ---------- */
.foot-bottom {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  margin-top: 0;
  padding: clamp(24px, 2.4vw, 32px) 0;
  border-top: 1px solid var(--line-soft);
}
.foot-copyright {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 11.5px;
  letter-spacing: 0.02em;
  color: rgba(200, 204, 212, 0.34);
}
.foot-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 28px;
}
.foot-legal__link {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 11.5px;
  letter-spacing: 0.02em;
  color: rgba(200, 204, 212, 0.4);
  transition: color 0.3s var(--ease-soft);
}
.foot-legal__link:hover,
.foot-legal__link:focus-visible {
  color: var(--silver-lt);
}

/* Flat bordered circles that simply fill on hover. The gradient fill, inner
   highlight, lift and shadow were doing four things at once; one clean state
   change looks more expensive than all of them together. */
.social-dot {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 9.92px;
  letter-spacing: 0.1em;
  color: rgba(200, 204, 212, 0.55);
  transition:
    color 0.3s var(--ease-soft),
    border-color 0.3s var(--ease-soft),
    background-color 0.3s var(--ease-soft);
}
.social-dot:hover,
.social-dot:focus-visible {
  color: var(--ink);
  background-color: var(--silver-lt);
  border-color: var(--silver-lt);
}

/* Every footer hover is now a plain colour change with no travel, so there is
   nothing motion-sensitive left to disable here. */
/* Font Awesome brand icons sit inside the social dots â€” override the tiny
   text sizing so the glyph reads clearly at any breakpoint. */
.social-dot i {
  font-size: 15.2px;
  letter-spacing: 0;
}

/* Font Awesome star ratings â€” the .stars letter-spacing already opens an even
   gap between the inline glyphs; nudge the size so they match the old text. */
.stars i {
  font-size: 13.12px;
}

/* ==========================================================================
   CURSOR / MISC
   ========================================================================== */
/* The cursor glow and dot were removed in favour of the chessboard lift
   below; the native cursor is used again site-wide. */

/* ---------- Interactive 3D chessboard ----------
   app.js swaps the painted body::before board for this grid of real squares
   when a fine pointer is available, then lifts the ones near the cursor.
   Sits on the same fixed layer at the same z-index, so the swap is seamless. */
.board-3d {
  position: fixed;
  inset: 0;
  z-index: -10;
  pointer-events: none;
  overflow: hidden;
  perspective: 900px;
  perspective-origin: 50% 50%;
  background-color: var(--board-dark);
}

/* Suppress the flat painted board once the real squares exist, otherwise the
   two patterns show through each other as the squares lift. */
body.has-board-3d::before {
  background-image: none;
}

.board-sq {
  position: absolute;
  display: block;
  background-color: var(--board-dark);
  transform-style: preserve-3d;
  /* Only the return-to-rest is eased; the lift itself is driven per-frame
     from JS, so a transition there would fight the rAF loop and lag. */
  transition:
    transform 0.55s var(--ease-luxe),
    opacity 0.55s var(--ease-luxe),
    --f 0.55s var(--ease-luxe);
  /* --f is the 0â†’1 lift factor written per-frame by app.js. Everything that
     sells the depth keys off it, so a resting square is completely flat and a
     raised one is fully modelled, with no state in between to manage. */
  --f: 0;
  /* Cast shadow under the raised block, plus a warm rim of bounced light. The
     spread scales with --f so squares at the rim of the cursor radius only
     hint at lifting while the centre ones sit well clear of the board. */
  box-shadow:
    calc(var(--f) * 10px) calc(var(--f) * 16px) calc(var(--f) * 34px)
      rgba(0, 0, 0, calc(var(--f) * 0.72)),
    0 0 calc(var(--f) * 26px) rgba(214, 164, 74, calc(var(--f) * 0.3));
}
.board-sq.is-light {
  background-color: var(--board-light);
}

/* The block face: a directional sheen that brightens the top-left edge and
   falls off to the bottom-right, so a lifted square reads as a solid piece
   catching the lamplight rather than a flat tile that merely got bigger. */
.board-sq::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: var(--f);
  background:
    linear-gradient(
      145deg,
      rgba(255, 226, 163, 0.55) 0%,
      rgba(255, 206, 128, 0.16) 34%,
      rgba(0, 0, 0, 0.2) 68%,
      rgba(0, 0, 0, 0.46) 100%
    ),
    linear-gradient(var(--board-dark-lit), var(--board-dark-lit));
  /* Inset rim = the chamfered edge of the block; the highlight along the top
     and the shadow along the bottom are what make the bevel legible. */
  box-shadow:
    inset 2px 2px 0 rgba(255, 232, 178, 0.42),
    inset -2px -2px 0 rgba(0, 0, 0, 0.5),
    inset 0 0 22px rgba(0, 0, 0, 0.35);
}
.board-sq.is-light::before {
  background:
    linear-gradient(
      145deg,
      rgba(255, 236, 186, 0.6) 0%,
      rgba(255, 214, 140, 0.2) 34%,
      rgba(0, 0, 0, 0.18) 68%,
      rgba(0, 0, 0, 0.42) 100%
    ),
    linear-gradient(var(--board-light-lit), var(--board-light-lit));
}

/* --f has to be a registered <number> for the calc()s above to resolve inside
   box-shadow lengths and for it to interpolate on the return-to-rest instead
   of snapping. Unregistered custom properties are raw tokens and animate
   discretely, which would make settling squares pop. */
@property --f {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

#toTop.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.scroll-rail {
  display: block;
  width: 1px;
  height: 54.4px;
  background: rgba(255, 255, 255, 0.16);
  overflow: hidden;
  position: relative;
}
.scroll-rail i {
  position: absolute;
  inset-inline: 0;
  top: 0;
  display: block;
  height: 45%;
  background: linear-gradient(180deg, var(--gold), transparent);
}

#newsEmail {
  background: transparent;
  border-radius: 30px;
}

#footEmail {
  background: transparent;
}

/* ==========================================================================
   CART / CHECKOUT â€” minimal support only
   Layout, spacing, typography and colour for both pages live in Tailwind
   utilities on the markup. Only the things utilities cannot express are here:
   parent-state switching, native form-control chrome, and one transition that
   needs a class toggled from JS.
   ========================================================================== */

/* Empty-cart and order-placed states are driven by a data attribute on an
   ancestor, so the toggle cannot be a utility on the elements themselves. */
[data-cart-empty="true"] .cart-empty-view {
  display: block;
}
[data-cart-empty="false"] .cart-empty-view {
  display: none;
}
[data-cart-empty="true"] .cart-live-view {
  display: none;
}

[data-checkout-state="placed"] .co-done-view {
  display: block;
}
[data-checkout-state="editing"] .co-done-view {
  display: none;
}
[data-checkout-state="placed"] .co-live-view {
  display: none;
}

/* Removal animation â€” the class is added by js/cart.js before the node goes.
   The row also carries a `transition-colors` utility for its hover tint, so
   this has to win the cascade to animate opacity/transform instead. */
.is-removing {
  opacity: 0;
  transform: translateX(40px);
  transition:
    opacity 0.45s var(--ease-soft),
    transform 0.45s var(--ease-luxe) !important;
}

/* Native control chrome. Appearance resets and the ::after knob on the toggle
   have no utility equivalent; the checked styling keys off them.
   The Tailwind `forms` plugin ships its own [type=radio]/[type=checkbox]
   checked styling (blue fill + a white SVG dot) at equal specificity but later
   in the cascade, so these selectors are doubled up to outrank it. */
.ui-radio.ui-radio {
  appearance: none;
  -webkit-appearance: none;
  background-image: none;
  transition:
    border-color 0.3s,
    box-shadow 0.3s,
    background 0.3s;
}
.ui-radio.ui-radio:checked {
  border-color: var(--gold);
  background-color: var(--gold);
  background-image: none;
  box-shadow: inset 0 0 0 3px var(--ink);
}
.ui-radio.ui-radio:checked:hover,
.ui-radio.ui-radio:checked:focus {
  border-color: var(--gold);
  background-color: var(--gold);
}
.ui-radio.ui-radio:focus {
  box-shadow: inset 0 0 0 3px var(--ink);
}
.ui-radio.ui-radio:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

.ui-toggle.ui-toggle {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  background-image: none;
  transition:
    border-color 0.4s,
    background 0.4s;
}
.ui-toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 3.52px;
  width: 15.2px;
  height: 15.2px;
  border-radius: 999px;
  background: rgba(200, 204, 212, 0.55);
  transform: translateY(-50%);
  transition:
    transform 0.45s var(--ease-luxe),
    background 0.4s;
}
.ui-toggle.ui-toggle:checked {
  border-color: rgba(201, 162, 39, 0.6);
  background-color: rgba(201, 162, 39, 0.16);
  background-image: none;
}
.ui-toggle.ui-toggle:checked:hover,
.ui-toggle.ui-toggle:checked:focus {
  border-color: rgba(201, 162, 39, 0.6);
  background-color: rgba(201, 162, 39, 0.16);
}
.ui-toggle.ui-toggle:checked::after {
  transform: translate(19.84px, -50%);
  background: var(--gold);
}
.ui-toggle.ui-toggle:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

/* The Tailwind `forms` plugin restyles bare inputs/selects/textareas (white
   fill, grey border, square corners) at a specificity that beats .luxe-input,
   which is why checkout's text fields rendered as white boxes. Doubling the
   class reclaims the project's own field styling without touching the original
   .luxe-input rule above. */
.luxe-input.luxe-input {
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 999px;
  background-color: rgba(255, 255, 255, 0.04);
  background-image: none;
  color: var(--silver-lt);
}
.luxe-input.luxe-input:focus {
  border-color: rgba(201, 162, 39, 0.65);
  background-color: rgba(201, 162, 39, 0.05);
  box-shadow: 0 0 0 4px rgba(201, 162, 39, 0.11);
  outline: none;
}
.luxe-input.luxe-input[aria-invalid="true"] {
  border-color: #e06666;
}
/* The textarea and the coupon pills opt out of the pill radius / fill. */
textarea.luxe-input.luxe-input {
  border-radius: 21.6px;
}

/* Payment card marks tint gold when their method is selected. The compound
   `has-[:checked]:[&>span:last-child]:` variant is not emitted by the Tailwind
   CDN build, so the selected-state tint lives here. */
label:has(input:checked) .pay-marks {
  color: var(--gold-lite);
}

/* Select caret drawn with gradients â€” not expressible as a utility. */
.ui-select.ui-select {
  appearance: none;
  -webkit-appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, rgba(201, 162, 39, 0.85) 50%),
    linear-gradient(135deg, rgba(201, 162, 39, 0.85) 50%, transparent 50%);
  background-position:
    calc(100% - 24.8px) calc(50% + 1px),
    calc(100% - 18.4px) calc(50% + 1px);
  background-size:
    6.4px 6.4px,
    6.4px 6.4px;
  background-repeat: no-repeat;
}
.ui-select option {
  background: var(--charcoal);
  color: var(--silver-lt);
}

/* Number input spinners. The class is doubled to outrank the Tailwind `forms`
   plugin, which sets its own `appearance` on `[type='number']` at equal
   specificity but later in the cascade (same approach as .ui-check and
   .ui-radio above). Without this the native stepper arrows survive in Chrome
   and Safari and sit on top of the custom -/+ buttons. */
.ui-spinless.ui-spinless {
  -moz-appearance: textfield;
  -webkit-appearance: none;
  appearance: textfield;
  background-image: none;
}
/* `!important` is needed here: the pseudo-element rule the forms plugin emits
   for the spin buttons cannot otherwise be outranked from a plain class. */
.ui-spinless.ui-spinless::-webkit-outer-spin-button,
.ui-spinless.ui-spinless::-webkit-inner-spin-button {
  -webkit-appearance: none !important;
  appearance: none !important;
  margin: 0;
  display: none;
}

/* ==========================================================================
   PRODUCT DETAILS PAGE â€” minimal support only
   Layout, spacing, typography and colour for the page live in Tailwind
   utilities on the markup. Only the selected-thumbnail state is here: the
   Tailwind CDN build does not emit `aria-pressed:` or `group-aria-pressed:`
   variants, and the gallery's active thumb keys off that attribute so the
   state stays in the accessibility tree rather than in a class.
   ========================================================================== */
[data-gallery-thumb][aria-pressed="true"] {
  border-color: rgba(201, 162, 39, 0.7);
  box-shadow: 0 0 38px -16px rgba(201, 162, 39, 0.85);
}
[data-gallery-thumb][aria-pressed="true"] img {
  filter: brightness(1);
}

/* Wishlist toggle â€” same missing `aria-pressed:` variant, on .icon-btn. */
[data-wishlist][aria-pressed="true"] {
  border-color: rgba(201, 162, 39, 0.6);
  background: rgba(201, 162, 39, 0.09);
  color: var(--gold-lite);
}

/* ==========================================================================
   SHOP PAGE â€” minimal support only
   Layout, grid, spacing, typography, colour, hover/focus states and the
   responsive behaviour all live in Tailwind utilities on the markup and in
   the shared components above (.product-card, .glass-card, .btn-*, .luxe-input).
   Only the things utilities cannot express are here: native form-control
   chrome for the filter checkbox and price slider, and one state driven by an
   attribute that the Tailwind CDN build does not emit a variant for.
   ========================================================================== */

/* Mobile filter drawer scroll panel. The drawer sits on a fixed full-screen
   layer, so its filter list can overflow the viewport on short screens. This
   panel owns that scroll: momentum on iOS, and `overscroll-behavior: contain`
   so reaching either end does not chain the gesture to the page underneath. */
.shop-drawer-scroll {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  touch-action: pan-y;
}

/* Shop toolbar: Filters button + sort select.
   The two controls derive their height from different padding (14.4px on
   .btn-line, and a per-page `!py-[11.2px]`) and different font sizes, so they
   render a few pixels apart. Below `lg` — the range where the Filters button
   exists at all — both are pinned to one height token instead. The `!important`
   is required to outrank the page's Tailwind `!py-*` utilities. The ≤480px
   uniform-control block further down sets the same token, so the two agree. */
@media (max-width: 1023px) {
  .shop-toolbar-controls .btn-line,
  .shop-toolbar-controls .ui-select {
    height: var(--control-h, 46px) !important;
    min-height: var(--control-h, 46px);
    padding-block: 0 !important;
    line-height: 1.1;
  }
  .shop-toolbar-controls .ui-select {
    display: flex;
    align-items: center;
  }
}

/* Filter checkboxes. Appearance reset plus the checked tick â€” the Tailwind
   `forms` plugin ships its own blue fill and white SVG at equal specificity
   but later in the cascade, so the class is doubled to outrank it (same
   approach as .ui-radio above). */
.ui-check.ui-check {
  appearance: none;
  -webkit-appearance: none;
  background-image: none;
  transition:
    border-color 0.3s,
    box-shadow 0.3s,
    background 0.3s;
}
.ui-check.ui-check:checked {
  border-color: var(--gold);
  background-color: var(--gold);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23050506' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-6'/%3E%3C/svg%3E");
  background-size: 11.2px 11.2px;
  background-position: center;
  background-repeat: no-repeat;
}
.ui-check.ui-check:checked:hover,
.ui-check.ui-check:checked:focus {
  border-color: var(--gold);
  background-color: var(--gold);
}
.ui-check.ui-check:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

/* Price slider. Range track and thumb are vendor pseudo-elements â€” there is
   no utility that can reach them. */
.ui-range {
  appearance: none;
  -webkit-appearance: none;
  height: 2px;
  background: linear-gradient(
    90deg,
    var(--gold-deep),
    var(--gold),
    var(--gold-lite)
  );
  border-radius: 999px;
  outline: none;
}
.ui-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16.8px;
  height: 16.8px;
  border-radius: 999px;
  background: var(--gold-lite);
  border: 2px solid var(--ink);
  box-shadow:
    0 0 0 1px rgba(201, 162, 39, 0.7),
    0 0 22px -6px rgba(201, 162, 39, 0.9);
  cursor: pointer;
  transition:
    transform 0.3s var(--ease-luxe),
    box-shadow 0.3s;
}
.ui-range::-moz-range-thumb {
  width: 16.8px;
  height: 16.8px;
  border-radius: 999px;
  background: var(--gold-lite);
  border: 2px solid var(--ink);
  box-shadow:
    0 0 0 1px rgba(201, 162, 39, 0.7),
    0 0 22px -6px rgba(201, 162, 39, 0.9);
  cursor: pointer;
  transition:
    transform 0.3s var(--ease-luxe),
    box-shadow 0.3s;
}
.ui-range:hover::-webkit-slider-thumb,
.ui-range:focus-visible::-webkit-slider-thumb {
  transform: scale(1.18);
}
.ui-range:hover::-moz-range-thumb,
.ui-range:focus-visible::-moz-range-thumb {
  transform: scale(1.18);
}

/* Add-to-cart confirmation. js/shop.js sets the attribute for ~1.6s; the
   Tailwind CDN build does not emit a `data-[added-state=true]:` variant, and
   the label swap needs generated content either way. */
[data-shop-add][data-added-state="true"] {
  border-color: rgba(201, 162, 39, 0.65);
  color: var(--gold-lite);
}
[data-shop-add][data-added-state="true"] span {
  visibility: hidden;
}
[data-shop-add][data-added-state="true"]::after {
  content: "Added to Cart";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}

/* Wishlist toggle on the shop cards â€” same missing `aria-pressed:` variant
   already noted for the product page. */
[data-shop-wishlist][aria-pressed="true"] {
  border-color: rgba(201, 162, 39, 0.6);
  background: rgba(201, 162, 39, 0.12);
  color: var(--gold-lite);
}

/* ========================================== */
/* SECTION: ANIMATION STYLES                  */
/* ========================================== */

/* ==========================================================================
   ULTIMATE CHESS â€” animation.css
   Keyframes, entry states, hover motion, GSAP-companion classes.
   ========================================================================== */

/* ---------- Keyframes ---------- */
@keyframes floatY {
  0%,
  100% {
    transform: translate3d(0, 0, 0) rotate(0deg);
  }
  50% {
    transform: translate3d(0, -22px, 0) rotate(2.2deg);
  }
}
@keyframes floatSoft {
  0%,
  100% {
    transform: translate3d(0, 0, 0);
  }
  50% {
    transform: translate3d(0, -12px, 0);
  }
}
@keyframes railPulse {
  0% {
    transform: translateY(-110%);
  }
  60% {
    transform: translateY(230%);
  }
  100% {
    transform: translateY(230%);
  }
}
@keyframes sheenSlide {
  0% {
    background-position: 220% 0;
  }
  100% {
    background-position: -120% 0;
  }
}
@keyframes particleRise {
  0% {
    transform: translate3d(0, 0, 0) scale(0.5);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  85% {
    opacity: 0.65;
  }
  100% {
    transform: translate3d(var(--drift, 14px), -115vh, 0) scale(1.1);
    opacity: 0;
  }
}
@keyframes glowPulse {
  0%,
  100% {
    opacity: 0.42;
    transform: scale(1);
  }
  50% {
    opacity: 0.85;
    transform: scale(1.06);
  }
}
@keyframes spinSlow {
  to {
    transform: rotate(360deg);
  }
}

/* ---------- Preloader ---------- */
.preloader-logo {
  opacity: 0;
  animation: preloadLogo 1s cubic-bezier(0.19, 1, 0.22, 1) 0.05s forwards;
  filter: drop-shadow(0 12px 34px rgba(201, 162, 39, 0.28));
}
@keyframes preloadLogo {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.94);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

#preloader {
  transition:
    opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1),
    visibility 0.8s;
}
#preloader.is-done {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* ---------- Hero entry states (GSAP animates these to visible) ---------- */
.line-mask {
  display: block;
  overflow: hidden;
  padding-bottom: 0.06em;
}
.hero-line {
  transform: translateY(105%);
  will-change: transform;
}
.hero-eyebrow,
.hero-sub,
.hero-cta,
.hero-stats,
.scroll-indicator {
  opacity: 0;
  will-change: transform, opacity;
}

/* ==========================================================================
   HERO — a full-bleed photographic stage.
   The photo is the foundation of the composition rather than a texture behind
   a gradient card: it is unblended and near-full opacity, darkened only by a
   veil tuned to protect the headline's contrast. Copy sits in a left-aligned
   editorial column so the right-hand third of the photograph stays open.
   Entrance keyframes are held until the preloader clears, at which point JS
   adds .hero-ready.
   ========================================================================== */
/* --header-h clears the fixed header. --hero-gap is the visible inset around
   the card; the photographic hero collapses it to zero to go edge-to-edge. */
.hero-container {
  --header-h: 96px;
  --hero-gap: clamp(20px, 3vmin, 40px);
  height: auto;
  min-height: calc(100dvh - var(--header-h));
  width: 100%;
  max-width: 100%;
  padding: var(--hero-gap);
  padding-top: calc(var(--header-h) + var(--hero-gap));
  padding-bottom: calc(var(--hero-gap) * 2);
  box-sizing: border-box;
  background: transparent;
  display: flex;
  overflow-x: clip;
}

.hero-content {
  flex: 1;
  width: 100%;
  min-width: 0;
  /* Extra bottom padding reserves the scroll-indicator's lane. */
  padding: clamp(40px, 5vh, 72px) clamp(16px, 3vw, 40px)
    clamp(112px, 12vh, 152px);
  background: linear-gradient(
    135deg,
    rgba(12, 12, 15, 1) 0%,
    rgba(20, 20, 25, 0.96) 50%,
    rgba(5, 5, 6, 1) 100%
  );
  border-radius: 32px;
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.7);
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  color: #eef1f6;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-weight: 900;
  font-size: clamp(36px, 6.8vw, 112px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  text-transform: none;
  overflow: hidden;
}

/* A single slow gold field, drifting rather than spinning. */
.hero-content::before {
  content: "";
  position: absolute;
  top: -25%;
  left: -25%;
  right: -25%;
  bottom: -25%;
  background:
    radial-gradient(
      ellipse 45% 40% at 22% 55%,
      rgba(201, 162, 39, 0.2) 0%,
      transparent 55%
    ),
    radial-gradient(
      ellipse 35% 45% at 82% 30%,
      rgba(232, 207, 130, 0.1) 0%,
      transparent 50%
    );
  animation: floatLayer 34s ease-in-out infinite;
  will-change: transform;
  pointer-events: none;
  mix-blend-mode: screen;
  z-index: 2;
}

/* --------------------------------------------------------------------------
   .hero-photo — the home page's photographic variant.
   about.html / contact.html carry no .hero-bg image, so they keep the gradient
   card above; everything below applies only where a photograph is present.
   -------------------------------------------------------------------------- */
.hero-container.hero-photo {
  --hero-gap: 0px;
  min-height: 100dvh;
  padding: 0;
  background: #050506;
}

.hero-photo .hero-content {
  /* Bottom padding reserves the scroll-indicator's lane; the inline padding
     forms the editorial column's left margin and holds copy off the far edge. */
  padding: calc(var(--header-h) + clamp(48px, 7vh, 96px))
    clamp(24px, 7vw, 120px) clamp(112px, 13vh, 160px);
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  align-items: flex-start;
  text-align: left;
  font-size: clamp(40px, 7.6vw, 132px);
  line-height: 0.98;
  letter-spacing: -0.045em;
}

/* Hairline frame — a thin inset rule that reads as a mount around the
   photograph and replaces the rounded card's shadow as the hero's edge. */
.hero-photo .hero-content::after {
  content: "";
  position: absolute;
  inset: clamp(12px, 1.6vw, 24px);
  border: 1px solid rgba(201, 162, 39, 0.16);
  pointer-events: none;
  z-index: 3;
}

/* Photographic bed — the base layer of the hero. The inner <img> is the node
   scroll.js targets with `[data-hero-bg] img` for the parallax drift; the bed
   itself is never transformed, so the motion stays clipped by
   .hero-content's overflow:hidden. The image is over-scaled so the drift never
   exposes an edge. */
.hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero-bg img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center 40%;
  display: block;
  will-change: transform;
  /* Unblended and essentially opaque: the photograph carries the hero now, so
     it is graded by the veil above it rather than dissolved into the gradient
     beneath it. */
  opacity: 0.92;
  transform: scale(1.06);
}

/* Grading veil. Weighted to the left so the copy column sits on the darkest
   part of the frame while the right side of the photograph stays readable. */
.hero-bg-veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(
      90deg,
      rgba(4, 4, 6, 0.94) 0%,
      rgba(4, 4, 6, 0.74) 42%,
      rgba(4, 4, 6, 0.28) 72%,
      rgba(4, 4, 6, 0.5) 100%
    ),
    linear-gradient(
      180deg,
      rgba(4, 4, 6, 0.72) 0%,
      rgba(4, 4, 6, 0.12) 38%,
      rgba(4, 4, 6, 0.88) 100%
    );
  pointer-events: none;
}

.hero-gradient-layer {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(
      ellipse 25% 25% at 15% 20%,
      rgba(232, 207, 130, 0.16) 0%,
      transparent 50%
    ),
    radial-gradient(
      ellipse 20% 20% at 85% 75%,
      rgba(201, 162, 39, 0.14) 0%,
      transparent 45%
    );
  animation: floatLayer 30s ease-in-out infinite;
  will-change: transform;
  pointer-events: none;
  z-index: 0;
}

/* In the photographic hero this layer is repurposed as a vignette, kept
   separate from the veil so the drifting gold field is not darkened with it. */
.hero-photo .hero-gradient-layer {
  background: radial-gradient(
    ellipse 78% 70% at 50% 45%,
    transparent 30%,
    rgba(4, 4, 6, 0.72) 100%
  );
  animation: none;
  z-index: 1;
}

.hero-title {
  display: block;
  position: relative;
  z-index: 10;
  margin: 0;
  padding: 0;
  font: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  text-align: inherit;
  text-transform: inherit;
  color: inherit;
}
.hero-title > span {
  display: block;
  margin: 0;
  padding: 0;
}

/* Headline layers — held at their start state until .hero-ready. */
.hero-text-back {
  position: relative;
  z-index: 1;
  opacity: 0;
  transform: translateY(-30px);
}
.hero-text-front {
  position: relative;
  z-index: 10;
  color: #c9a227;
  opacity: 0;
  transform: translateY(30px);
}
.hero-text-paris {
  position: relative;
  z-index: 10;
  opacity: 0;
  transform: translateY(30px);
}

/* In the photographic hero the three lines no longer sandwich a chess image on
   the z-axis, so they are differentiated typographically instead: an outlined
   opening line, a solid gold middle, and a light serif close. */
.hero-photo .hero-text-back {
  z-index: 10;
  color: transparent;
  /* The stroke is the only thing drawing this line, so it is kept near-opaque
     and scaled with the type — a hairline at 1px disappears against the
     brighter parts of the photograph at large sizes. */
  -webkit-text-stroke: max(1.5px, 0.014em) rgba(238, 241, 246, 0.88);
  /* A soft dark halo holds the outline legible wherever the photo behind it
     runs light. */
  text-shadow: 0 2px 22px rgba(4, 4, 6, 0.85);
}
.hero-photo .hero-text-paris {
  /* The closing line drops out of the heavy display weight into the serif used
     for body copy, at a fraction of the headline size — it reads as a coda to
     the headline rather than a third shout. */
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 300;
  font-style: italic;
  font-size: 0.36em;
  line-height: 1.2;
  letter-spacing: 0.02em;
  color: rgba(238, 241, 246, 0.82);
  margin-top: 0.5em;
}

/* Base placement for the chess piece. The home hero no longer carries one —
   its composition is now the photograph plus a single copy column — but
   about.html and contact.html still declare a #travelPiece in their heroes and
   rely on this as its pre-travel state (JS swaps it onto the fixed layer
   below on load, and reduced-motion leaves it here). */
.hero-chess-wrapper {
  position: absolute;
  z-index: 5;
  width: 24%;
  right: 9%;
  top: 50%;
  transform: translateY(-48%);
  pointer-events: none;
  opacity: 0;
}
#hero.hero-ready .hero-chess-wrapper {
  animation: heroFadeIn 1s ease 0.5s forwards;
}
.hero-chess {
  width: 100%;
  display: block;
  aspect-ratio: 2 / 3;
  height: auto;
  object-fit: contain;
}

/* ---------------------------------------------------------------------------
   SCROLL-TRAVELLING PIECE
   The piece lives on a fixed layer from the very first paint, parked exactly
   where the hero composition wants it. Scroll then slides it left/right down
   the page as one unbroken motion â€” it is never re-parented or re-positioned
   mid-scroll, so there is no point at which it disappears and returns.
   GSAP owns the transform on .hero-chess; the wrapper carries position + blur,
   so the two never fight over the same property.
   --------------------------------------------------------------------------- */
.hero-chess-wrapper.is-travelling {
  position: fixed;
  /* Parked on the hero's right-hand side, matching the original absolute
     placement (width 24%, right 9%, vertically centred on the headline) so
     the first frame of the fixed layer is identical to the static hero. */
  top: 50%;
  left: auto;
  right: 9%;
  width: min(24vw, 320px);
  margin: 0;
  transform: translateY(-48%); /* GSAP drives .hero-chess, not the wrapper */
  perspective: none;
  /* In the hero the piece is part of the composition and must sit in FRONT of
     .hero-content's opaque gradient, so it starts lifted. Once it reaches the
     content sections JS drops it to `.is-behind`, where it belongs behind the
     copy â€” in front, it poked through the gaps between cards as a stray sliver. */
  z-index: 6;
  /* Moving the wrapper to <body> takes it out of range of the
     `#hero.hero-ready .hero-chess-wrapper` intro rule, so the base opacity:0
     would leave it permanently invisible. The wrapper is held fully opaque
     here and the fade-in is played on the image by JS instead. */
  opacity: 1;
  animation: none !important;
}

/* Dropped behind the page content for the rest of the journey. */
.hero-chess-wrapper.is-travelling.is-behind {
  z-index: 0;
}

.hero-chess-wrapper.is-travelling .hero-chess {
  will-change: transform, filter, opacity;
  filter: blur(var(--piece-blur, 0px));
}

/* The travelling piece renders on a fixed layer at z-index 0-2. Content
   sections get their own stacking context above it so the blurred piece
   always reads as background and never sits over copy. Sections that paint
   an opaque fill (bg-charcoal) would hide the piece outright, so while the
   piece is travelling those fills are softened to a translucent charcoal â€”
   the piece stays visible behind them, the section still reads as its own
   band, and no section's own layout or colour scheme changes. */
body.piece-travelling main > section {
  position: relative;
  z-index: 3;
}
body.piece-travelling main > section.bg-charcoal {
  background-color: rgb(12 12 15 / 0.88);
}

#hero.hero-ready .hero-text-back {
  animation: heroFadeInDown 0.8s ease 0.2s forwards;
}
#hero.hero-ready .hero-text-front {
  animation: heroFadeInUp 0.8s ease 0.8s forwards;
}
#hero.hero-ready .hero-text-paris {
  animation: heroFadeInUp 0.8s ease 1.1s forwards;
}

/* With no chess piece to wait on, the photographic hero's headline lands
   sooner. */
#hero.hero-photo.hero-ready .hero-text-front {
  animation-delay: 0.55s;
}
#hero.hero-photo.hero-ready .hero-text-paris {
  animation-delay: 0.85s;
}

@keyframes floatLayer {
  0%,
  100% {
    transform: translate(0, 0) scale(1);
  }
  25% {
    transform: translate(3%, -2%) scale(1.02);
  }
  50% {
    transform: translate(-2%, 3%) scale(0.98);
  }
  75% {
    transform: translate(-3%, -1%) scale(1.01);
  }
}
@keyframes heroFadeInDown {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
@keyframes heroFadeInUp {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
@keyframes heroFadeIn {
  to {
    opacity: 1;
  }
}

/* Supporting copy sits above the gradient fields. */
.hero-content .hero-eyebrow {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin: 0 0 25.6px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: clamp(9px, 0.78vw, 11px);
  font-weight: 400;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: #c9a227;
}
.hero-eyebrow-rule {
  display: block;
  height: 1px;
  width: 40px;
  background: rgba(201, 162, 39, 0.5);
}

.hero-content .hero-sub {
  position: relative;
  z-index: 10;
  max-width: 640px;
  margin: 41.6px 16px 0;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(14.4px, 1.05vw, 18px);
  font-weight: 400;
  line-height: 1.65;
  letter-spacing: normal;
  text-transform: none;
  color: rgba(200, 204, 212, 0.7);
}

.hero-content .hero-cta {
  position: relative;
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 38.4px;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 16px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
}

.hero-content .scroll-indicator {
  position: absolute;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9.6px;
  font-size: 16px;
  letter-spacing: normal;
  text-transform: none;
}

/* Photographic hero: every copy block is left-aligned and width-capped so the
   editorial column holds a consistent measure against the image. */
.hero-photo .hero-content .hero-eyebrow {
  justify-content: flex-start;
  margin: 0 0 clamp(20px, 2.6vh, 32px);
  letter-spacing: 0.36em;
}
.hero-photo .hero-eyebrow-rule {
  width: 56px;
  background: linear-gradient(
    90deg,
    rgba(201, 162, 39, 0) 0%,
    rgba(201, 162, 39, 0.8) 100%
  );
}
.hero-photo .hero-content .hero-sub {
  max-width: 52ch;
  margin: clamp(28px, 3.4vh, 44px) 0 0;
  padding-left: clamp(14px, 1.4vw, 22px);
  /* A gold rule down the left edge ties the sub-copy to the eyebrow's accent
     and anchors the ragged-right paragraph to the column's spine. */
  border-left: 1px solid rgba(201, 162, 39, 0.34);
  font-size: clamp(15px, 1.15vw, 19px);
  line-height: 1.7;
  color: rgba(200, 204, 212, 0.74);
}
.hero-photo .hero-content .hero-cta {
  justify-content: flex-start;
  margin-top: clamp(32px, 4vh, 52px);
}
/* Moved out of the centre to the column's edge, so it lines up with the copy
   rather than floating under the middle of the photograph. */
.hero-photo .hero-content .scroll-indicator {
  bottom: clamp(32px, 5vh, 56px);
  left: clamp(24px, 7vw, 120px);
  transform: none;
  align-items: flex-start;
}

/* ==========================================================================
   HERO — .hero-cinema (home page)
   A full-bleed film frame. Where .hero-photo sat copy on a still photograph in
   a single centred-left column, this variant treats the hero as a widescreen
   plate: looping video as the base, a measured baseline grid over it, and the
   composition split into a bottom-weighted copy column with a vertical caption
   rail down the right edge. The headline is set as a stacked ascending scale
   rather than three equal shouts, and the whole frame is held inside a thin
   gold mount that reads as a projection gate.
   Same class hooks as the other heroes, so animation.js / scroll.js are
   unchanged: .hero-bg is the parallax target, .hero-eyebrow/-sub/-cta and
   .scroll-indicator are the fade-in group, .hero-text-* are the headline
   layers, and #hero.hero-ready still gates the entrance.
   ========================================================================== */
.hero-container.hero-cinema {
  --header-h: 96px;
  --hero-gap: 0px;
  --hero-inset: clamp(20px, 4vw, 72px);
  min-height: 100dvh;
  padding: 0;
  background: #040406;
  overflow: hidden;
}

.hero-cinema .hero-content {
  padding: calc(var(--header-h) + clamp(24px, 4vh, 48px)) var(--hero-inset)
    clamp(96px, 11vh, 132px);
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  /* Bottom-weighted: the plate breathes above, the copy sits low in frame the
     way a title card does. */
  justify-content: flex-end;
  align-items: stretch;
  text-align: left;
  font-size: clamp(38px, 6.4vw, 116px);
  line-height: 0.92;
  letter-spacing: -0.045em;
}

/* The gradient field from the base card would wash out the footage. */
.hero-cinema .hero-content::before {
  display: none;
}

/* Projection gate — a thin gold mount inset from the frame's edge. */
.hero-cinema .hero-content::after {
  content: "";
  position: absolute;
  inset: clamp(10px, 1.2vw, 20px);
  border: 1px solid rgba(201, 162, 39, 0.18);
  pointer-events: none;
  z-index: 4;
}

/* ---------- Video bed ---------- */
.hero-cinema .hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero-cinema .hero-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center 45%;
  display: block;
  will-change: transform;
  /* Over-scaled so the parallax drift never exposes an edge, and graded down
     by the veil above rather than dimmed here. */
  transform: scale(1.08);
  opacity: 0.88;
}

/* Grading veil. Darkest along the bottom where the copy lands, with a soft
   left bias so the headline keeps contrast against bright frames. */
.hero-cinema .hero-bg-veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(
      180deg,
      rgba(4, 4, 6, 0.78) 0%,
      rgba(4, 4, 6, 0.22) 34%,
      rgba(4, 4, 6, 0.86) 78%,
      rgba(4, 4, 6, 0.96) 100%
    ),
    linear-gradient(
      90deg,
      rgba(4, 4, 6, 0.72) 0%,
      rgba(4, 4, 6, 0.24) 55%,
      rgba(4, 4, 6, 0.46) 100%
    );
  pointer-events: none;
}

/* Vignette, kept off the veil so the two can be tuned independently. */
.hero-cinema .hero-gradient-layer {
  background: radial-gradient(
    ellipse 82% 74% at 50% 46%,
    transparent 28%,
    rgba(4, 4, 6, 0.7) 100%
  );
  animation: none;
  z-index: 1;
}

/* Measured baseline grid — a faint set of verticals that gives the plate an
   architectural read and echoes the board's file divisions. */
.hero-cinema .hero-grid-lines {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image: linear-gradient(
    90deg,
    rgba(238, 241, 246, 0.055) 1px,
    transparent 1px
  );
  background-size: 12.5% 100%;
  mask-image: linear-gradient(
    180deg,
    transparent 0%,
    #000 22%,
    #000 62%,
    transparent 96%
  );
  -webkit-mask-image: linear-gradient(
    180deg,
    transparent 0%,
    #000 22%,
    #000 62%,
    transparent 96%
  );
}

/* ---------- Split stage ---------- */
.hero-cinema .hero-stage {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(24px, 4vw, 64px);
  width: 100%;
}
.hero-cinema .hero-col {
  min-width: 0;
  max-width: min(100%, 15.5em);
}

/* Vertical caption rail down the right edge — set in the frame's own margin,
   it acts as the counterweight to the left-heavy copy column. */
.hero-cinema .hero-rail {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding-bottom: 4px;
  writing-mode: vertical-rl;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: rgba(201, 162, 39, 0.66);
}
.hero-cinema .hero-rail-line {
  width: 1px;
  height: clamp(48px, 9vh, 96px);
  background: linear-gradient(
    180deg,
    rgba(201, 162, 39, 0) 0%,
    rgba(201, 162, 39, 0.55) 100%
  );
}
.hero-cinema .hero-rail-line:last-child {
  background: linear-gradient(
    180deg,
    rgba(201, 162, 39, 0.55) 0%,
    rgba(201, 162, 39, 0) 100%
  );
}

/* ---------- Headline: ascending scale ---------- */
.hero-cinema .hero-title {
  text-align: left;
}

/* Opening line — small, tracked-out and lowered in the hierarchy, so it reads
   as a lead-in to the display word rather than competing with it. */
.hero-cinema .hero-text-back {
  z-index: 10;
  color: rgba(238, 241, 246, 0.9);
  -webkit-text-stroke: 0;
  font-size: 0.3em;
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1.1;
  text-transform: uppercase;
  margin-bottom: 0.5em;
  text-shadow: 0 2px 18px rgba(4, 4, 6, 0.8);
}
/* The display word — the single loudest element in the frame. */
.hero-cinema .hero-text-front {
  color: #eef1f6;
  text-shadow: 0 8px 40px rgba(4, 4, 6, 0.75);
}
/* Closing line — gold serif coda, set on its own baseline under the display
   word and separated by a hairline rule. */
.hero-cinema .hero-text-paris {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 300;
  font-style: italic;
  font-size: 0.3em;
  line-height: 1.2;
  letter-spacing: 0.01em;
  color: #c9a227;
  margin-top: 0.42em;
  padding-top: 0.42em;
  border-top: 1px solid rgba(201, 162, 39, 0.28);
  display: inline-block;
}

/* ---------- Supporting copy ---------- */
.hero-cinema .hero-content .hero-eyebrow {
  justify-content: flex-start;
  margin: 0 0 clamp(18px, 2.4vh, 30px);
  letter-spacing: 0.36em;
}
.hero-cinema .hero-eyebrow-rule {
  width: 56px;
  background: linear-gradient(
    90deg,
    rgba(201, 162, 39, 0) 0%,
    rgba(201, 162, 39, 0.8) 100%
  );
}

/* Sub-copy sits beside the CTAs on wide frames rather than stacking above
   them, which keeps the block low and wide like a title card's credits. */
.hero-cinema .hero-content .hero-sub {
  max-width: 46ch;
  width: 100%;
  margin: clamp(22px, 2.8vh, 34px) 0 0;
  padding-left: 0;
  border-left: 0;
  font-size: clamp(14.5px, 1.05vw, 17.5px);
  line-height: 1.75;
  color: rgba(200, 204, 212, 0.72);
}
.hero-cinema .hero-content .hero-cta {
  justify-content: flex-start;
  margin-top: clamp(26px, 3.4vh, 42px);
}

.hero-cinema .hero-content .scroll-indicator {
  bottom: clamp(26px, 4vh, 44px);
  left: var(--hero-inset);
  transform: none;
  align-items: flex-start;
}

/* The looping plate is motion; honour the opt-out by freezing it to its
   poster frame. */

/* ==========================================================================
   HERO — .hero-inner (all inner pages)
   The home page's .hero-cinema plate, restaged for a page that has content
   below it. Same visual language — full-bleed photographic plate, grading
   veil, baseline grid, projection-gate mount, ascending headline scale and a
   vertical caption rail — but sized as a band (not 100dvh) so the first
   content section stays within reach of the fold.
   Same class hooks as .hero-cinema, so animation.js / scroll.js are unchanged:
   .hero-bg is the parallax target ([data-hero-bg]), .hero-eyebrow/-sub/-cta
   are the fade-in group, .hero-text-* are the headline layers, and
   #hero.hero-ready still gates the entrance.
   ========================================================================== */
.hero-container.hero-inner {
  --header-h: 96px;
  --hero-gap: 0px;
  --hero-inset: clamp(20px, 4vw, 72px);
  min-height: clamp(420px, 62vh, 660px);
  padding: 0;
  margin-top: 0;
  background: #040406;
  overflow: hidden;
}

.hero-inner .hero-content {
  padding: calc(var(--header-h) + clamp(28px, 4vh, 52px)) var(--hero-inset)
    clamp(48px, 7vh, 76px);
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  justify-content: flex-end;
  align-items: stretch;
  text-align: left;
  /* One step down from .hero-cinema — this is a page title, not a title card. */
  font-size: clamp(34px, 5.2vw, 88px);
  line-height: 0.94;
  letter-spacing: -0.04em;
}

.hero-inner .hero-content::before {
  display: none;
}

/* Projection gate — the same thin gold mount as the home plate. */
.hero-inner .hero-content::after {
  content: "";
  position: absolute;
  inset: clamp(10px, 1.2vw, 20px);
  border: 1px solid rgba(201, 162, 39, 0.18);
  pointer-events: none;
  z-index: 4;
}

/* ---------- Photographic bed ---------- */
.hero-inner .hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero-inner .hero-bg :is(img, video) {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center 42%;
  display: block;
  will-change: transform;
  transform: scale(1.08);
  opacity: 0.82;
}

/* Grading veil — bottom-weighted where the copy lands, left-biased so the
   headline keeps contrast against bright plates. */
.hero-inner .hero-bg-veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(
      180deg,
      rgba(4, 4, 6, 0.82) 0%,
      rgba(4, 4, 6, 0.34) 36%,
      rgba(4, 4, 6, 0.88) 80%,
      rgba(4, 4, 6, 0.97) 100%
    ),
    linear-gradient(
      90deg,
      rgba(4, 4, 6, 0.76) 0%,
      rgba(4, 4, 6, 0.28) 58%,
      rgba(4, 4, 6, 0.5) 100%
    );
  pointer-events: none;
}

.hero-inner .hero-gradient-layer {
  background: radial-gradient(
    ellipse 82% 76% at 46% 48%,
    transparent 26%,
    rgba(4, 4, 6, 0.72) 100%
  );
  animation: none;
  z-index: 1;
}

.hero-inner .hero-grid-lines {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image: linear-gradient(
    90deg,
    rgba(238, 241, 246, 0.055) 1px,
    transparent 1px
  );
  background-size: 12.5% 100%;
  mask-image: linear-gradient(
    180deg,
    transparent 0%,
    #000 26%,
    #000 66%,
    transparent 96%
  );
  -webkit-mask-image: linear-gradient(
    180deg,
    transparent 0%,
    #000 26%,
    #000 66%,
    transparent 96%
  );
}

/* ---------- Split stage ---------- */
.hero-inner .hero-stage {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(24px, 4vw, 64px);
  width: 100%;
}
.hero-inner .hero-col {
  min-width: 0;
  max-width: min(100%, 17em);
}

.hero-inner .hero-rail {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding-bottom: 4px;
  writing-mode: vertical-rl;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: rgba(201, 162, 39, 0.66);
}
.hero-inner .hero-rail-line {
  width: 1px;
  height: clamp(36px, 6vh, 72px);
  background: linear-gradient(
    180deg,
    rgba(201, 162, 39, 0) 0%,
    rgba(201, 162, 39, 0.55) 100%
  );
}
.hero-inner .hero-rail-line:last-child {
  background: linear-gradient(
    180deg,
    rgba(201, 162, 39, 0.55) 0%,
    rgba(201, 162, 39, 0) 100%
  );
}

/* ---------- Breadcrumb ----------
   Replaces the standalone breadcrumb strip the inner pages carried above the
   old banner; it now sits inside the plate, above the eyebrow. */
.hero-inner .hero-crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  margin: 0 0 clamp(14px, 2vh, 22px);
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.5px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(200, 204, 212, 0.5);
}
.hero-inner .hero-crumbs a {
  color: rgba(200, 204, 212, 0.7);
  transition: color 0.3s var(--ease-luxe);
}
.hero-inner .hero-crumbs a:hover {
  color: #e8cf82;
}
.hero-inner .hero-crumbs i {
  font-size: 8px;
  color: rgba(201, 162, 39, 0.5);
}
.hero-inner .hero-crumbs [aria-current] {
  color: rgba(201, 162, 39, 0.85);
}

/* ---------- Headline: ascending scale ---------- */
.hero-inner .hero-title {
  text-align: left;
}

.hero-inner .hero-text-back {
  z-index: 10;
  color: rgba(238, 241, 246, 0.9);
  -webkit-text-stroke: 0;
  font-size: 0.3em;
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1.1;
  text-transform: uppercase;
  margin-bottom: 0.5em;
  text-shadow: 0 2px 18px rgba(4, 4, 6, 0.8);
}
.hero-inner .hero-text-front {
  color: #eef1f6;
  text-shadow: 0 8px 40px rgba(4, 4, 6, 0.75);
}
.hero-inner .hero-text-paris {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 300;
  font-style: italic;
  font-size: 0.32em;
  line-height: 1.2;
  letter-spacing: 0.01em;
  color: #c9a227;
  margin-top: 0.42em;
  padding-top: 0.42em;
  border-top: 1px solid rgba(201, 162, 39, 0.28);
  display: inline-block;
}

/* ---------- Supporting copy ---------- */
.hero-inner .hero-content .hero-eyebrow {
  justify-content: flex-start;
  margin: 0 0 clamp(16px, 2.2vh, 26px);
  letter-spacing: 0.36em;
}
.hero-inner .hero-eyebrow-rule {
  width: 56px;
  background: linear-gradient(
    90deg,
    rgba(201, 162, 39, 0) 0%,
    rgba(201, 162, 39, 0.8) 100%
  );
}

.hero-inner .hero-content .hero-sub {
  max-width: 52ch;
  margin: clamp(18px, 2.4vh, 28px) 0 0;
  padding-left: 0;
  border-left: 0;
  font-size: clamp(14px, 1vw, 16.5px);
  line-height: 1.75;
  color: rgba(200, 204, 212, 0.72);
}
.hero-inner .hero-content .hero-cta {
  justify-content: flex-start;
  margin-top: clamp(22px, 3vh, 34px);
}

/* This banner is a band, not a viewport — there is nothing to scroll-hint to. */
.hero-inner .hero-content .scroll-indicator {
  display: none;
}

/* --------------------------------------------------------------------------
   .hero-inner--slim — product-details.
   The page's <h1> lives in the purchase panel, so the plate carries only the
   breadcrumb and eyebrow and collapses to a shallow band that keeps the
   gallery near the fold.
   -------------------------------------------------------------------------- */
.hero-container.hero-inner--slim {
  min-height: clamp(190px, 26vh, 272px);
}
.hero-inner--slim .hero-content {
  /* With no headline to bottom-weight, the band centres its two lines under
     the header instead of dropping them to the floor of the plate. */
  justify-content: center;
  padding: calc(var(--header-h) + clamp(12px, 1.8vh, 20px)) var(--hero-inset)
    clamp(18px, 2.4vh, 28px);
}
.hero-inner--slim .hero-stage {
  align-items: center;
}
.hero-inner--slim .hero-content .hero-eyebrow {
  margin-bottom: 0;
}

/* ---------- Scroll reveal (GSAP-driven, JS adds .is-in) ---------- */
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 42px, 0);
  filter: blur(6px);
  transition:
    opacity 1s var(--ease-luxe),
    transform 1.05s var(--ease-luxe),
    filter 1s var(--ease-luxe);
  will-change: transform, opacity;
}
[data-reveal].is-in {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  filter: blur(0);
}
[data-reveal-x="left"] {
  transform: translate3d(-56px, 0, 0);
}
[data-reveal-x="right"] {
  transform: translate3d(56px, 0, 0);
}

/* Split-text words (built by JS) */
.split-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
}
.split-word > span {
  display: inline-block;
  transform: translateY(100%);
  will-change: transform;
}

/* ---------- Floating decor ---------- */
.float-piece {
  animation: floatY 9s ease-in-out infinite;
  will-change: transform;
}
.float-piece:nth-of-type(2) {
  animation-duration: 11.5s;
  animation-delay: -3s;
}

.logo-mark {
  transition: transform 0.6s var(--ease-luxe);
}

/* ---------- Scroll indicator ---------- */
.scroll-rail i {
  animation: railPulse 2.3s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

/* ---------- Sheen sweeps ---------- */
.video-sheen {
  animation: sheenSlide 9s linear infinite;
}
.promo-sweep {
  animation: sheenSlide 6.5s linear infinite;
}

/* ---------- Glow orbs ---------- */
.glow-orb {
  animation: glowPulse 11s ease-in-out infinite;
}
.glow-orb--silver {
  animation-duration: 14s;
  animation-delay: -4s;
}
.news-glow {
  animation: glowPulse 8s ease-in-out infinite;
}

/* ---------- Gold particles (built by JS) ---------- */
.particle {
  position: absolute;
  bottom: -6vh;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--gold-lite);
  box-shadow: 0 0 8px 2px rgba(201, 162, 39, 0.55);
  opacity: 0;
  animation: particleRise linear infinite;
  will-change: transform, opacity;
}

/* ---------- Tilt / lift ---------- */
[data-tilt] {
  transform: perspective(1100px) rotateX(0) rotateY(0);
  will-change: transform;
}

/* ---------- Mouse-parallax wrapper (generated by scroll.js) ---------- */
.mp-layer {
  display: block;
  width: 100%;
  will-change: transform;
}

/* ---------- Magnetic buttons ---------- */
[data-magnetic] {
  will-change: transform;
}
[data-magnetic] span {
  display: inline-block;
  will-change: transform;
}

/* ---------- Modal ---------- */
#quickModal {
  opacity: 0;
  transition: opacity 0.45s var(--ease-soft);
}
#quickModal.is-open {
  display: flex;
  opacity: 1;
}
#quickModal .glass-card {
  transform: translateY(26px) scale(0.96);
  transition: transform 0.55s var(--ease-luxe);
}
#quickModal.is-open .glass-card {
  transform: translateY(0) scale(1);
}

/* ---------- Mobile menu ---------- */
/* The overlay sits above the header, so the burger is unreachable once open.
   This close button lives inside the overlay and mirrors its position. */
.menu-close {
  position: absolute;
  top: 22px;
  right: 20px;
  z-index: 2;
  font-size: 16px;
  opacity: 0;
  transform: scale(0.85) rotate(-45deg);
  transition:
    opacity 0.45s var(--ease-luxe),
    transform 0.45s var(--ease-luxe),
    border-color 0.35s,
    color 0.35s,
    background 0.35s;
}
#mobileMenu.is-open .menu-close {
  opacity: 1;
  transform: scale(1) rotate(0);
  transition-delay: 0.16s;
}

#mobileMenu {
  opacity: 0;
  transition: opacity 0.5s var(--ease-soft);
}
#mobileMenu.is-open {
  display: block;
  opacity: 1;
}
#mobileMenu .mobile-link {
  opacity: 0;
  transform: translateY(28px);
  transition:
    opacity 0.6s var(--ease-luxe),
    transform 0.6s var(--ease-luxe);
}
#mobileMenu.is-open .mobile-link {
  opacity: 1;
  transform: translateY(0);
}
#mobileMenu.is-open .mobile-link:nth-child(1) {
  transition-delay: 0.08s;
}
#mobileMenu.is-open .mobile-link:nth-child(2) {
  transition-delay: 0.14s;
}
#mobileMenu.is-open .mobile-link:nth-child(3) {
  transition-delay: 0.2s;
}
#mobileMenu.is-open .mobile-link:nth-child(4) {
  transition-delay: 0.26s;
}
#mobileMenu.is-open .mobile-link:nth-child(5) {
  transition-delay: 0.32s;
}
#mobileMenu.is-open .mobile-link:nth-child(6) {
  transition-delay: 0.38s;
}
#mobileMenu.is-open .mobile-link:nth-child(7) {
  transition-delay: 0.44s;
}

/* ---------- Timeline dot glow on reveal ---------- */
.tl-item.is-in .tl-dot {
  box-shadow:
    0 0 0 5px rgba(201, 162, 39, 0.14),
    0 0 22px 3px rgba(201, 162, 39, 0.4);
  transition: box-shadow 0.9s var(--ease-luxe);
}

/* ==========================================================================
   REDUCED MOTION
   ========================================================================== */

/* ========================================== */
/* SECTION: HERITAGE STYLES                   */
/* ========================================== */

/* ==========================================================================
   ULTIMATE CHESS â€” heritage.css
   Pinned, scroll-scrubbed "About" sequence.

   Every value that changes with scroll is a custom property written by
   js/heritage-scene.js. Nothing here animates on its own â€” the scroll
   position is the only clock, which is what keeps the piece, the copy,
   the lighting and the background locked to each other.
   ========================================================================== */

#heritageStage[hidden] {
  display: none;
}

.heritage-stage {
  /* --hs-p : 0..1 progress across the whole sequence
     --hs-i : index of the stage currently reading (0..n-1)
     --hs-hue: goldâ†’silverâ†’gold drift, written per frame                     */
  --hs-p: 0;
  --hs-key-x: 50%;
  --hs-key-y: 42%;
  --hs-key-c: 201, 162, 39;
  --hs-key-a: 0.18;
  position: relative;
}

/* The section itself is made tall by JS (height = 100vh * stages), so the
   viewport below can stick for the whole run. */
.hs-viewport {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  display: flex;
  align-items: center;
  isolation: isolate;
}

/* ==========================================================================
   BACKGROUND BEDS â€” cross-fade, never cut
   ========================================================================== */
.hs-beds {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hs-bed {
  position: absolute;
  inset: 0;
  opacity: 0;
  background:
    radial-gradient(ellipse at 50% 30%, var(--bed-b), transparent 62%),
    linear-gradient(180deg, var(--bed-a), #050506 88%);
  will-change: opacity;
}

/* Moving key light â€” the "lamp" the piece is lit by. */
.hs-keylight {
  position: absolute;
  inset: -20%;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(
    circle at var(--hs-key-x) var(--hs-key-y),
    rgba(var(--hs-key-c), var(--hs-key-a)),
    transparent 46%
  );
  filter: blur(14px);
  will-change: background;
}

/* Chessboard grid that scales/rotates with progress â€” a supporting graphic
   that reads as the board the piece is standing on. */
.hs-grid {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 150vmax;
  height: 150vmax;
  z-index: 1;
  pointer-events: none;
  opacity: 0.14;
  background-image:
    linear-gradient(rgba(201, 162, 39, 0.35) 1px, transparent 1px),
    linear-gradient(90deg, rgba(201, 162, 39, 0.35) 1px, transparent 1px);
  background-size: 83.2px 83.2px;
  mask-image: radial-gradient(ellipse at 50% 50%, #000 0%, transparent 58%);
  -webkit-mask-image: radial-gradient(
    ellipse at 50% 50%,
    #000 0%,
    transparent 58%
  );
  transform: translate3d(-50%, -50%, 0) rotateX(64deg)
    rotate(var(--hs-grid-r, 0deg)) scale(var(--hs-grid-s, 1));
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}

.hs-grain {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  opacity: 0.35;
}

/* ==========================================================================
   CHAPTER FIGURES â€” one cut-out per stage, cross-faded by JS
   ========================================================================== */
/* The copy column owns the left half, so the figures live in the right half.
   z-index 4 keeps them above the beds/grid/ring but under the copy (5) and
   the grain (6), so a headline never sits behind a figure. */
.hs-figures {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
}
.hs-figure {
  position: absolute;
  /* Moved off the right edge and in toward the middle of the stage. Still a
     right-anchor, just a much larger inset: growing `right` is what walks
     the figure leftward, and keeping the anchor on that side means the
     figure's own width never enters the sum, so nothing has to be retuned
     when max-width or the viewport changes.
     The floor stays modest on purpose. The copy column is the left
     min(100%,832px) of a 1700px wrap and the figure sits under it at a lower
     z-index, so on a ~1200px window a large fixed inset would slide the
     cut-out behind the headline instead of beside it. Scaling by vw keeps
     the shift proportional to the room actually available, and the 64px
     floor is what still clears the copy at the narrow end of desktop. */
  right: clamp(64px, 16vw, 320px);
  bottom: 0;
  height: min(84svh, 760px);
  width: auto;
  max-width: 46vw;
  object-fit: contain;
  object-position: bottom center;
  opacity: 0;
  /* Warmed and darkened slightly so the cut-outs sit inside the scene's
     gold key light instead of reading as pasted-on stock art. */
  filter: brightness(0.88) contrast(1.04) saturate(0.92)
    drop-shadow(0 30px 60px rgba(0, 0, 0, 0.55));
  /* Feathered foot â€” the figures are cut out at the ankle, and a hard edge
     against the bed gives away the mask. */
  mask-image: linear-gradient(180deg, #000 78%, transparent 99%);
  -webkit-mask-image: linear-gradient(180deg, #000 78%, transparent 99%);
  will-change: transform, opacity;
}

/* Orbiting dashed ring â€” position/rotation/scale scrubbed by JS. */
.hs-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  width: min(78vmin, 704px);
  aspect-ratio: 1;
  color: var(--gold, #c9a227);
  pointer-events: none;
  opacity: var(--hs-ring-o, 0.4);
  transform: translate3d(-50%, -50%, 0)
    translate3d(var(--hs-ring-x, 0px), var(--hs-ring-y, 0px), 0)
    rotate(var(--hs-ring-r, 0deg)) scale(var(--hs-ring-s, 1));
  will-change: transform, opacity;
}

/* ==========================================================================
   COPY STAGES
   ========================================================================== */
.hs-copy {
  position: relative;
  z-index: 5;
  width: 100%;
  pointer-events: none;
}
.hs-eyebrow {
  opacity: var(--hs-eyebrow-o, 1);
  transform: translate3d(0, var(--hs-eyebrow-y, 0px), 0);
  will-change: transform, opacity;
}

/* Slides are stacked; only transforms/opacity move, so they never reflow. */
.hs-slides {
  position: relative;
  margin-top: clamp(24px, 3vw, 44px);
  min-height: clamp(352px, 40vh, 480px);
}
.hs-slide {
  position: absolute;
  inset: 0 auto auto 0;
  width: min(100%, 832px);
  opacity: 0;
  transform: translate3d(0, 60px, 0);
  will-change: transform, opacity, filter;
}
.hs-index {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.08px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold, #c9a227);
}
.hs-title {
  margin-top: 17.6px;
  font-size: clamp(30.4px, 4.4vw, 67.2px);
}
.hs-copytext {
  margin-top: 24px;
  max-width: 672px;
  font-size: clamp(17.28px, 1.3vw, 20.8px);
  line-height: 1.8;
  color: rgba(200, 204, 212, 0.62);
}
.hs-copytext + .hs-copytext {
  margin-top: 16px;
}

/* ==========================================================================
   PROGRESS RAIL
   ========================================================================== */
.hs-rail {
  position: absolute;
  right: clamp(17.6px, 3vw, 51.2px);
  top: 50%;
  translate: 0 -50%;
  z-index: 7;
  height: min(38vh, 320px);
  pointer-events: auto;
}
/* The 1px track sits behind the labels; the fill is a child of it so it can
   grow from 0 to 100% without the labels inheriting the gradient. */
/* The track is pinned to the rail's right edge and the labels run leftward
   from it, so the rail always hugs the viewport edge no matter how long the
   chapter names are. */
.hs-rail-line {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: rgba(255, 255, 255, 0.12);
}
.hs-rail-fill {
  position: absolute;
  inset: 0 0 auto 0;
  height: calc(var(--hs-p) * 100%);
  background: linear-gradient(
    180deg,
    var(--gold-deep, #8a6d15),
    var(--gold-lite, #e8cf82)
  );
  box-shadow: 0 0 12px 1px rgba(201, 162, 39, 0.5);
}
.hs-rail-ticks {
  position: relative;
  height: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.hs-rail-ticks li {
  display: flex;
  justify-content: flex-end;
}
.hs-rail-ticks button {
  display: flex;
  align-items: center;
  flex-direction: row-reverse; /* dot on the track, label to its left */
  gap: 11.2px;
  padding: 4px 0;
  margin-right: -3.04px;
  background: none;
  border: 0;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.hs-rail-ticks i {
  flex: none;
  width: 6.72px;
  height: 6.72px;
  border-radius: 999px;
  border: 1px solid rgba(201, 162, 39, 0.5);
  background: var(--ink, #050506);
  transition:
    background 0.45s ease,
    box-shadow 0.45s ease,
    scale 0.45s ease;
}
.hs-rail-ticks span {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 9.28px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(200, 204, 212, 0.42);
  opacity: 0;
  translate: 6px 0;
  transition:
    opacity 0.45s ease,
    translate 0.45s ease,
    color 0.45s ease;
}
/* Passed stages keep a lit dot; only the current one shows its label. */
.hs-rail-ticks button.is-on i {
  background: var(--gold, #c9a227);
  box-shadow: 0 0 12px 2px rgba(201, 162, 39, 0.45);
  scale: 1.25;
}
.hs-rail-ticks button.is-current i {
  scale: 1.5;
}
.hs-rail-ticks button.is-current span,
.hs-rail-ticks button:hover span,
.hs-rail-ticks button:focus-visible span {
  opacity: 1;
  translate: 0 0;
}
.hs-rail-ticks button.is-current span {
  color: var(--gold, #c9a227);
}
.hs-rail-ticks button:focus-visible {
  outline: 1px solid var(--gold, #c9a227);
  outline-offset: 5.6px;
  border-radius: 3.2px;
}

/* When the cinematic stage is live, the plain timeline is redundant. */
body.hs-live #heritageFallback {
  display: none;
}

/* ==========================================================================
   RESPONSIVE â€” the sequence stays, it just breathes differently
   ========================================================================== */

/* ==========================================================================
   REDUCED MOTION â€” no pinning, no scrub, no 3D. Fall back to the timeline.
   ========================================================================== */

/* ========================================== */
/* SECTION: MATERIALS STYLES                  */
/* ========================================== */

/* ==========================================================================
   ULTIMATE CHESS â€” materials.css
   Pinned, scroll-scrubbed "Find your material" sequence.

   Same contract as heritage.css: nothing in here has its own clock. Every
   value that moves is a custom property written per-frame by
   js/materials-scene.js from a single scroll progress, which is what keeps
   the visual (left), the copy (right), the background and the supporting
   graphics locked to each other and perfectly reversible.
   ========================================================================== */

#materialStage[hidden] {
  display: none;
}

.mat-stage {
  /* --ms-p  : 0..1 progress across the whole sequence
     --ms-*  : per-frame scrubbed values, all written by JS               */
  --ms-p: 0;
  --ms-key-x: 28%;
  --ms-key-y: 46%;
  --ms-key-c: 201, 162, 39;
  /* The heading band now sits outside .ms-viewport, so the stage itself has
     to carry the ink base â€” otherwise that strip would read as a lighter
     seam above the beds, which bottom out at this same colour. */
  background: var(--ink, #050506);
  --ms-key-a: 0.2;
  position: relative;
}

/* Section height is set by JS (100vh * (n+1)); this sticks for the whole run
   and releases only once the last material has fully resolved. */
.ms-viewport {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  display: flex;
  align-items: center;
  isolation: isolate;
}

/* ==========================================================================
   BACKGROUND BEDS â€” cross-fade, never cut
   ========================================================================== */
.ms-beds {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.ms-bed {
  position: absolute;
  inset: 0;
  opacity: 0;
  background:
    radial-gradient(ellipse at 26% 34%, var(--bed-b), transparent 64%),
    linear-gradient(180deg, var(--bed-a), #050506 90%);
  will-change: opacity;
}

/* Moving key light â€” the lamp the material is lit by. Shares its colour with
   the copy accents so the whole frame agrees on one light source. */
.ms-keylight {
  position: absolute;
  inset: -20%;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(
    circle at var(--ms-key-x) var(--ms-key-y),
    rgba(var(--ms-key-c), var(--ms-key-a)),
    transparent 48%
  );
  filter: blur(16px);
  will-change: background;
}

/* Receding chessboard plane â€” the surface the material sits on. */
.ms-grid {
  position: absolute;
  left: 28%;
  top: 62%;
  width: 150vmax;
  height: 150vmax;
  z-index: 1;
  pointer-events: none;
  opacity: var(--ms-grid-o, 0.12);
  background-image:
    linear-gradient(rgba(201, 162, 39, 0.32) 1px, transparent 1px),
    linear-gradient(90deg, rgba(201, 162, 39, 0.32) 1px, transparent 1px);
  background-size: 80px 80px;
  mask-image: radial-gradient(ellipse at 50% 50%, #000 0%, transparent 55%);
  -webkit-mask-image: radial-gradient(
    ellipse at 50% 50%,
    #000 0%,
    transparent 55%
  );
  transform: translate3d(-50%, -50%, 0) rotateX(68deg)
    rotate(var(--ms-grid-r, 0deg)) scale(var(--ms-grid-s, 1));
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}

.ms-grain {
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  opacity: 0.32;
}

/* ==========================================================================
   LAYOUT â€” visual left, copy right
   ========================================================================== */
.ms-inner {
  position: relative;
  z-index: 5;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(32px, 4vw, 72px);
  align-items: center;
}

/* Column wrapper for the visual â€” the stack inside it does the moving. */
.ms-visual-col {
  position: relative;
  min-width: 0;
}

/* ==========================================================================
   LEFT â€” the product visual
   ========================================================================== */
.ms-visual {
  position: relative;
  aspect-ratio: 4/5;
  width: 100%;
  /* Height-bounded as well as width-bounded: at 4/5 a wide column would be
     taller than the viewport and the stack would burst out of the pinned
     frame. Capping against vh keeps it inside the sticky screen at every
     aspect ratio, and the ticks/halo sit outside it so it needs headroom. */
  /* Sized for its *painted* box, not its layout box: the scrubbed transform
     scales the stack up to ~1.09 and rotates it, so the base has to leave
     that headroom or the visual overhangs the column at peak scale. The
     svh cap is what keeps it clear of the centred heading above it â€” the
     column only owns the screen below the title. */
  max-width: min(400px, 30vw, 42svh);
  max-height: 56svh;
  margin-inline: auto;
  /* The stack itself drifts and turns as a unit; individual frames layer
     their own motion on top, which is what gives the parallax. */
  transform: translate3d(var(--ms-vis-x, 0px), var(--ms-vis-y, 0px), 0)
    rotate(var(--ms-vis-r, 0deg)) scale(var(--ms-vis-s, 1));
  will-change: transform;
}

/* Halo behind the stack, tinted by the same key colour. */
.ms-halo {
  position: absolute;
  inset: -14%;
  z-index: 0;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 46%,
    rgba(var(--ms-key-c), 0.28),
    transparent 62%
  );
  filter: blur(30px);
  opacity: var(--ms-halo-o, 0.8);
  transform: scale(var(--ms-halo-s, 1));
  will-change: transform, opacity;
}

/* Dashed orbit ring â€” a supporting graphic that turns with progress. */
.ms-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1;
  width: 118%;
  aspect-ratio: 1;
  color: var(--gold, #c9a227);
  pointer-events: none;
  opacity: var(--ms-ring-o, 0.34);
  transform: translate3d(-50%, -50%, 0) rotate(var(--ms-ring-r, 0deg))
    scale(var(--ms-ring-s, 1));
  will-change: transform, opacity;
}

/* Frames are stacked and only ever transform/fade, so nothing reflows and
   the whole crossfade stays on the compositor. */
.ms-frames {
  position: absolute;
  inset: 0;
  z-index: 2;
}
.ms-frame {
  position: absolute;
  inset: 0;
  opacity: 0;
  overflow: hidden;
  border-radius: 2px;
  transform-origin: 50% 55%;
  will-change: transform, opacity, filter;
  backface-visibility: hidden;
}
.ms-frame img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* Slight over-scale so the inner parallax never exposes an edge. */
  scale: 1.08;
  translate: 0 var(--ms-img-y, 0px);
  will-change: translate;
}
/* Hairline + inner vignette: makes each frame read as a mounted plate
   rather than a bare photo. */
.ms-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  box-shadow:
    inset 0 0 0 1px rgba(232, 207, 130, 0.16),
    inset 0 -90px 110px -60px rgba(5, 5, 6, 0.92);
}

/* Corner ticks â€” a small piece of instrumentation that reads as calipers. */
.ms-ticks {
  position: absolute;
  inset: -21.6px;
  z-index: 3;
  pointer-events: none;
  opacity: var(--ms-tick-o, 0.55);
}
.ms-ticks span {
  position: absolute;
  width: 18.4px;
  height: 18.4px;
  border: 1px solid rgba(201, 162, 39, 0.55);
}
.ms-ticks span:nth-child(1) {
  top: 0;
  left: 0;
  border-right: 0;
  border-bottom: 0;
}
.ms-ticks span:nth-child(2) {
  top: 0;
  right: 0;
  border-left: 0;
  border-bottom: 0;
}
.ms-ticks span:nth-child(3) {
  bottom: 0;
  left: 0;
  border-right: 0;
  border-top: 0;
}
.ms-ticks span:nth-child(4) {
  bottom: 0;
  right: 0;
  border-left: 0;
  border-top: 0;
}

/* Big ghost numeral behind the stack â€” one per material, cross-fading. */
.ms-numerals {
  position: absolute;
  left: -6%;
  bottom: -9%;
  z-index: 0;
  pointer-events: none;
  line-height: 1;
}
/* Mirrored when the visual sits in the right column, so the numeral always
   hangs off the stack's outer edge rather than into the copy. */
.ms-inner[data-side="1"] .ms-numerals {
  left: auto;
  right: -6%;
}
.ms-inner[data-side="1"] .ms-numeral {
  left: auto;
  right: 0;
}
.ms-numeral {
  position: absolute;
  left: 0;
  bottom: 0;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(96px, 13vw, 192px);
  font-weight: 700;
  color: transparent;
  -webkit-text-stroke: 1px rgba(232, 207, 130, 0.16);
  opacity: 0;
  white-space: nowrap;
  will-change: transform, opacity;
}

/* ==========================================================================
   RIGHT â€” the copy column
   ========================================================================== */
.ms-copy {
  position: relative;
}

/* ==========================================================================
   SECTION HEADING â€” centred, above the alternating columns
   ========================================================================== */
/* In normal flow above the pinned viewport â€” NOT sticky. It scrolls up and
   off like any other section heading; only .ms-viewport below it pins. */
.ms-head {
  position: relative;
  z-index: 6;
  text-align: center;
  padding-inline: 24px;
  padding-block: clamp(28.8px, 4.4vh, 51.2px) clamp(16px, 2.4vh, 25.6px);
}
/* Centred eyebrow: the rule that normally trails it would break the axis. */
.ms-head .eyebrow {
  justify-content: center;
}
.ms-head .section-title {
  margin-top: clamp(14.4px, 1.6vw, 22.4px);
  font-size: clamp(38.4px, 6vw, 86.4px);
  line-height: 1.02;
}

/* Panels stack in one box; height is reserved so the layout never jumps
   between materials of different copy length. */
.ms-panels {
  position: relative;
  /* Reserves height for the tallest material so the column never jumps
     between them. The panels are absolutely positioned, so anything this box
     does not reserve simply overflows and gets clipped by the viewport â€”
     which is what was cutting the features list and CTA off the bottom.
     Measured content runs ~490px, so the floor has to clear that. The old
     416px ceiling dated from when the heading overlaid the pinned screen and
     the column had to duck under it; the heading scrolls away now, so the
     column owns the full height and the cap is no longer needed. */
  min-height: clamp(496px, 46svh, 544px);
}
.ms-panel {
  position: absolute;
  inset: 0 auto auto 0;
  width: min(100%, 576px);
  opacity: 0;
  will-change: transform, opacity, filter;
}

.ms-index {
  display: flex;
  align-items: center;
  gap: 13.6px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.08px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold, #c9a227);
}
.ms-index::after {
  content: "";
  flex: 1;
  height: 1px;
  max-width: 80px;
  background: linear-gradient(90deg, rgba(201, 162, 39, 0.55), transparent);
}

.ms-title {
  margin-top: 16px;
  /* Subordinate to the centred section heading above it, and small enough
     that the longest material title still leaves room for the CTA. */
  font-size: clamp(27.2px, 2.9vw, 43.2px);
  line-height: 1.06;
}
.ms-sub {
  margin-top: 14.4px;
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 10.56px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(200, 204, 212, 0.44);
}
.ms-text {
  margin-top: 21.6px;
  max-width: 544px;
  font-size: clamp(14.4px, 1.02vw, 16.64px);
  line-height: 1.78;
  color: rgba(200, 204, 212, 0.62);
}

/* Features stagger in behind the headline â€” each row carries its own delay
   as a custom property so JS can drive them from one panel progress value. */
.ms-features {
  margin: 30.4px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 12px;
  max-width: 512px;
}
.ms-features li {
  display: flex;
  align-items: baseline;
  gap: 12.8px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  font-size: 13.76px;
  color: rgba(200, 204, 212, 0.7);
  opacity: var(--row-o, 0);
  transform: translate3d(var(--row-x, 18px), 0, 0);
  will-change: transform, opacity;
}
.ms-features li i {
  flex: none;
  margin-top: 2.4px;
  font-size: 13.12px;
  line-height: 1;
  color: var(--gold, #c9a227);
  filter: drop-shadow(0 0 6px rgba(201, 162, 39, 0.5));
  font-style: normal;
}
.ms-features li b {
  font-weight: 500;
  color: var(--silverlt, #eef1f6);
}

.ms-actions {
  margin-top: 33.6px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 17.6px;
  opacity: var(--row-o, 0);
  transform: translate3d(var(--row-x, 18px), 0, 0);
  will-change: transform, opacity;
}
.ms-price {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 11.52px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(200, 204, 212, 0.5);
}
.ms-price b {
  color: var(--goldlite, #e8cf82);
  font-weight: 500;
}

/* Only the panel actually on screen may be clicked or tabbed into. */
.ms-panel[aria-hidden="true"] {
  pointer-events: none;
}
.ms-panel[aria-hidden="false"] {
  pointer-events: auto;
}

/* ==========================================================================
   PROGRESS RAIL
   ========================================================================== */
.ms-rail {
  position: absolute;
  /* The track hugs this edge and the labels run leftward from it. The dot
     sits ~3px past the track, so the offset has to clear both the dot and
     its glow or the current chapter's label is cut by the frame edge. */
  right: clamp(25.6px, 3.6vw, 57.6px);
  padding-right: 8px;
  top: 50%;
  translate: 0 -50%;
  z-index: 7;
  height: min(34vh, 288px);
  pointer-events: auto;
}
.ms-rail-line {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: rgba(255, 255, 255, 0.12);
}
.ms-rail-fill {
  position: absolute;
  inset: 0 0 auto 0;
  height: calc(var(--ms-p) * 100%);
  background: linear-gradient(
    180deg,
    var(--gold-deep, #8a6d15),
    var(--gold-lite, #e8cf82)
  );
  box-shadow: 0 0 12px 1px rgba(201, 162, 39, 0.5);
}
.ms-rail-ticks {
  position: relative;
  height: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.ms-rail-ticks li {
  display: flex;
  justify-content: flex-end;
}
.ms-rail-ticks button {
  display: flex;
  align-items: center;
  flex-direction: row-reverse; /* dot on the track, label to its left */
  gap: 11.2px;
  padding: 4px 0;
  margin-right: -3.04px;
  background: none;
  border: 0;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.ms-rail-ticks i {
  flex: none;
  width: 6.72px;
  height: 6.72px;
  border-radius: 999px;
  border: 1px solid rgba(201, 162, 39, 0.5);
  background: var(--ink, #050506);
  transition:
    background 0.45s ease,
    box-shadow 0.45s ease,
    scale 0.45s ease;
}
.ms-rail-ticks span {
  font-family:
    "Inter",
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: 9.28px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(200, 204, 212, 0.42);
  opacity: 0;
  translate: 6px 0;
  transition:
    opacity 0.45s ease,
    translate 0.45s ease,
    color 0.45s ease;
}
.ms-rail-ticks button.is-on i {
  background: var(--gold, #c9a227);
  box-shadow: 0 0 12px 2px rgba(201, 162, 39, 0.45);
  scale: 1.25;
}
.ms-rail-ticks button.is-current i {
  scale: 1.5;
}
.ms-rail-ticks button.is-current span,
.ms-rail-ticks button:hover span,
.ms-rail-ticks button:focus-visible span {
  opacity: 1;
  translate: 0 0;
}
.ms-rail-ticks button.is-current span {
  color: var(--gold, #c9a227);
}
.ms-rail-ticks button:focus-visible {
  outline: 1px solid var(--gold, #c9a227);
  outline-offset: 5.6px;
  border-radius: 3.2px;
}

/* Rail navigation switched off. The progress track is redundant against the
   copy, which already names and numbers each material. Hidden rather than
   deleted so the markup and its JS click bindings stay intact â€” re-enable by
   removing this one rule. Placed after the rail block so it wins on order. */
.ms-rail {
  display: none;
}

/* When the pinned sequence is live, the plain tile grid is redundant. */
body.ms-live #materialFallback {
  display: none;
}

/* ==========================================================================
   RESPONSIVE â€” the sequence stays; the two halves stack.
   ========================================================================== */

/* ==========================================================================
   REDUCED MOTION â€” no pinning, no scrub. The tile grid is the section.
   ========================================================================== */

/* ==========================================================================
   "FIND YOUR MATERIAL" â€” IMAGE SIZING
   Scoped to #categories so only this section's visuals change. The ID keeps
   these ahead of the width-based .tile overrides in responsive.css, which
   would otherwise re-shrink the grid below 1024px.
   ========================================================================== */

/* Pinned stage: give the scrubbed frame stack more of the sticky screen.
   The svh caps still bound it, so it cannot outgrow the pinned viewport or
   collide with the centred heading above it.

   Scaled up toward the About section's figure presence (.hs-figure runs to
   min(84svh,760px)). It cannot go the whole way: .hs-figure is bottom-
   anchored in a full-bleed viewport and is free to bleed off it, while this
   stack is a grid column sharing the pinned screen with the centred heading
   above and the copy column beside it. These caps are what that frame
   allows â€” and the painted box is larger still, since the scrub scales the
   stack to ~1.09 and the halo/ring sit outside it.

   Note the 4/5 aspect-ratio makes the width caps govern height too: the
   third `min()` term is a height-derived width bound, so it has to rise
   with max-height or it silently pins the visual at the old size. */
.ms-visual {
  max-width: min(600px, 44vw, 63svh);
  max-height: 78svh;
}

/* Short screens (small phones, landscape): the stacked visual and the copy
   cannot both have their full share of a ~640px viewport. The copy is the
   part that must stay whole, so the visual yields and the panel reservation
   comes down to what the text actually needs at this size. */

/* Fallback tile grid: wider tiles, and a floor so short viewports still get
   a substantial image rather than a letterboxed sliver. */
#categories .tile {
  aspect-ratio: 11/9;
  min-height: 272px;
}

/* ==========================================================================
   "FIND YOUR MATERIAL" â€” BORDERLESS PRESENTATION
   The visuals here read as mounted plates: a hairline frame, caliper corner
   ticks and a hard rounded edge. The heritage/About cut-outs (.hs-figure)
   carry none of that â€” they are unframed and feathered into the scene, and
   that is the treatment this section is aligned to.

   Only the framing is removed. The scrubbed transforms, the crossfade, the
   inner parallax, the halo/ring graphics, the hover zoom and the tile
   labels are all untouched.
   ========================================================================== */

/* Pinned stage frames: no hairline, and no vignette either. The inset
   shadow was the plate's backing â€” with the frame gone it reads as a dark
   wash behind the lower half of the image rather than as lighting. The
   ::after box is kept (emptied) so nothing else that targets it breaks. */
#categories .ms-frame {
  border-radius: 0;
}
#categories .ms-frame::after {
  box-shadow: none;
}

/* The halo is the other thing painting behind the image: a gold radial
   tint sized to the frame box, which with no frame edge to justify it
   shows up as a coloured ground. Removed rather than hidden, so the JS
   that scrubs --ms-halo-o / --ms-halo-s keeps running without effect. */
#categories .ms-halo {
  background: none;
}

/* Contain rather than cover: the frames now sit on the bare bed, so the
   image is shown whole the way the About cut-outs are, instead of being
   cropped to fill a plate that no longer exists.

   The base rule's `scale:1.08` was overscan â€” bleed so the inner parallax
   (`translate: 0 var(--ms-img-y)`) could never drag a cropped edge into
   view. Under `contain` there is nothing to hide behind, so the overscan
   just crops the image it is meant to protect. Dropped to 1, and the
   parallax translate is left alone: it still runs, moving the whole
   contained image rather than sliding a crop window over it. */
#categories .ms-frame img {
  object-fit: contain;
  object-position: center;
  scale: 1;
  /* Warmed to sit in the section's key light, as .hs-figure is. `contain`
     removes the plate that used to do this, so the lighting moves onto the
     image. Softer than the About values because these are product shots on
     a lit bed, not cut-outs against a gradient. */
  filter: brightness(0.94) contrast(1.03) saturate(0.96)
    drop-shadow(0 26px 52px rgba(0, 0, 0, 0.5));
}

/* Feathered foot only, matching .hs-figure. The symmetric top/bottom fade
   that replaced the frame was safe while the image was `cover`-cropped with
   1.08 overscan â€” the fade only ever touched overscan, never artwork. Under
   `contain` the real edges sit inside the box, so a top fade would cut into
   the image itself. Fading just the last stretch keeps the About-style
   dissolve into the bed without clipping anything. */
#categories .ms-frame {
  mask-image: linear-gradient(180deg, #000 82%, transparent 99%);
  -webkit-mask-image: linear-gradient(180deg, #000 82%, transparent 99%);
}

/* Caliper corner ticks are frame instrumentation; with no frame to measure
   they read as a border. Hidden, not removed â€” JS still scrubs --ms-tick-o
   and that stays harmless. */
#categories .ms-ticks {
  display: none;
}

/* Fallback tile grid: no outline, no boxed hover ring. The veil gradient and
   the label keep the caption legible, and the hover zoom is preserved. */
#categories .tile {
  border: 0;
  border-radius: 0;
  background: transparent;
  backdrop-filter: none;
}
#categories .tile:hover {
  border-color: transparent;
  /* Ambient lift only â€” no rectangular glow tracing the tile edge. */
  box-shadow: 0 34px 70px -42px rgba(0, 0, 0, 0.95);
}
/* The opaque sub-panel background exists so small copy never sits over the
   board. These tiles carry only a large label on its own veil, so they can
   stay transparent in both the normal and reduced-transparency cases. */

/* ========================================== */
/* SECTION: SLICK THEME STYLES                */
/* ========================================== */

/* ==========================================================================
   ULTIMATE CHESS â€” slick-theme.css
   Skins the Slick carousels (Featured / Best Sellers / New Arrivals) to the
   house palette. Loaded after slick.css + slick-theme.css (CDN) so these rules
   win. Custom prev/next arrows live in the section headers (.rail-btn); Slick's
   own arrows stay disabled. Only the dots + track spacing are themed here.
   ========================================================================== */

/* ---- Slider wrapper: give the track room and kill layout jump on load ---- */
.uc-slider {
  position: relative;
}

/* Before Slick initialises, the raw <article> children would stack full-width.
   Constrain them so the pre-init flash matches the grid rather than a tall
   column, then Slick takes over. */
.uc-slider:not(.slick-initialized) {
  display: flex;
  gap: 24px;
  overflow: hidden;
}
.uc-slider:not(.slick-initialized) > * {
  flex: 0 0 calc(33.333% - 16px);
  min-width: 0;
}

/* ---- Gutters between slides (the grids used gap; recreate it here) ---- */
/* align-items:stretch alone is not enough: Slick writes an inline height on
   .slick-track only with adaptiveHeight, and leaves each .slick-slide at its
   own content height otherwise. `height:auto` then lets a short card sit
   shorter than a tall one, and the loop clones — which enter the track at a
   different moment than the originals — end up measured against a different
   tallest sibling, which is what produced the jump on wrap.
   Forcing every slide (original and clone alike) to `height:auto !important`
   plus a stretch flex chain makes the tallest card in the *whole* track set
   the row height, so wrapping can never change it. */
.uc-slider .slick-track {
  display: flex !important;
  align-items: stretch;
}
.uc-slider .slick-slide {
  height: auto !important;
  margin: 0 12px;
  display: flex;
  align-items: stretch;
  transform: none !important;
  float: none;
}
/* When slidesToShow > 1 Slick wraps each slide's contents in an anonymous
   <div>. That wrapper must also stretch, or the card inside it collapses back
   to content height and the equal-height chain is broken one level down. */
.uc-slider .slick-slide > div {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
  min-width: 0;
}
/* Slick needs .slick-list to clip the track horizontally, otherwise every
   slide (and its infinite clones) shows at once and the carousel can't move.
   overflow MUST stay hidden â€” the -12px side margins reclaim the first/last
   slide's outer gutter, and the vertical padding gives the hover lift + shadow
   room inside the clipped box instead of switching overflow to visible. */
.uc-slider .slick-list {
  margin: 0 -12px;
  overflow: hidden;
  padding-block: 14px;
}

/* Cards inside a slide must fill the slide and shed any fixed flex width the
   rail layout gave them, so Slick controls the sizing. */
.uc-slider .slick-slide > .product-card,
.uc-slider .slick-slide > .arrival-card,
.uc-slider .slick-slide > .rail-card,
.uc-slider .slick-slide > .testi-card {
  height: 100%;
  flex: 1 1 auto !important; /* override .rail-card flex:0 0 clamp(...) */
  margin: 0;
}

/* The Best Sellers rail reads edge-to-edge on the page; add the section's
   original horizontal breathing room back onto the list. */
.uc-slider--edge {
  padding-inline: clamp(20px, 4vw, 56px);
}

/* ---- Dots ---- */
.uc-slider .slick-dots {
  position: static;
  margin-top: 36px;
  display: flex !important;
  justify-content: center;
  gap: 8.8px;
}
.uc-slider .slick-dots li {
  width: auto;
  height: auto;
  margin: 0;
}
.uc-slider .slick-dots li button {
  width: auto;
  height: auto;
  padding: 0;
}
.uc-slider .slick-dots li button:before {
  content: "";
  position: static;
  display: block;
  width: 22px;
  height: 3px;
  border-radius: 999px;
  background: rgba(200, 204, 212, 0.22);
  opacity: 1;
  transition:
    background 0.4s var(--ease-luxe),
    width 0.4s var(--ease-luxe);
}
.uc-slider .slick-dots li.slick-active button:before {
  width: 40px;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold-lite));
}
.uc-slider .slick-dots li button:hover:before {
  background: rgba(201, 162, 39, 0.6);
}

/* Slick's loop clones are never tracked by GSAP/ScrollTrigger, so if a clone
   is made from a card that still carries the reveal state it stays at
   opacity:0 forever — a full-width but invisible slide, which is what read as
   "blank space" at the wrap from the last slide back to the first. Inside a
   slider the reveal animation has no purpose anyway (the cards arrive by
   sliding, not by scrolling into view), so hard-clear it for every slide and
   its descendants, clones included. */
.uc-slider .slick-slide [data-reveal],
.uc-slider .slick-slide[data-reveal],
.uc-slider .slick-cloned [data-reveal],
.uc-slider .slick-cloned[data-reveal] {
  opacity: 1 !important;
  transform: none !important;
  filter: none !important;
}

/* ---- Disable Slick's built-in arrows (we use the .rail-btn header nav) ---- */
.uc-slider .slick-prev,
.uc-slider .slick-next {
  display: none !important;
}

/* ---- Grab cursor while dragging ---- */
.uc-slider .slick-list {
  cursor: grab;
}
.uc-slider .slick-list:active {
  cursor: grabbing;
}

/* Focus ring on keyboard-focused slides shouldn't be clipped. */
.uc-slider .slick-slide:focus {
  outline: none;
}
.uc-slider .slick-slide:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ---- Reduced motion: dots still fine, autoplay is disabled in JS ---- */

/* ========================================== */
/* SECTION: RESPONSIVE STYLES                 */
/* ========================================== */

/* ==========================================================================
   ULTIMATE CHESS â€” responsive.css
   Breakpoint refinements. Base styles are mobile-safe; these tune the edges.
   Order: large â†’ small (plus a few min-width enhancements at the end).
   ========================================================================== */

/* ==========================================================================
   3XL â€” ultra wide (1800px+)
   ========================================================================== */

/* ==========================================================================
   DESKTOP / LAPTOP (max 1280px)
   ========================================================================== */

/* ==========================================================================
   TABLET (max 1024px)
   ========================================================================== */

/* ==========================================================================
   SMALL TABLET / LARGE MOBILE (max 768px)
   ========================================================================== */

/* ==========================================================================
   MOBILE (max 600px)
   ========================================================================== */

/* ==========================================================================
   SMALL MOBILE (max 400px)
   ========================================================================== */

/* ==========================================================================
   ORIENTATION â€” short landscape phones
   ========================================================================== */

/* ==========================================================================
   INPUT CAPABILITY â€” hover-capable pointers only
   ========================================================================== */

/* ==========================================================================
   CHESSBOARD BACKDROP â€” section transparency
   The fixed board on body::before is only visible where the page lets it
   through, so the full-bleed section fills become translucent warm-dark
   washes instead of opaque charcoal. Cards, modals, header and menu keep
   their solid fills â€” they need to stay readable over the pattern.
   ========================================================================== */
/* Opacity raised and paired with a blur: the board still shows through as a
   warm texture, but square edges no longer cut across lines of type. The blur
   is what actually protects readability — it destroys the hard checker edge
   while keeping the tonal variation that makes the backdrop worth having. */
main > section.bg-charcoal,
main > section.bg-ink,
footer.bg-charcoal {
  background-color: rgb(20 12 6 / 0.88);
}

/* The blur is applied separately and NOT to sections holding a pinned scene:
   backdrop-filter makes an element the containing block for fixed/sticky
   descendants, which would unpin .hs-viewport / .ms-viewport exactly the way
   `overflow:hidden` on <html> once did (see the note at the top of this file).
   Those two sections keep the opaque wash above, which is what carries the
   readability anyway — the blur is only edge-softening on top of it. */
main > section.bg-charcoal:not(:has(.hs-viewport)):not(:has(.ms-viewport)),
main > section.bg-ink:not(:has(.hs-viewport)):not(:has(.ms-viewport)),
footer.bg-charcoal {
  backdrop-filter: blur(6px);
}

/* Alternating sections sit slightly lighter, so scrolling reads as moving
   across the board rather than under one continuous sheet. */
main > section.bg-charcoal:nth-of-type(even) {
  background-color: rgb(30 18 9 / 0.86);
}

/* The travelling-piece softening must still win over the rules above. */
body.piece-travelling main > section.bg-charcoal {
  background-color: rgb(20 12 6 / 0.82);
}

/* Sub-panels that sit inside a section and previously relied on an opaque
   parent. These carry the smallest text on the page, so they go fully opaque
   — the board reads around them, never behind their copy. */
.product-card,
.tile,
.testi-card,
.arrival-card {
  backdrop-filter: blur(12px);
  background-color: rgb(14 10 6 / 0.97);
}

/* The board is decorative; on reduced-transparency setups drop back to a
   flat warm dark so nothing competes with the copy. */

/* ==========================================================================
   PRINT
   ========================================================================== */

/* ==========================================================================
   RESPONSIVE / MEDIA QUERIES  (largest breakpoint -> smallest)
   ========================================================================== */

@media (min-width: 1800px) {
  :root {
    --pad-x: 72px;
    --sec-y: 83.2px;
  }
  .section-title {
    font-size: clamp(54.4px, 4.4vw, 92.8px);
  }
  .collection-card {
    min-height: 368px;
  }
}
@media (max-width: 1280px) {
  .hs-figure {
    right: 80px;
  }
  .pt-28 {
    padding-top: 3rem !important;
  }
  .mobile-link span {
    font-family:
      "Inter",
      -apple-system,
      BlinkMacSystemFont,
      sans-serif;
    font-size: clamp(20.6px, 5vw, 26.4px);
  }
  .hs-slide {
    width: min(100%, 552px);
  }
}

@media (min-width: 1024px) {
  #siteHeader.is-solid > div {
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }

  .brand-layout {
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    grid-template-areas:
      "lead   score"
      "ledger ledger";
    gap: 4.5rem 4rem;
    align-items: start;
  }
  .brand-copy {
    font-size: 1.125rem;
  }
  .brand-ledger {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .brand-ledger > div {
    border-bottom: 0;
  }
  .brand-ledger > div + div {
    padding-left: 2.25rem;
    border-left: 1px solid rgba(255, 255, 255, 0.08);
  }

  .foot-grid {
    grid-template-columns: 1.6fr repeat(3, minmax(0, 1fr));
  }
  .foot-brand {
    grid-column: auto;
  }

  .ms-inner {
    /* No top reservation: the heading now scrolls above the pinned viewport
       rather than overlaying it, so the columns own the full sticky screen
       and centre in it. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    /* Symmetric gutters. The columns swap sides per material, so the frame
       has to look the same mirrored â€” an asymmetric pad would make every
       other material sit visibly off-centre. */
    padding-inline: clamp(72px, 7vw, 128px);
  }

  /* ---- Alternation ----
     Odd-indexed materials swap the columns: visual right, copy left. Grid
     column assignment is the only thing that changes â€” both columns keep
     their own styling, so nothing has to be duplicated per side. The value
     is a hard 0/1 written by JS at the seam midpoint, so the swap happens
     while both materials are mid-dissolve and is never seen as a jump. */
  .ms-visual-col {
    grid-column: 1;
    grid-row: 1;
  }
  .ms-copy {
    grid-column: 2;
    grid-row: 1;
  }
  .ms-inner[data-side="1"] .ms-visual-col {
    grid-column: 2;
  }
  .ms-inner[data-side="1"] .ms-copy {
    grid-column: 1;
  }
}
@media (max-width: 991px) {
  .hs-figure {
    top: 30% !important;
  }
  /* .ms-inner / .ms-visual sizing for this range now lives in the
   "FIND YOUR MATERIAL â€” VISUAL VISIBILITY (max 1024px)" block below. The
   78svh !important cap that used to sit here is what let the visual grow
   past the pinned viewport and get clipped, so it is deliberately gone. */
  .foot-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 8px;
    padding-bottom: 20px;
    align-items: start;
  }
  .brand-copy {
    max-width: 100%;
  }
  .hero-cinema .hero-text-front {
    font-size: 7vw;
  }
  .mb-14 {
    margin-bottom: 1.5rem;
  }
}

/* ==========================================================================
   TABLET (992px â€“ 1024px) â€” right-column visuals sit centred
   At this width the two-column desktop rules are still in force, but the
   About figure is bottom-anchored (`bottom:0`) and the material stack keeps
   its desktop caps, so both images drop low in the pinned frame instead of
   sitting beside their copy. Anchor them to the vertical middle instead.
   ========================================================================== */
@media (min-width: 992px) and (max-width: 1024px) {
  /* About â€” release the bottom anchor and centre on the stage. */
  .hs-figure {
    top: 50%;
    bottom: auto;
    right: clamp(40px, 8vw, 96px);
    height: min(70svh, 620px);
    max-width: 44vw;
    object-position: center;
    /* The scrubbed transform on this element is written by JS as a full
       `transform` string, so the centring offset cannot live there â€” it
       would be overwritten on the first scroll frame. Margin does the same
       job and is untouched by the animation. */
    margin-top: min(-35svh, -310px);
    mask-image: none;
    -webkit-mask-image: none;
  }

  /* Find your material â€” both columns share the pinned screen's middle. */
  .ms-inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    padding-inline: clamp(32px, 5vw, 64px);
  }
  .ms-visual {
    align-self: center;
    max-width: min(360px, 38vw, 48svh);
    max-height: 62svh;
    margin-block: auto;
  }
}

/* ==========================================================================
   "FIND YOUR MATERIAL" â€” VISUAL VISIBILITY (max 1024px)
   The pinned stage is `height:100svh; overflow:hidden`, so whatever the two
   rows do not fit inside that screen is simply clipped away. Below the
   desktop breakpoint `.ms-inner` falls back to its single-column default,
   and `.ms-panels` alone reserves clamp(496px,46svh,544px) plus the grid
   gap â€” more than a 1024x768 tablet has. The visual is the first row, so it
   was the part pushed past the clipped top edge and never seen.

   Note `.ms-visual-col` does not exist in the markup: `.ms-visual` is itself
   the grid item, so the column rules elsewhere in this file that target the
   wrapper never match. Everything here addresses `.ms-visual` directly.

   Two columns keep the visual beside the copy rather than stacked above it,
   and both rows are re-capped against svh so the pair actually fits.
   ========================================================================== */
@media (max-width: 1024px) {
  .ms-inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(20px, 3vw, 40px);
    padding-inline: clamp(20px, 4vw, 48px);
  }

  /* The visual is the grid item itself â€” centre it in its own row and cap it
     against the sticky screen so the stack, its halo and its ticks all land
     inside the clipped frame. */
  .ms-visual {
    align-self: center;
    max-width: min(340px, 42vw, 44svh);
    max-height: 52svh;
    margin-inline: auto;
  }

  /* The copy column has to yield too: its reservation is what overflowed the
     screen in the first place, and at two columns it no longer needs to
     reserve for the desktop line lengths. */
  .ms-panels {
    min-height: min(430px, 60svh);
  }
  .ms-panel {
    width: 100%;
  }
}

/* Below the two-column fallback the stage genuinely runs out of width, so the
   columns stack â€” and then the reservations have to come down again or the
   visual is clipped for the same reason as above. */
@media (max-width: 640px) {
  .ms-inner {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(12px, 3vw, 24px);
  }
  /* Banner mode: the visual sits above the copy and is bounded by height
     rather than width, because the copy â€” not the image â€” is what has to
     stay above the fold on a phone. */
  .ms-visual {
    aspect-ratio: 1;
    max-width: min(300px, 60vw);
    max-height: 30svh;
  }
  .ms-panels {
    min-height: min(430px, 52svh);
  }
}

/* ==========================================================================
   "THE HOUSE" â€” COMPACT TABLET/MOBILE (max 1024px)
   Below the desktop breakpoint the layout stacks to a single column, so the
   section's desktop rhythm (3.5rem grid gap, 2.25rem ledger cells, 1.375rem
   hand names) turns into a very long scroll for what is a short amount of
   copy. Everything here tightens spacing and type only â€” no structural
   change, so the stacked order and the divider logic stay as they are.
   ========================================================================== */
@media (max-width: 1024px) {
  .brand-layout {
    gap: 2rem 0;
  }

  .brand-title {
    margin-top: 1.1rem;
  }
  .brand-copy {
    margin-top: 1.1rem;
    font-size: 0.9375rem;
    line-height: 1.65;
  }
  .brand-signature {
    margin-top: 1.35rem;
  }

  /* The score panel: smaller inset, tighter rows, smaller hand names. */
  .brand-score {
    padding: 1.25rem 1.15rem 1.1rem;
    border-radius: 16px;
  }
  .brand-score-head {
    padding-bottom: 0.75rem;
  }
  .brand-hands li {
    padding: 0.5rem 0;
    gap: 0.85rem;
  }
  .bh-name {
    font-size: 1.125rem;
  }
  .brand-score-foot {
    padding-top: 0.75rem;
    font-size: 0.75rem;
  }

  /* Ledger cells lose most of their vertical padding â€” at two columns the
     numerals already have plenty of air from their own line-height. */
  .brand-ledger > div {
    padding: 1.15rem 1rem 1rem 0;
  }
  .counter-num {
    font-size: clamp(30px, 4.4vw, 40px);
  }
  .counter-cap {
    margin-top: 6px;
  }
}

@media (min-width: 900px) {
  .foot-rail {
    grid-template-columns: minmax(0, 1.15fr) minmax(360px, 0.85fr);
  }
  .foot-rail form {
    padding-bottom: 6px;
  }
}
@media (max-width: 880px) {
  .hs-figure {
    right: 43% !important;
  }
  .hs-copytext {
    font-size: clamp(14.28px, 1.3vw, 20.8px);
  }
  .hs-slide {
    width: 68%;
  }
}

@media (min-width: 768px) {
  .pillar-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .foot-bottom {
    flex-direction: row;
    justify-content: space-between;
    text-align: left;
  }
  /* #toTop is position:fixed at bottom-right and sits over this row once the
     page is scrolled to the end; reserve its width so the last legal link is
     never tucked underneath it. */
  .foot-bottom .foot-legal {
    padding-right: 64px;
  }
  .section-title {
    font-size: clamp(24.6px, 7.4vw, 30.4px) !important;
  }
}

@media (max-width: 1280px) {
  :root {
    --sec-y: clamp(28.8px, 3.6vw, 51.2px);
  }

  .glow-orb {
    width: min(544px, 92vw);
    filter: blur(96px);
  }
  .collection-card {
    min-height: 304px;
  }
}

@media (max-width: 1024px) {
  /* Tighten the vertical rhythm between sections by 50% on tablet and below. */
  :root {
    --pad-x: clamp(20px, 4vw, 36px);
    --sec-y: clamp(14.4px, 1.8vw, 25.6px);
  }

  .hero-chess-wrapper {
    width: 52%;
    right: auto;
    opacity: 0.28;
  }
  #hero.hero-ready .hero-chess-wrapper {
    animation: heroFadeInSoft 1s ease 0.5s forwards;
  }
  @keyframes heroFadeInSoft {
    to {
      opacity: 0.28;
    }
  }

  /* Hero sizing is owned by the .hero-container rules in animation.css. */
  .hero-container {
    min-height: calc(100dvh - var(--header-h));
  }
  .hero-content {
    padding: 56px 20px 96px;
  }

  .hero-container.hero-photo {
    min-height: 100dvh;
  }
  .hero-photo .hero-content {
    padding: calc(var(--header-h) + 40px) clamp(24px, 6vw, 48px) 104px;
    font-size: clamp(40px, 8.4vw, 84px);
  }

  .hero-cinema .hero-content {
    padding: calc(var(--header-h) + 32px) var(--hero-inset)
      clamp(88px, 10vh, 112px);
    font-size: clamp(40px, 8.6vw, 86px);
  }
  .hero-cinema .hero-col {
    max-width: none;
  }

  .hero-inner .hero-content {
    padding: calc(var(--header-h) + 30px) var(--hero-inset)
      clamp(44px, 6vh, 64px);
    font-size: clamp(36px, 7.4vw, 68px);
  }
  .hero-inner .hero-col {
    max-width: none;
  }

  #categories .tile {
    aspect-ratio: 4/3;
    min-height: 248px;
  }

  .uc-slider:not(.slick-initialized) > * {
    flex: 0 0 calc(50% - 12px);
  }

  /* Cards stop trying to span rows */
  .collection-card,
  .collection-card.lg\:row-span-2 {
    min-height: 288px !important;
  }

  .product-media {
    aspect-ratio: 1/1;
  }
  .arrival-media {
    aspect-ratio: 4/3;
  }
  .tile {
    aspect-ratio: 16/10;
  }

  .timeline {
    padding-left: 25.6px;
  }
  .tl-dot {
    left: -32.8px;
  }

  .testi-quote {
    font-size: 15.2px;
    line-height: 1.75;
  }

  /* Disable 3D tilt on touch-first widths â€” it fights with scrolling */
  [data-tilt] {
    transform: none !important;
  }
}

@media (max-width: 1023px) {
  .brand-title {
    max-width: none;
  }

  /* Slider arrows stay beside the section heading below the lg: breakpoint
     instead of dropping to their own row under it. The header wrappers use
     Tailwind's lg:flex-row / lg:justify-between, which stop applying here, so
     the row layout is re-stated on the nav's parent. */
  .slider-nav {
    flex: 0 0 auto;
  }
  :is(div, header):has(> .slider-nav) {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
  }
  :is(div, header):has(> .slider-nav) > :not(.slider-nav) {
    min-width: 0;
  }

  /* Smaller tap targets so the pair doesn't crowd the headline. */
  .rail-btn {
    width: 40px;
    height: 40px;
    font-size: 13px;
  }

  /* The piece flies above the copy at this width, so the text sits low. */
  .hs-viewport {
    align-items: flex-end;
  }
  .hs-copy {
    padding-bottom: clamp(64px, 12vh, 112px);
  }
  /* Copy runs the full width here, so the figure retreats upward and dims
     rather than competing with the headline for the same pixels. */
  .hs-figure {
    right: 50%;
    transform-origin: 50% 0;
    bottom: auto;
    top: 0;
    height: min(52svh, 460px);
    max-width: 74vw;
    margin-right: -37vw;
    opacity: 0;
    filter: brightness(0.72) contrast(1.02) saturate(0.86)
      drop-shadow(0 22px 44px rgba(0, 0, 0, 0.6));
    mask-image: linear-gradient(180deg, #000 62%, transparent 96%);
    -webkit-mask-image: linear-gradient(180deg, #000 62%, transparent 96%);
  }
  .brand-copy {
    max-width: 100%;
    font-size: 0.8rem;
  }
  .brand-ledger {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    border-top: 1px solid rgba(255, 255, 255, 0.1);
  }

  .ms-viewport {
    align-items: center;
  }
  .ms-inner {
    padding-block: clamp(24px, 4svh, 40px);
    align-content: center;
  }
  .ms-head {
    padding-block: clamp(22.4px, 3.6svh, 32px) clamp(11.2px, 2vh, 16px);
  }
  .ms-head .section-title {
    margin-top: 11.2px;
    font-size: clamp(28px, 7vw, 41.6px);
  }
  .ms-numerals {
    display: none;
  }
  .ms-rail {
    right: 16px;
    height: 22vh;
  }
  .ms-rail-ticks span {
    display: none;
  }
  .ms-grid {
    background-size: 54.4px 54.4px;
  }

  .ms-panel {
    width: 100%;
  }
}

@media (max-width: 1023px) and (max-height: 700px) {
  /* Short landscape. The type steps down so the copy fits the reduced height;
     the reservation is deliberately modest because above 640px the copy now
     sits in its own column rather than under the visual, so a tall floor here
     would push the whole grid past the pinned viewport and clip the image. */
  .ms-panels {
    min-height: min(360px, 68svh);
  }
  .ms-title {
    font-size: clamp(22.4px, 5.6vw, 28.8px);
  }
  .ms-text {
    font-size: 12.64px;
    line-height: 1.55;
    margin-top: 11.2px;
  }
  .ms-features {
    margin-top: 12.8px;
    gap: 5.6px;
  }
  .ms-features li {
    font-size: 11.68px;
    padding-bottom: 5.6px;
  }
  .ms-actions {
    margin-top: 14.4px;
  }
}

@media (max-width: 768px) {
  :root {
    --sec-y: clamp(12.8px, 2.4vw, 19.2px);
  }

  /* The left-weighted veil assumes a wide frame; on narrow screens the copy
     spans the full width, so the grading flips to a vertical wash instead. */
  .hero-photo .hero-bg-veil {
    background: linear-gradient(
      180deg,
      rgba(4, 4, 6, 0.8) 0%,
      rgba(4, 4, 6, 0.6) 40%,
      rgba(4, 4, 6, 0.94) 100%
    );
  }

  /* The rail needs frame width it no longer has; the copy takes the full
     measure and the grid coarsens so the verticals stay readable. */
  .hero-cinema .hero-rail {
    display: none;
  }
  .hero-cinema .hero-grid-lines {
    background-size: 25% 100%;
  }
  .hero-cinema .hero-bg-veil {
    background: linear-gradient(
      180deg,
      rgba(4, 4, 6, 0.7) 0%,
      rgba(4, 4, 6, 0.3) 32%,
      rgba(4, 4, 6, 0.92) 76%,
      rgba(4, 4, 6, 0.97) 100%
    );
  }

  .hero-inner .hero-rail {
    display: none;
  }
  .hero-inner .hero-grid-lines {
    background-size: 25% 100%;
  }
  .hero-inner .hero-bg-veil {
    background: linear-gradient(
      180deg,
      rgba(4, 4, 6, 0.74) 0%,
      rgba(4, 4, 6, 0.36) 34%,
      rgba(4, 4, 6, 0.93) 78%,
      rgba(4, 4, 6, 0.97) 100%
    );
  }

  .hs-slides {
    min-height: clamp(272px, 36vh, 368px);
  }
  .hs-copytext {
    font-size: 16.8px;
  }
  /* Labels would crowd a phone frame â€” the lit dots carry the state alone. */
  .hs-rail {
    right: 16px;
    height: 24vh;
  }
  .hs-rail-ticks span {
    display: none;
  }
  .hs-ring {
    width: min(94vmin, 416px);
  }
  .hs-grid {
    background-size: 54.4px 54.4px;
    opacity: 0.1;
  }
  .hs-figure {
    height: min(42svh, 340px);
    max-width: 86vw;
    margin-right: -43vw;
  }

  .ms-title {
    font-size: clamp(24.8px, 6.4vw, 33.6px);
  }
  .ms-text {
    font-size: 13.28px;
    margin-top: 13.6px;
    line-height: 1.65;
  }
  .ms-sub {
    margin-top: 9.6px;
  }
  .ms-features {
    margin-top: 16px;
    gap: 7.2px;
  }
  .ms-features li {
    font-size: 12.32px;
    padding-bottom: 7.2px;
  }
  .ms-actions {
    margin-top: 18.4px;
  }
  .ms-ticks {
    inset: -11.2px;
  }
  /* Type steps down here, so the copy is shorter than at tablet widths. The
     reservation only applies once the columns actually stack (<=640px); in
     the two-column range above that, the block near "VISUAL VISIBILITY" owns
     it, because a floor this tall there would clip the visual. */
  @media (max-width: 640px) {
    .ms-panels {
      min-height: clamp(400px, 50svh, 448px);
    }
  }

  .section-title {
    font-size: clamp(29.6px, 7.4vw, 46.4px);
    line-height: 1.1;
  }
  .eyebrow {
    font-size: 9.28px;
    letter-spacing: 0.26em;
  }
  .eyebrow::before {
    width: 25.6px;
  }

  .float-piece {
    display: none !important;
  }

  /* Buttons go full-width so thumbs can reach them */
  .btn-primary,
  .btn-ghost {
    width: 100%;
    padding: 16px 25.6px;
    font-size: 11.2px;
  }
  .hero-cta .btn-primary,
  .hero-cta .btn-ghost {
    width: 100%;
  }
  #cta .btn-primary,
  #cta .btn-ghost {
    width: 100%;
    max-width: 352px;
  }

  /* Rails / cards */
  .rail-card {
    flex-basis: clamp(224px, 78vw, 288px);
  }
  .rail {
    scroll-padding-inline: var(--pad-x);
  }

  .promo-banner {
    border-radius: 22.4px;
  }
  .glass-card {
    border-radius: 21.6px;
  }
  .collection-card,
  .product-card,
  .tile,
  .rail-card {
    border-radius: 18.4px;
  }
  .rail-media {
    border-radius: 17.4px 17.4px 0 0;
  }

  /* Timeline */
  .tl-item {
    padding-bottom: 44px;
  }
  .tl-title {
    font-size: clamp(18.4px, 5.4vw, 24.8px);
  }
  .tl-copy {
    font-size: 14.08px;
  }
  /* Too narrow to wrap text around â€” the figure leads the chapter instead. */
  .tl-figure {
    float: none;
    display: block;
    width: 132px;
    margin: 0 0 16px;
  }

  /* Newsletter stacks */
  #newsletterForm .luxe-input {
    text-align: center;
  }

  #toTop {
    bottom: 17.6px;
    right: 17.6px;
    width: 44.8px;
    height: 44.8px;
  }
}

@media (max-width: 767px) {
  .pillar {
    padding: 2.5rem 1.75rem 2rem;
  }
  .pillar-index {
    font-size: 3rem;
    top: 1.25rem;
    right: 1.5rem;
  }
  .hero-cinema .hero-content .hero-sub {
    max-width: 100%;
    width: 100%;
  }
  .hero-cinema .hero-content .hero-eyebrow {
    justify-content: center;
    margin: 0 0 clamp(18px, 2.4vh, 30px);
    letter-spacing: 0.36em;
  }

  /* ------------------------------------------------------------------
     HERO — CENTRED ON PHONES

     The desktop hero is an editorial split: a left-weighted copy column
     balanced by the vertical caption rail down the right edge. That rail
     is already hidden below 768px, which leaves the copy hugging the left
     of an otherwise empty frame with nothing to counterweight it. Centring
     the column restores the balance on a single-column layout.

     The eyebrow and CTA are centred at every width already; what needs
     overriding here is `.hero-content`'s `text-align:left`, the headline's
     own left alignment, the sub's asymmetric margin, and the column's
     `15.5em` cap (which would otherwise sit the centred block off-centre).
     ------------------------------------------------------------------ */
  .hero-cinema .hero-content {
    text-align: center;
  }

  .hero-cinema .hero-stage {
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  /* The cap exists to hold a tight measure beside the rail. With the rail
     gone the column should take the full frame so the centred text is
     centred on the viewport, not within a narrow left-anchored box. */
  .hero-cinema .hero-col {
    max-width: none;
    width: 100%;
    margin-inline: auto;
  }

  .hero-cinema .hero-title {
    text-align: center;
  }

  /* `margin:41.6px 16px 0` is a left/right pair, not a centring one — it
     holds the measure off the frame edge. `auto` centres the block while
     the inline padding keeps it clear of the projection gate. */
  .hero-content .hero-sub {
    margin-inline: auto;
    padding-inline: 16px;
  }

  /* Both are flex rows that already centre their own children; this centres
     the boxes themselves now that the column is full-width. */
  .hero-content .hero-eyebrow,
  .hero-content .hero-cta {
    justify-content: center;
  }

  /* ------------------------------------------------------------------
     ABOUT + "FIND YOUR MATERIAL" — NO SCROLL SEQUENCE BELOW 768px

     js/heritage-scene.js and js/materials-scene.js both bail out at this
     same breakpoint, so on a phone neither stage is ever promoted and the
     static fallbacks below them are the sections. These rules are the
     backstop for the one case JS cannot cover: a viewport resized across
     768px after load, where the stage is already live. Hiding the stage
     and forcing its fallback back on mirrors what the reduced-motion
     block does, and unpins the scrubbed viewports at the same time.
     ------------------------------------------------------------------ */
  #heritageStage {
    display: none !important;
  }
  body.hs-live #heritageFallback {
    display: block !important;
  }

  #materialStage {
    display: none !important;
  }
  body.ms-live #materialFallback {
    display: block !important;
  }

  /* ------------------------------------------------------------------
     ABOUT — CHAPTER CARDS

     The desktop treatment is a ruled timeline: a vertical hairline with a
     dot per chapter. That reads as one continuous ribbon, which needs a
     left gutter to work — and a gutter is expensive on a ~360px screen
     while carrying no meaning here (the chapters are themes, not dates).

     On mobile each chapter becomes a self-contained card instead: figure
     banded across the top, numeral in the corner, copy beneath. The stack
     reads as five discrete chapters, the figures get real presence rather
     than being shrunk to a 132px thumbnail, and the full column width goes
     to the text. Counter-based numerals replace the dots as the throughline.
     ------------------------------------------------------------------ */
  #heritageFallback .timeline {
    padding-left: 0;
    border-left: 0;
    counter-reset: tl-chapter;
    display: grid;
    gap: 16px;
    grid-template-columns: 48% 48%;
  }
  .mb-14 {
    margin-bottom: 1rem !important;
  }
  #heritageFallback .tl-item {
    counter-increment: tl-chapter;
    position: relative;
    padding-bottom: 0;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 18px;
    background: var(--slate2, #101014);
  }
  /* The dot belongs to the rule that no longer exists. */
  #heritageFallback .tl-dot {
    display: none;
  }
  /* Desktop clears the figure's float; there is no float left to clear, and
     the leftover block adds a stray row to the card. */
  #heritageFallback .tl-item::after {
    display: none;
  }

  /* Figure as a banded header. `cover` at a wide ratio crops to the piece
     rather than letterboxing a tall cut-out into a short box, and the mask
     feathers it into the card body so the seam never reads as a hard edge. */
  #heritageFallback .tl-figure {
    float: none;
    display: block;
    width: 100%;
    height: clamp(132px, 34vw, 176px);
    margin: 0;
    object-fit: contain;
    object-position: center 38%;
    filter: brightness(0.82) contrast(1.06) saturate(0.9);
    mask-image: linear-gradient(180deg, #000 62%, transparent 100%);
    -webkit-mask-image: linear-gradient(180deg, #000 62%, transparent 100%);
  }

  /* Chapter numeral, sat over the figure's top corner. Decorative — the
     eyebrow beneath still names the chapter for a screen reader. */
  #heritageFallback .tl-item::before {
    content: counter(tl-chapter, decimal-leading-zero);
    position: absolute;
    top: 12px;
    right: 16px;
    z-index: 2;
    font-family:
      "Inter",
      -apple-system,
      BlinkMacSystemFont,
      sans-serif;
    font-size: 11px;
    letter-spacing: 0.22em;
    color: var(--gold, #c9a227);
    opacity: 0.75;
  }

  /* Copy block. Sits in normal flow directly beneath the figure — no
     negative margin. An earlier revision pulled the text up into the
     figure's feathered tail, which put the copy underneath a
     later-painting image and clipped it inside the card's
     `overflow:hidden`. The mask already blends the seam on its own. */
  #heritageFallback .tl-year {
    margin-top: 14px;
    padding: 0 18px;
    font-size: 9.28px;
    letter-spacing: 0.24em;
  }
  #heritageFallback .tl-title {
    margin-top: 9px;
    padding: 0 18px;
    font-size: clamp(20px, 5.6vw, 25px);
    line-height: 1.22;
  }
  #heritageFallback .tl-copy {
    margin-top: 10px;
    padding: 0 18px 20px;
    font-size: 14.4px;
    line-height: 1.7;
  }

  /* The heading band's desktop spacing (mb-20 / 5rem) is dead space here.
     `.mb-20` / `.mb-7` are Tailwind utilities from the CDN sheet, so these
     carry `!important` for the same reason as the grid override below. */
  #heritageFallback .wrap > .mb-20 {
    margin-bottom: clamp(28px, 7vw, 40px) !important;
  }

  /* ------------------------------------------------------------------
     FIND YOUR MATERIAL — TWO-UP CATEGORY GRID

     This is a six-item category menu, not a gallery. Full-width tiles turn
     it into six screens of scrolling to read six words. A two-up grid of
     portrait crops shows the whole set at once, which is what a menu is
     for, and portrait suits the standing-piece photography better than the
     desktop landscape ratio.
     ------------------------------------------------------------------ */
  /* `!important` is deliberate: Tailwind is loaded from a CDN and injects its
     own sheet, so `sm:grid-cols-2` (min-width:640px) is live across 640-767px
     at equal specificity and would otherwise win on source order. */
  #materialFallback .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: 10px !important;
  }
  #categories .tile {
    aspect-ratio: 3/4;
    min-height: 0;
    border-radius: 14px;
    /* The borderless desktop presentation reads as floating plates at size;
       at thumbnail scale the tiles need an edge to separate from the bed. */
    border: 1px solid var(--line);
    overflow: hidden;
  }
  /* `contain` letterboxes badly once a tile is this small — `cover` fills the
     crop. Less grayscale too: at thumbnail size the material is the only
     thing distinguishing one tile from the next, so the colour has to read. */
  /* `!important` on the filter: the later `@media (hover:none)` block lifts
     every `.tile-img` to `grayscale(0) brightness(.86)` for touch, which
     matches every phone and would wash out the label against the veil. The
     un-greyed part of that intent is kept here, just darker. */
  #categories .tile-img {
    object-fit: cover;
    filter: grayscale(0.2) brightness(0.7) !important;
  }
  /* A stronger veil: the label sits over a much smaller image here, so it
     needs its own ground to stay legible against a busy crop. */
  #categories .tile-veil {
    background: linear-gradient(180deg, transparent 42%, rgba(5, 5, 6, 0.94));
  }
  /* The label sits over the veil at the tile foot. `flex-wrap:wrap` lets the
     longest category ("Tournament") break rather than overflow a half-width
     tile, and the arrow is kept from shrinking so it never lands alone. */
  #categories .tile-label {
    right: 0;
    flex-wrap: wrap;
    padding: 12px 12px 13px;
    font-size: clamp(14px, 3.9vw, 16.4px);
    line-height: 1.15;
    gap: 4px 6px;
  }
  #categories .tile-label i {
    font-size: 0.75em;
    flex: none;
  }

  #materialFallback .mb-7 {
    margin-bottom: clamp(24px, 6vw, 32px) !important;
  }
}

@media (max-width: 640px) {
  /* Tile sizing for this range now lives in the `max-width:767px` block with
     the rest of the one-per-row mobile grid — a `min-height` here would
     cascade over it and reintroduce the letterboxed short tile. */

  .rail-btn {
    width: 34px;
    height: 34px;
    font-size: 11px;
  }
  :is(div, header):has(> .slider-nav) {
    gap: 12px;
  }
  .slider-nav {
    gap: 8px;
  }

  /* Menu type steps down with the viewport so six links plus the header
     still fit one screen without scrolling. */
  .mobile-link {
    font-size: 10.4px;
    letter-spacing: 0.2em;
    padding-block: 12.8px;
  }
  .mobile-link span {
    font-size: clamp(22.4px, 6.2vw, 30.4px);
  }

  .uc-slider:not(.slick-initialized) > * {
    flex: 0 0 100%;
  }
}

@media (max-width: 600px) {
  .wrap {
    padding-inline: 20px;
  }
  .brand-ledger {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border-top: 1px solid rgba(255, 255, 255, 0.1);
  }
  .section-pad {
    padding-block: clamp(11.2px, 2.6vw, 16px);
  }
  .section-title {
    font-size: clamp(23.6px, 4.4vw, 36.4px);
    line-height: 1.1;
  }
  .card-body {
    padding: 20px;
  }
  .card-copy {
    font-size: 12.8px;
  }
  .card-title {
    font-size: 21.6px;
  }

  .product-body {
    padding: 18.4px 17.6px 22.4px;
  }
  .product-name {
    font-size: 16px;
  }
  .product-price {
    font-size: 15.2px;
  }

  .rail-body {
    padding: 20px 20px 22.4px;
    gap: 8px;
  }
  .rail-body .product-name {
    font-size: 19.2px;
  }
  .rail-body .product-price {
    padding-top: 13px;
    font-size: 16px;
  }

  .arrival-card {
    border-radius: 20px;
  }
  .arrival-body {
    padding: 20px 20px 22px;
    gap: 11px;
  }
  .arrival-head {
    gap: 12px;
  }
  .arrival-head .product-name {
    font-size: 19.2px;
  }
  .arrival-head .product-price {
    font-size: 16px;
  }
  .arrival-body .product-cat {
    margin: 0;
  }

  .testi-card {
    padding: 22.4px;
  }
  /* Tighten the quote-to-footer gap, not .testi-foot's margin-top: that stays
     `auto` so the footer keeps pinning to the card foot at every width. */
  .testi-quote {
    margin-bottom: 24px;
  }
  .testi-foot {
    padding-top: 19.2px;
  }
  .testi-avatar {
    width: 40px;
    height: 40px;
  }

  .promo-banner .btn-primary {
    width: 100%;
  }

  .counter-num {
    font-size: clamp(30.4px, 9vw, 41.6px);
  }
  .counter-cap {
    font-size: 8.96px;
    letter-spacing: 0.16em;
  }

  .social-dot {
    width: 36.8px;
    height: 36.8px;
    font-size: 8.96px;
  }
  .icon-btn {
    width: 38.4px;
    height: 38.4px;
  }

  /* Quick view is always visible on touch â€” hover never fires */
  .quick-view {
    transform: translate(-50%, 0);
    opacity: 1;
    bottom: 14.4px;
    padding: 10.4px 19.2px;
    font-size: 9.28px;
  }
}

@media (max-width: 480px) {
  .hero-chess-wrapper {
    width: 75%;
  }
  .foot-social,
  .hero-inner .hero-content .hero-eyebrow {
    justify-content: center;
  }
  .hero-inner .hero-col,
  .hero-inner .hero-content .hero-sub {
    max-width: 100%;
    width: 100%;
  }
  .card-cta,
  .testi-foot {
    justify-content: center;
  }

  /* ---- Uniform control height ----
     Buttons, inputs and selects each derive their height from their own
     padding (17.6px on .btn-primary/.btn-ghost, 14.4px on .btn-line, 16.8px on
     .luxe-input) and several are overridden per-page with Tailwind `!py-*`
     utilities. The result on a phone is a column of controls that all differ
     by a few pixels. Here every control is pinned to one height token and the
     vertical padding is dropped, so the height comes from the box rather than
     from whatever padding each control happened to carry.

     `!important` is unavoidable: the per-page overrides are Tailwind `!py-*`
     utilities, which are themselves `!important` and cannot be outranked by
     specificity alone. */
  :root {
    --control-h: 46px;
  }

  .btn-primary,
  .btn-ghost,
  .btn-line,
  .btn-magnetic,
  .luxe-input,
  .ui-select,
  select.luxe-input,
  input.luxe-input {
    height: var(--control-h) !important;
    min-height: var(--control-h);
    padding-block: 0 !important;
    line-height: 1.1;
  }

  /* Inputs and selects need their text vertically centred once the padding
     that used to do it is gone. Buttons already centre via inline-flex. */
  .luxe-input,
  .ui-select {
    display: flex;
    align-items: center;
  }
  /* A flex display on a text input is inert in most engines, so the centring
     above is belt-and-braces; this keeps the caret and value centred where it
     is ignored. */
  input.luxe-input {
    display: block;
    line-height: var(--control-h);
  }

  /* The textarea is exempt — it is multi-line by definition and a fixed height
     would defeat it. `.luxe-input--area` is matched too: contact.html defines
     that modifier in a page-scoped <style> that loads after this file, and its
     own `min-height` would otherwise fight a bare `textarea` selector. */
  textarea.luxe-input,
  .luxe-input--area {
    height: auto !important;
    min-height: 176px;
    padding-block: 14px !important;
    line-height: 1.55;
    display: block;
  }

  /* Icon buttons are square, so they follow the same token to stay in line
     with the controls they sit beside. */
  .icon-btn {
    width: var(--control-h);
    height: var(--control-h);
  }

  /* The cart stepper is a compound control with its own internal buttons and
     is sized deliberately further down. It is simply not part of the selector
     list above — no opt-out is needed, and an `!important` reset here would
     outrank the explicit sizes set for it later in this same block. */

  /* ---- Cart page cards ----
     The line-item action row is `flex-wrap justify-between` until `lg`. Below
     480px the stepper, subtotal and Remove button no longer fit on one line,
     so they wrap to ragged rows — `justify-between` then pushes the lone
     wrapped item hard to one edge, and the subtotal block's own `text-right`
     leaves its label and figure aligned against the item title above, which is
     left-aligned. The row is laid out as a column here so every element shares
     one left edge with the product copy. */
  [data-cart-item] .cart-line-actions {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 18px;
  }
  [data-cart-item] .cart-line-actions > * {
    text-align: left;
  }
  /* The stepper and Remove control sit on one line together — they are compact
     enough to share a row, and splitting them would stretch the card. */
  [data-cart-item] .cart-line-actions .cart-line-price {
    display: flex;
    width: 100%;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
  }
  [data-cart-item] .cart-line-actions .cart-line-price > span:last-child {
    margin-top: 0;
  }

  /* ---- Mobile card optimisation ----
     The card is padded for desktop; below 480px that padding plus a 5.5rem
     thumbnail column leaves the title wrapping after two or three words. Trim
     the gutters and the thumbnail so the copy column gets the width back. */
  [data-cart-item] {
    padding-inline: 16px;
    padding-block: 22px;
  }
  [data-cart-item] > .grid {
    grid-template-columns: 4.5rem minmax(0, 1fr);
    column-gap: 14px;
    row-gap: 18px;
  }

  /* The subtotal is the figure that matters on a small screen, so it keeps its
     weight while the per-unit line and spec list step back. */
  [data-cart-item] .cart-line-price > span:last-child {
    font-size: 19px;
  }

  /* The action row reads as a bar under the product copy rather than three
     loose stacked controls. The subtotal takes the first row on its own; the
     stepper and Remove control share the second, pushed to opposite ends.
     Ordering does this with flex rather than negative margins, so it does not
     depend on either control's rendered height. */
  [data-cart-item] .cart-line-actions {
    flex-flow: row wrap;
    align-items: center;
    gap: 14px;
  }
  [data-cart-item] .cart-line-actions .cart-line-price {
    order: 1;
  }
  [data-cart-item] .cart-line-actions > .inline-flex:not([data-cart-remove]) {
    order: 2;
  }
  [data-cart-item] .cart-line-actions [data-cart-remove] {
    order: 3;
    margin-left: auto;
    padding-block: 8px;
  }
  /* The stepper is trimmed to a compact 30px control so it sits lightly beside
     the Remove button instead of dominating the action row. Shrinking the
     visible circle would normally cost touch accuracy, so the tap area is put
     back with a transparent ::before that extends each button to ~44px — the
     target stays thumb-sized while the chrome reads small. */
  [data-cart-item] [data-qty] {
    position: relative;
    height: 30px;
    width: 30px;
    font-size: 10px;
  }
  /* The overlay is extended vertically and outward only. Growing it inward too
     would overlap the number input sitting between the two buttons and swallow
     taps meant for it, so each button reaches only away from the centre. */
  [data-cart-item] [data-qty]::before {
    content: "";
    position: absolute;
    top: 50%;
    height: 44px;
    width: 38px;
    transform: translateY(-50%);
  }
  [data-cart-item] [data-qty="decrease"]::before {
    left: -8px;
  }
  [data-cart-item] [data-qty="increase"]::before {
    right: -8px;
  }
  /* The wrapper's padding is dropped to 2px so the ring hugs the smaller
     buttons rather than leaving a slack border around them. */
  [data-cart-item] .cart-line-actions > .inline-flex:not([data-cart-remove]) {
    padding: 2px;
  }
  [data-cart-item] [data-qty-input] {
    width: 32px;
    font-size: 12.8px;
  }

  /* Totals rows: label left, figure right, with the figure allowed to sit on
     its own line rather than being crushed by a long label. */
  .cart-total-row {
    gap: 10px;
  }
  .cart-total-row > :last-child {
    text-align: right;
    white-space: nowrap;
  }

  /* The coupon row's chip is centred when it wraps below the form. */
  .cart-coupon-row {
    justify-content: flex-start;
  }

  .foot-grid {
    display: grid;
    grid-template-columns: 100%;
    gap: 8px;
    padding-bottom: 20px;
    align-items: start;
  }
  .foot-brand__text {
    max-width: 100%;
  }
  .menu-close {
    top: 18px;
    right: 16px;
    font-size: 15px;
  }

  .mobile-link {
    font-size: 9.6px;
    letter-spacing: 0.18em;
    padding-block: 11.2px;
    gap: 12px;
  }
  .mobile-link span {
    font-size: clamp(20.8px, 5.8vw, 26.4px);
  }

  .hero-container {
    padding: 12px;
    margin-top: 60px;
    min-height: calc(100dvh - 60px);
  }
  .hero-content {
    font-size: clamp(30.4px, 10.5vw, 48px);
    letter-spacing: -0.03em;
    border-radius: 20px;
  }
  .hero-text-back {
    z-index: 10;
  }
  .hero-content .hero-eyebrow {
    font-size: 8px;
    letter-spacing: 0.2em;
    gap: 9.6px;
  }
  .hero-eyebrow-rule {
    width: 22.4px;
  }

  .hero-container.hero-photo {
    --header-h: 60px;
    padding: 0;
    margin-top: 0;
    min-height: 100dvh;
  }
  .hero-photo .hero-content {
    padding: calc(var(--header-h) + 32px) 20px 96px;
    font-size: clamp(34px, 11.5vw, 54px);
    letter-spacing: -0.035em;
    border-radius: 0;
  }
  .hero-photo .hero-content::after {
    inset: 10px;
  }
  /* At mobile headline sizes .36em leaves the closing line too slight to hold
     its own against the two display lines above it. */
  .hero-photo .hero-text-paris {
    font-size: 0.46em;
  }
  .hero-photo .hero-content .hero-eyebrow {
    letter-spacing: 0.24em;
  }
  .hero-photo .hero-eyebrow-rule {
    width: 28px;
  }
  /* Centred with the rest of the sub-480 content rather than pinned to the
     hero's left inset. */
  .hero-photo .hero-content .scroll-indicator {
    left: 50%;
    transform: translateX(-50%);
  }

  .hero-container.hero-cinema {
    --header-h: 60px;
    --hero-inset: 20px;
    padding: 0;
    margin-top: 0;
    min-height: 100dvh;
  }
  .hero-cinema .hero-content {
    padding: calc(var(--header-h) + 24px) var(--hero-inset)
      clamp(84px, 10vh, 104px);
    font-size: clamp(36px, 12vw, 58px);
    border-radius: 0;
  }
  .hero-cinema .hero-content::after {
    inset: 10px;
  }
  .hero-cinema .hero-text-back {
    font-size: 0.26em;
    letter-spacing: 0.18em;
  }
  .hero-cinema .hero-text-paris {
    font-size: 0.36em;
  }
  .hero-cinema .hero-content .hero-eyebrow {
    letter-spacing: 0.24em;
    font-size: 8.5px;
  }
  .hero-cinema .hero-eyebrow-rule {
    width: 30px;
  }

  .hero-container.hero-inner--slim {
    min-height: clamp(170px, 24vh, 220px);
  }

  .hero-container.hero-inner {
    --header-h: 60px;
    --hero-inset: 20px;
    min-height: clamp(360px, 56vh, 480px);
  }
  .hero-inner .hero-content {
    padding: calc(var(--header-h) + 22px) var(--hero-inset)
      clamp(38px, 5vh, 52px);
    font-size: clamp(32px, 10vw, 50px);
    border-radius: 0;
  }
  .hero-inner .hero-content::after {
    inset: 10px;
  }
  .hero-inner .hero-text-back {
    font-size: 0.26em;
    letter-spacing: 0.18em;
  }
  .hero-inner .hero-text-paris {
    font-size: 0.38em;
  }
  .hero-inner .hero-content .hero-eyebrow {
    letter-spacing: 0.24em;
    font-size: 8.5px;
  }
  .hero-inner .hero-eyebrow-rule {
    width: 30px;
  }
  .hero-inner .hero-crumbs {
    font-size: 9.5px;
    letter-spacing: 0.12em;
  }
  #heritageFallback .timeline {
    padding-left: 0;
    border-left: 0;
    counter-reset: tl-chapter;
    display: grid;
    gap: 16px;
    grid-template-columns: 100%;
  }

  /* ---- Sub-480 centring --------------------------------------------------
     Below 480px every layout has already collapsed to a single column, so
     the left-aligned rhythm the wider breakpoints rely on just reads as
     ragged. Layout here is Tailwind utilities in the markup rather than
     component classes, so centre structurally: text-align on the page
     containers cascades into the utility-styled children, and the flex/grid
     rules re-point the utility rows (`flex items-start`, `flex-col`, `grid`)
     at the centre. Anything that must stay left is handed back at the
     bottom of this block. */
  main,
  main section,
  main header,
  main article,
  main aside,
  .wrap,
  .site-footer,
  .glass-card {
    text-align: center;
  }

  /* The hero headlines set `text-align:left` from a two-class selector, so
     the container rule above can't outrank them — restate at their weight. */
  .hero-photo .hero-title,
  .hero-cinema .hero-title,
  .hero-inner .hero-title,
  .hero-container .hero-content {
    text-align: center;
  }
  .hero-content .hero-eyebrow,
  .hero-inner .hero-crumbs {
    justify-content: center;
  }

  /* Utility flex/grid rows: centre the boxes, not only their text. The
     `flex items-start` icon+label lists and the `flex-col` stacks are the
     two shapes that recur across every page. */
  main .flex:not(.justify-between),
  .site-footer .flex:not(.justify-between) {
    justify-content: center;
  }
  main .flex-col,
  main .items-start,
  .site-footer .flex-col,
  .site-footer .items-start {
    align-items: center;
  }
  main .grid,
  .site-footer .grid {
    justify-items: center;
  }

  /* Width-constrained flow content still sits in a left-hugging box unless
     its own margins are released. */
  main p,
  main [class*="max-w-"] {
    margin-inline: auto;
  }

  /* Rules drawn as pseudo-elements were anchored to the left edge. */
  .section-title::after,
  .foot-head::after {
    margin-inline: auto;
  }

  /* Outside-the-box bullets throw off the optical centre. */
  main ul,
  main ol,
  .site-footer ul {
    list-style-position: inside;
    padding-left: 0;
  }

  /* --- Handed back: centring breaks or hurts readability here ----------- */

  /* Form fields — a centred caret and centred typing is disorienting. */
  .luxe-input,
  main input,
  main textarea,
  main select {
    text-align: left;
  }

  /* Split label/value rows (cart lines, order summary, totals) depend on
     their two ends staying pinned apart. */
  main .justify-between {
    justify-content: space-between;
    text-align: left;
  }

  /* The mobile nav overlay keeps its own deliberate alignment. */
  #mobileMenu,
  .mobile-link {
    text-align: left;
  }
  #mobileMenu .flex {
    justify-content: flex-start;
  }
  .glass-card label {
    text-align: left !important;
    width: 100%;
  }
  [type="text"],
  input:where(:not([type])),
  [type="email"],
  [type="url"],
  [type="password"],
  [type="number"],
  [type="date"],
  [type="datetime-local"],
  [type="month"],
  [type="search"],
  [type="tel"],
  [type="time"],
  [type="week"],
  [multiple],
  textarea,
  select {
    font-size: 0.8rem !important;
  }
  select {
    padding-top: 0.5rem !important;
    padding-bottom: 0.5rem !important;
    width: 100;
  }
.glass-card header {text-align: left !important;}

}

@media (max-width: 400px) {
  .wrap {
    padding-inline: 16px;
  }
  .mt-2 {
    margin-top: 0.15rem !important;
  }
  .section-title {
    font-size: clamp(26.4px, 8.4vw, 35.2px);
  }

  .mobile-link {
    font-size: 9px;
    letter-spacing: 0.16em;
    padding-block: 9.6px;
    gap: 10px;
  }
  .mobile-link span {
    font-size: 21.6px;
  }

  .btn-primary,
  .btn-ghost,
  .btn-line {
    font-size: 10.24px;
    letter-spacing: 0.14em;
  }

  .rail-card {
    flex-basis: 84vw;
  }

  .foot-link {
    font-size: 13.12px;
  }
}

@media (max-width: 375px) {
  .hero-chess-wrapper {
    width: 82%;
  }
  .-top-1 {
	top: 0.4rem !important;
}
  .shop-toolbar-controls {flex-direction: column !important;}

  .hero-content {
    font-size: clamp(28px, 9.8vw, 41.6px);
    letter-spacing: -0.03em;
  }
  .hero-photo .hero-content {
    font-size: clamp(30px, 10.6vw, 46px);
  }
  .hero-cinema .hero-content {
    font-size: clamp(32px, 11vw, 48px);
  }
  .hero-inner .hero-content {
    font-size: clamp(29px, 9.4vw, 42px);
  }
}

@media (max-width: 360px) {
  /* At the narrowest widths the subtotal label and figure keep sharing a line
     but tighten up: a smaller gap and top alignment so the tall figure does
     not drag the small-caps label off its baseline. */
  [data-cart-item] .cart-line-actions .cart-line-price {
    flex-direction: row;
    align-items: flex-start;
    gap: 4px;
  }

  /* The stepper tightens once more at this width. The 44px tap overlays are
     left untouched — the visible control shrinks, the target does not. */
  [data-cart-item] [data-qty] {
    height: 28px;
    width: 28px;
  }
  [data-cart-item] [data-qty-input] {
    width: 28px;
  }

  .mobile-link {
    font-size: 8.6px;
    letter-spacing: 0.14em;
    padding-block: 8.8px;
    gap: 9px;
  }
  .mobile-link span {
    font-size: 19.2px;
  }
}

@media (max-height: 520px) and (orientation: landscape) {
  .hero-container {
    height: auto;
    max-height: none;
    min-height: auto;
  }
  .hero-content {
    padding-block: 80px 48px;
  }
  .scroll-indicator {
    display: none;
  }
  #brand,
  #cta {
    min-height: auto;
  }

  /* Height, not width, is the constraint in landscape â€” shrink the links so
     the full list still clears the fold. */
  .mobile-link {
    font-size: 9px;
    padding-block: 7.2px;
  }
  .mobile-link span {
    font-size: 18.4px;
  }
}

@media (hover: none) {
  .quick-view {
    opacity: 1;
    transform: translate(-50%, 0);
  }
  .card-img,
  .product-img,
  .tile-img,
  .rail-img,
  .arrival-img {
    filter: grayscale(0) brightness(0.86);
  }
}

@media (hover: hover) and (pointer: fine) {
  .product-card:hover {
    transform: translateY(-8px);
  }
  .tile:hover {
    transform: translateY(-6px);
  }
}

@media (prefers-reduced-motion: reduce) {
  #siteHeader,
  #siteHeader > div,
  #siteHeader .logo-mark,
  #siteHeader .logo-mark img,
  #siteHeader .logo-mark + span > span {
    transition: none;
  }

  .is-removing,
  .ui-toggle::after {
    transition-duration: 0.01ms !important;
  }

  .ui-range::-webkit-slider-thumb,
  .ui-range::-moz-range-thumb {
    transition-duration: 0.01ms !important;
  }

  .preloader-logo {
    animation: none;
    opacity: 1;
  }

  .hero-chess-wrapper {
    opacity: 1 !important;
    transform: none !important;
  }

  .hero-cinema .hero-video {
    display: none;
  }
  .hero-cinema .hero-bg {
    background: url("../assets/images/hero.jpg") center 45% / cover no-repeat;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  .hero-line {
    transform: none !important;
  }
  .hero-eyebrow,
  .hero-sub,
  .hero-cta,
  .hero-stats,
  .scroll-indicator {
    opacity: 1 !important;
  }
  .hero-text-back,
  .hero-text-front,
  .hero-text-paris {
    opacity: 1 !important;
    transform: none !important;
  }
  .hero-content::before,
  .hero-content::after,
  .hero-gradient-layer {
    animation: none !important;
  }
  .split-word > span {
    transform: none !important;
  }
  .particle,
  .float-piece {
    animation: none !important;
  }
  /* app.js already skips the board lift under reduced motion; belt-and-braces
     in case the grid was built before the preference changed. */
  .board-sq {
    transform: none !important;
    transition: none !important;
  }

  #heritageStage {
    display: none !important;
  }
  body.hs-live #heritageFallback {
    display: block !important;
  }

  #materialStage {
    display: none !important;
  }
  body.ms-live #materialFallback {
    display: block !important;
  }

  .uc-slider .slick-track {
    transition: none !important;
  }
}

@media (prefers-reduced-transparency: reduce) {
  body::before {
    background-image: none;
  }
  .board-3d {
    display: none;
  }

  .site-footer::after {
    display: none;
  }
  .foot-bottom::before {
    display: none;
  }

  #categories .tile {
    background-color: transparent;
  }

  main > section.bg-charcoal,
  main > section.bg-ink,
  footer.bg-charcoal {
    background-color: var(--charcoal);
    backdrop-filter: none;
  }
  .product-card,
  .tile,
  .testi-card,
  .arrival-card {
    backdrop-filter: none;
    background-color: var(--slate2);
  }
}

@media print {
  #preloader,
  #siteHeader,
  #mobileMenu,
  #toTop,
  #quickModal,
  #heroCanvas,
  #particles,
  .board-3d,
  .glow-orb {
    display: none !important;
  }
  body {
    background: #fff;
    color: #000;
  }
  body::before,
  body::after {
    display: none !important;
  }
  .section-title,
  .product-name,
  .card-title {
    color: #000;
  }
}
