/* ============================================================
   NEXTFABRI — Red & Black Streetwear Theme
   Global Stylesheet
   ============================================================ */

/* ---------- CSS Variables ---------- */
:root {
  --red: #e01722;
  --red-dark: #8f0d15;
  --red-bright: #ff2a36;
  --black: #0a0a0a;
  --charcoal: #141416;
  --gray-800: #1f1f24;
  --gray-600: #4a4a52;
  --gray-400: #8d8d97;
  --white: #f2efec;
  --font-display: "Neue Montreal", "Helvetica Neue", "Arial Black", Helvetica, sans-serif;
  --font-body: "Neue Montreal", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --max-width: 1200px;
}

/* ---------- Reset ---------- */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* The page base colour lives on <html> (it propagates to the canvas)
     rather than on <body>. An opaque body fill would paint OVER the
     watermark below, hiding it; keeping body transparent lets the
     about-page mark sit between the canvas and the content. Renders
     identically either way — --black is #0a0a0a dark, #fafafa light,
     the same two values the inline anti-flash background already uses. */
  background-color: var(--black);
}

body {
  background-color: transparent;
  color: var(--white);
  font-family: var(--font-body);
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
}

main {
  flex: 1;
}

/* First homepage section sits tighter under the hero band. */
/* body is a flex column, so .section shrink-wraps its content; a
   carousel of absolutely-positioned slides has no content width,
   so carousel sections must take the full row explicitly. */
.carousel-section {
  width: 100%;
}

/* Carousel + categories section heads are CENTERED title images
   (assets/logos "New Drop / Best Seller / Hoodies - theme.png",
   one PNG per theme), wobbling with the same SVG squiggle as the
   hero logo. The wrap reuses the .hero-logo recipe - overflow hidden
   plus tiny negative margins so the displacement filter never clips -
   and symmetric ch padding so the wobble never leaves the box. */
.carousel-section .section-head {
  position: relative;
  justify-content: center;
}

.section-head .title-img-wrap {
  overflow: hidden;
  margin: -0.35% 0;
  padding-inline: 1.5ch;
  white-space: nowrap;
  will-change: filter;
}

.title-img-wrap img {
  width: clamp(190px, 26vw, 300px);
  display: inline-block;
  height: auto;
  user-select: none;
  -webkit-user-drag: none;
}

/* One PNG per theme; the other stays in the DOM (the squiggle targets
   the wrap, not the img) but is never painted. */
.title-img-wrap img.title-img-light {
  display: none;
}

html[data-theme="light"] .title-img-wrap img.title-img-light {
  display: inline-block;
}

html[data-theme="light"] .title-img-wrap img.title-img-dark {
  display: none;
}

.drop-section {
  padding-top: 2rem;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: var(--red-bright);
  text-decoration: none;
}

a:hover {
  color: var(--white);
}

::selection {
  background: var(--red);
  color: var(--black);
}

/* ---------- Header — Aceternity "Resizable Navbar" port ----------
   A floating pill: fixed to the top, centered, dark glass. It
   shrinks + blurs once the page scrolls (see .scrolled in main.js). */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  justify-content: center;
  padding: 0.9rem 1rem 0;
  pointer-events: none; /* only the pill itself catches clicks */
}

.nav-inner {
  pointer-events: auto;
  width: min(var(--max-width), 100%);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: rgba(12, 12, 13, 0.88);
  border: 1px solid rgba(224, 23, 34, 0.3);
  border-radius: 9999px;
  padding: 0.65rem 1.4rem;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1),
    padding 0.5s cubic-bezier(0.4, 0, 0.2, 1),
    background-color 0.5s, box-shadow 0.5s, border-color 0.5s;
}

.site-header.scrolled .nav-inner {
  width: min(680px, 100%);
  padding: 0.4rem 1.2rem;
  background: rgba(12, 12, 13, 0.62);
  border-color: rgba(224, 23, 34, 0.45);
  box-shadow:
    0 10px 32px rgba(0, 0, 0, 0.55),
    0 0 24px rgba(224, 23, 34, 0.08);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

/* Desktop: the gooey nav block floats on the pill's true midline
   (absolute, out of the flex flow) so Home/Shop/About/Contact stay
   genuinely centered between the logo and the action cluster. No
   max-width cap here — a cap computed from the pill width shrinks
   with the .scrolled state and pushes the links off-center. Space
   is managed by tightening link padding on narrow viewports. */
@media (min-width: 769px) {
  .nav-inner .main-nav {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
  }

  .gooey-nav-container nav ul {
    flex-wrap: nowrap;
    justify-content: center;
  }

  .gooey-nav-container nav ul li a {
    padding: 0.6em 0.85em;
    letter-spacing: 0.15em;
  }
}

/* Narrow desktop band: tighter links so the centered block keeps
   clear of the logo and the icon cluster (no collision, no cap). */
@media (min-width: 769px) and (max-width: 950px) {
  .gooey-nav-container nav ul li a {
    padding: 0.6em 0.65em;
    letter-spacing: 0.1em;
  }
}

.logo {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

/* Navbar logo = the angular N mark (square-ish, so a touch smaller
   than the wordmark it replaced); shrinks with the pill on scroll. */
.logo-img {
  height: 32px;
  width: auto;
  transition: height 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.site-header.scrolled .logo-img {
  height: 24px;
}

/* ============================================================
   NAV — ReactBits "Gooey Nav" descendant (js/gooey-nav.js),
   stripped to the active-state pill: clicking an item fades a
   pill in behind it, then navigation follows. Particles and the
   SVG goo filter were removed by design.
   ============================================================ */
.gooey-nav-container {
  --color-1: #ff2a36;
  --color-2: #e01722;
  --color-3: #ff8a7a;
  --color-4: #8f0d15;
  --linear-ease: linear(
    0,
    0.068,
    0.19 2.7%,
    0.804 8.1%,
    1.037,
    1.199 13.2%,
    1.245,
    1.27 15.8%,
    1.274,
    1.272 17.4%,
    1.249 19.1%,
    0.996 28%,
    0.949,
    0.928 33.3%,
    0.926,
    0.933 36.8%,
    1.001 45.6%,
    1.013,
    1.019 50.8%,
    1.018 54.4%,
    1 63.1%,
    0.995 68%,
    1.001 85%,
    1
  );
  position: relative;
}

.gooey-nav-container nav {
  display: flex;
  position: relative;
  transform: translate3d(0, 0, 0.01px);
}

.gooey-nav-container nav ul {
  display: flex;
  gap: 0.4em;
  list-style: none;
  padding: 0 0.4em;
  margin: 0;
  position: relative;
  z-index: 3;
}

.gooey-nav-container nav ul li {
  border-radius: 100vw;
  position: relative;
  cursor: pointer;
  transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
  box-shadow: 0 0 0.5px 1.5px transparent;
}

.gooey-nav-container nav ul li a {
  display: inline-block;
  padding: 0.6em 1em;
  color: var(--white);
  text-transform: uppercase;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  transition: color 0.3s ease;
}

.gooey-nav-container nav ul li a:hover {
  color: var(--red-bright);
}

.gooey-nav-container nav ul li:focus-within:has(:focus-visible) {
  box-shadow: 0 0 0.5px 1.5px var(--red-bright);
}

.gooey-nav-container nav ul li::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 10px;
  background: var(--white);
  opacity: 0;
  transform: scale(0);
  transition: all 0.3s ease;
  z-index: -1;
}

.gooey-nav-container nav ul li.active a {
  color: var(--black);
}

.gooey-nav-container nav ul li.active::after {
  opacity: 1;
  transform: scale(1);
}

@keyframes goo-pill {
  to {
    transform: scale(1);
    opacity: 1;
  }
}

/* Mobile nav toggle */
.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--red);
  color: var(--red-bright);
  font-size: 1.3rem;
  padding: 0.25rem 0.75rem;
  cursor: pointer;
  border-radius: 9999px;
  transition: transform 0.2s ease;
}

.nav-toggle:active {
  transform: scale(0.9);
}

/* ============================================================
   HERO — upper-half drip logo band
   A permanently dark poster block: identical in both themes (the
   values pin the old dark-palette vars so light-mode flips can't
   leak in). The block is the upper half of the viewport only: the
   wordmark rides the red glow at its bottom seam, where the page
   content (footer) begins.
   ============================================================ */
.hero {
  /* Single source of truth for the wordmark box. .hero-logo sizes itself
     from it, and .hero-mark derives its vertical offset from it so the
     watermark can never drift off the wordmark centre. */
  --logo-w: min(66vw, 940px);
  --black: #0a0a0a;
  --red-dark: #8f0d15;
  --white: #f2efec;
  /* OPAQUE dark backdrop: the wave canvas is translucent in places,
     so without this the page background (light #fafafa in light mode)
     shows through and the hero "changes themes". Hardcoded, not a
     variable — this section never re-themes. */
  background-color: #0a0a0a;
  min-height: 50svh; /* the hero IS the upper half: the lower half is gone */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end; /* wordmark pinned to the hero bottom, near the page seam */
  gap: clamp(1.4rem, 3.5vh, 2.4rem);
  padding: 6rem 1rem 2.5rem; /* top clears the floating pill; modest bottom padding keeps the wordmark clear of the seam glow */
  text-align: center;
  position: relative;
  overflow: hidden;
}

/* Gradient Waves — WebGL raymarched plasma waves (ReactBits port,
   js/gradient-waves.js), recolored black/deep-red/bright-red.
   Sits behind the hero content; a center vignette keeps the logo
   and CTA readable over the waves. */
.waves-bg {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  /* Full original hero height, anchored to the band's bottom seam:
     the visible slice is the composition's lower part (waves + red
     bottom glow) exactly where the full-screen hero showed it, while
     everything above the band is cropped away. */
  height: 100svh;
  z-index: 0;
  pointer-events: none;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(
    ellipse 60% 42% at 50% 74%,
    rgba(10, 10, 10, 0.72) 0%,
    rgba(10, 10, 10, 0.38) 55%,
    rgba(10, 10, 10, 0) 100%
  );
}

/* Red glow from the hero's bottom edge (same point as the waves'
   bottom glow) — also the seam into the themed page below: it fades
   toward the theme's background color, so light mode rolls from the
   dark poster into off-white through a warm red, never a hard line. */
.hero::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: min(34vh, 320px);
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(10, 10, 10, 0) 0%, #0a0a0a 92%),
    radial-gradient(
      circle at 50% 100%,
      rgba(232, 18, 28, 0.32) 0%,
      rgba(232, 18, 28, 0.08) 40%,
      rgba(255, 255, 255, 0) 70%
    );
}



.hero-logo {
  width: var(--logo-w);
  position: relative;
  z-index: 2;
}

.hero-logo img {
  width: 100%;
  height: auto;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
  transform-origin: 50% 0%;
  will-change: transform, clip-path;
}

/* Squiggly wobble: js/squiggle.js swaps pre-built SVG displacement
   filters on the wrapper (vanilla port of Aceternity "Squiggly Text").
   (Second .hero-logo block: its negative crop margins intentionally
   win over the base rule; the lower-half anchoring itself comes from
   justify-content flex-end on .hero, not from margins.) */
.hero-logo {
  overflow: hidden;
  margin-top: -0.35%;
  margin-bottom: -0.35%;
}

.squiggle-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Tagline */
.hero-tagline {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.55em;
  padding-left: 0.55em; /* optically re-center tracked text */
  font-size: clamp(0.62rem, 1.3vw, 0.95rem);
  color: var(--white);
  z-index: 2;
  position: relative;
}

/* CTA button with dripping border on hover */
.btn-drip {
  position: relative;
  display: inline-block;
  background: var(--black);
  border: 1px solid var(--red);
  color: var(--white);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  padding: 1rem 2.6rem 1rem calc(2.6rem + 0.35em);
  cursor: pointer;
  z-index: 2;
  position: relative;
  transition: background-color 0.25s, box-shadow 0.25s;
}

.btn-drip:hover {
  background-color: rgba(224, 23, 34, 0.09);
  box-shadow: 0 0 26px rgba(224, 23, 34, 0.16);
}

/* The drop that falls from the button's bottom edge on hover */
.btn-drip::after {
  content: "";
  position: absolute;
  left: 24%;
  top: 100%;
  width: 7px;
  height: 10px;
  margin-top: -1px;
  background: var(--red);
  border-radius: 50% 50% 50% 50% / 40% 40% 60% 60%;
  opacity: 0;
  pointer-events: none;
  transform: translate(0, -2px) scale(0.3);
}

.btn-drip:hover::after {
  animation: btn-drip-fall 0.85s cubic-bezier(0.55, 0, 0.8, 0.4) infinite;
}

@keyframes btn-drip-fall {
  0%   { opacity: 0; transform: translate(0, -2px) scale(0.3); }
  12%  { opacity: 1; transform: translate(0, 1px) scale(1); }
  70%  { opacity: 1; }
  100% { opacity: 0; transform: translate(0, 54px) scale(0.8); }
}

/* Staggered entrance for tagline + CTA (JS-gated so no-JS still shows them) */
.js .hero-tagline,
.js .btn-drip {
  opacity: 0;
  animation: hero-fade-up 0.8s ease-out forwards;
}

.js .hero-tagline { animation-delay: 0.15s; }
.js .btn-drip     { animation-delay: 0.4s; }

@keyframes hero-fade-up {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================================================
   FILM GRAIN — animated analog noise over the whole page
   ============================================================ */
.grain {
  position: fixed;
  inset: -50%;
  width: 200%;
  height: 200%;
  pointer-events: none;
  z-index: 9990;
  opacity: 0.055;
  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='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: 180px 180px;
  animation: grain-shift 0.9s steps(1) infinite;
}

@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  12%  { transform: translate(-84px, -36px); }
  25%  { transform: translate(48px, -72px); }
  37%  { transform: translate(-60px, 48px); }
  50%  { transform: translate(72px, 84px); }
  62%  { transform: translate(-96px, -12px); }
  75%  { transform: translate(24px, -60px); }
  87%  { transform: translate(-36px, 72px); }
  100% { transform: translate(0, 0); }
}

/* ============================================================
   SPLASH CURSOR — fluid-sim trail canvas (js/splash-cursor.js)
   Sits above the page but below grain; pointer-events stay off so
   links/buttons are never blocked.
   ============================================================ */
.splash-cursor-canvas {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  display: block;
  pointer-events: none;
  z-index: 50;
}

/* ============================================================
   BRAND WATERMARK — one oversized NEXTFABRI mark, page centre
   ============================================================ */
/* Opted in per page by data-watermark on <html> (about, contact,
   faq, privacy, shipping); the other five pages carry no such
   attribute and so render no ::before at all (content stays "none").

   The mark is painted at stack level -1: above the <html> canvas
   colour, below every in-flow block, so headings, copy, cards,
   page band and footer all stay on top. pointer-events:none keeps
   every control clickable. The path resolves against this
   stylesheet, hence ../ . Single mark, not a tile: no-repeat plus
   a viewport-relative size, so it scales with the window.

   VERTICAL OFFSET: the opaque .page-header band covers roughly the
   top third of the viewport, so a dead-vertically-centred mark
   loses its top edge behind it and reads as "drifted upward".
   Shifting down by half a band height (8.75rem ~ the measured
   279px band / 2) centres it in the visible content area instead,
   where the whole mark is on screen.

   The third term in background-size (100vh - 21rem) caps the mark
   to the room actually left below the band. Without it a short
   window (measured 1440x600: 360px mark vs 297px of clearance)
   clips the top AND overflows the bottom. It never binds at normal
   sizes — min() picks 60vmin at 900px tall and above.

   LOCKED: position:fixed pins the mark to the viewport, so it
   never scrolls away and never drifts. Nothing on <html> or
   <body> may gain transform / filter / will-change / contain /
   perspective — any of those would capture the fixed containing
   block and break the lock. Do not "fix" this into static. */
html[data-watermark] body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.09;
  background-image: url("../assets/logos/nextfabri-mark.png");
  background-repeat: no-repeat;
  background-position: center calc(50% + 8.75rem);
  background-size: min(620px, 60vmin, calc(100vh - 21rem)) auto;
}

/* Same mark over the porcelain base: the light theme inverts the
   canvas, so it needs a little more alpha to still register. */
html[data-watermark][data-theme="light"] body::before {
  opacity: 0.11;
}

/* ---------- Buttons (inner pages) ---------- */
.btn {
  display: inline-block;
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.9rem;
  padding: 0.85rem 2rem;
  border: 1px solid var(--red);
  background-color: var(--red);
  color: var(--white);
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s, transform 0.1s;
}

.btn:hover {
  background-color: transparent;
  color: var(--red-bright);
  transform: translateY(-2px);
}

.btn-outline {
  background-color: transparent;
  color: var(--red-bright);
}

.btn-outline:hover {
  background-color: var(--red);
  color: var(--white);
}

.btn-sm {
  padding: 0.5rem 1.2rem;
  font-size: 0.75rem;
}

/* Button pair spacing (404 "Go to Shop" / "Back Home" etc.). */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.5rem;
}

/* ---------- Section layout ---------- */
.section {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 4rem 1rem;
}

.section-title {
  font-family: var(--font-display);
  font-size: 1.7rem;
  text-transform: uppercase;
  letter-spacing: 3px;
  margin-bottom: 2rem;
}

.section-title span {
  color: var(--red);
}

/* Header row for homepage sections. Carousel and category sections
   override this to justify-content: center, so the title image
   stays dead-center between the section edges. */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2rem;
}

.section-head .section-title {
  margin-bottom: 0;
}



.carousel-section .section-title {
  margin-bottom: 0;
  font-size: 2rem;
  letter-spacing: 4px;
}



/* ---------- Product grid ---------- */
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1.5rem;
}

.product-card {
  background-color: var(--charcoal);
  border: 1px solid var(--gray-800);
  transition: border-color 0.2s, transform 0.2s, box-shadow 0.45s ease, background-color 0.45s ease;
}

.product-card:hover {
  border-color: var(--red);
  transform: translateY(-4px);
}

.product-media .product-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.value-stack {
  max-width: 720px;
}

.value-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.35rem;
  padding: 1.6rem 0;
}

.value-row + .value-row {
  border-top: 1px solid var(--gray-800);
}

.value-row h3 {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 1.05rem;
}

.value-row p {
  color: var(--gray-400);
  max-width: 55ch;
}

@media (min-width: 769px) {
  .value-row {
    grid-template-columns: 220px 1fr;
    align-items: baseline;
    gap: 2rem;
  }
}

.product-media {
  position: relative;
  background: linear-gradient(160deg, var(--gray-800), var(--charcoal));
  aspect-ratio: 3 / 4;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-600);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 2px;
}

.product-info {
  padding: 1rem;
}

.product-info h3 {
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 1px;
}

.product-info .price {
  color: var(--red-bright);
  font-weight: bold;
  margin: 0.4rem 0 0.8rem;
}

/* ---------- Product detail page ---------- */
.product-detail {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem;
}

.product-detail .product-media {
  aspect-ratio: 1 / 1;
  font-size: 1rem;
}

.product-detail h1 {
  font-family: var(--font-display);
  font-size: 2rem;
  text-transform: uppercase;
  letter-spacing: 2px;
}

.product-detail .price {
  color: var(--red-bright);
  font-size: 1.5rem;
  margin: 0.75rem 0 1.25rem;
}

.product-detail .description {
  color: var(--gray-400);
  margin-bottom: 1.5rem;
}

.option-group {
  margin-bottom: 1.5rem;
}

.option-group label {
  display: block;
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 2px;
  color: var(--gray-400);
  margin-bottom: 0.5rem;
}

.size-options {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.size-btn {
  min-width: 3rem;
  padding: 0.6rem 0.75rem;
  background: var(--charcoal);
  border: 1px solid var(--gray-600);
  color: var(--white);
  cursor: pointer;
  transition: border-color 0.2s, background-color 0.2s;
}

.size-btn.selected,
.size-btn:hover {
  border-color: var(--red);
  background-color: var(--red-dark);
}

/* ---------- Quantity stepper ----------
   -  [ 1 ]  +  as one joined control: the border belongs to the
   wrapper so the three parts read as a single field rather than
   three loose boxes. The number box keeps the old field look but
   drops its own border, and the browser's native spinners are gone
   now that there are real buttons. */
.quantity .qty-stepper {
  display: inline-flex;
  align-items: stretch;
  max-width: 100%;
  background: var(--charcoal);
  border: 1px solid var(--gray-600);
}

.quantity .qty-btn {
  width: 3rem;
  min-height: 2.9rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--white);
  font-family: var(--font-display);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s, opacity 0.2s;
}

/* Colour-only press feedback - no movement, so nothing here needs a
   prefers-reduced-motion gate. */
.quantity .qty-btn:hover:not(:disabled) {
  background: var(--red-dark);
}

.quantity .qty-btn:active:not(:disabled) {
  background: var(--red);
}

.quantity .qty-btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.quantity .qty-btn:focus-visible {
  outline: 2px solid var(--red-bright);
  outline-offset: -2px;
}

.quantity .qty-stepper input {
  width: 3.25rem;
  padding: 0.6rem 0.25rem;
  border: 0;
  border-left: 1px solid var(--gray-600);
  border-right: 1px solid var(--gray-600);
  background: transparent;
  color: var(--white);
  font-family: var(--font-body);
  font-size: 1rem;
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
}

.quantity .qty-stepper input::-webkit-outer-spin-button,
.quantity .qty-stepper input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}

.quantity .qty-stepper input:focus-visible {
  outline: 2px solid var(--red-bright);
  outline-offset: -2px;
}

/* ---------- Forms (contact) ---------- */
.contact-form {
  display: grid;
  gap: 1rem;
  max-width: 560px;
}

.contact-form label {
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 2px;
  color: var(--gray-400);
}

.contact-form input,
.contact-form textarea {
  padding: 0.75rem;
  background: var(--charcoal);
  border: 1px solid var(--gray-600);
  color: var(--white);
  font-family: var(--font-body);
  font-size: 1rem;
}

.contact-form input:focus,
.contact-form textarea:focus {
  outline: 2px solid var(--red);
  outline-offset: 1px;
}

.form-status {
  min-height: 1.5rem;
  color: var(--red-bright);
}

/* ---------- Page header (inner pages) ---------- */
/* Registered custom property so the theme swap can INTERPOLATE the
   header wash (plain gradients are not animatable). */
@property --ph-glow {
  syntax: "<color>";
  inherits: true;
  initial-value: rgba(143, 13, 21, 0);
}

/* Grainient layer (ReactBits port) behind inner-page titles.
   The page-header keeps its themed backdrop; the shader canvas
   fills the band and the existing content stacks above it. */
.page-header {
  position: relative;
  overflow: hidden;
}

.grainient-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.page-header > *:not(.grainient-bg) {
  position: relative;
  z-index: 1;
}

.page-header {
  --ph-glow: var(--red-dark);
  background: linear-gradient(135deg, var(--black) 60%, var(--ph-glow));
  border-bottom: 1px solid var(--red);
  padding: 7rem 1rem 3.5rem; /* top clears the floating pill */
  text-align: center;
  transition: --ph-glow 0.45s ease, background-color 0.45s ease;
}

/* Inner pages without a page-header still clear the pill */
main.section:first-of-type {
  padding-top: 7.5rem;
}

.page-header h1 {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 4px;
  font-size: clamp(1.8rem, 4vw, 3rem);
}

.page-header p {
  color: var(--gray-400);
  margin-top: 0.5rem;
}

/* ---------- Footer ---------- */
.site-footer {
  background-color: var(--charcoal);
  border-top: 1px solid var(--red);
  margin-top: 4rem;
}

.site-footer .footer-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 2.5rem 1rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 2rem;
}

.footer-logo {
  height: 56px;
  width: auto;
  margin-bottom: 0.7rem;
  filter: none !important; /* footer logo is static by design — no squiggle */
}

.site-footer h4 {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.85rem;
  margin-bottom: 0.75rem;
  color: var(--red-bright);
}

.site-footer ul {
  list-style: none;
}

.site-footer li {
  margin-bottom: 0.4rem;
}

.site-footer a {
  color: var(--gray-400);
  font-size: 0.9rem;
}

.site-footer a:hover {
  color: var(--white);
}

/* "Stalk Us" is a regular footer column in .footer-inner (same markup
   shape as the Shop / Nextfabri columns), so it inherits the shared
   h4/ul/li/a treatment and matches the rest of the footer by design. */

/* ============================================================
   ACCOUNT PAGE - sign-up panel + why-join perks
/* ============================================================
   ACCOUNT — SIGN IN / REGISTER
   One centered charcoal panel holding the tabbed login/register
   form (the old perks aside was removed). Inputs and labels reuse
   the shared .contact-form treatment.
   ============================================================ */
.account-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 3rem;
  align-items: start;
  justify-items: center;
}

.account-panel {
  /* The contact form caps at 560px; the account panel matches so the
     form reads as a single centered card on every screen. */
  max-width: 560px;
  width: 100%;
  background: var(--charcoal);
  border: 1px solid var(--gray-800);
  padding: 2rem;
}

.account-lede {
  color: var(--gray-400);
  margin: -0.4rem 0 0.4rem;
  max-width: 46ch;
}

.account-field {
  display: grid;
  gap: 0.45rem;
}

.account-optional {
  color: var(--gray-600);
  letter-spacing: 1px;
  text-transform: none;
  font-size: 0.68rem;
}

.account-hint {
  color: var(--gray-600);
  font-size: 0.75rem;
  margin: -0.2rem 0 0;
}

.account-panel select {
  width: 100%;
  padding: 0.75rem 2.4rem 0.75rem 0.75rem;
  background-color: var(--charcoal);
  border: 1px solid var(--gray-600);
  color: var(--white);
  font-family: var(--font-body);
  font-size: 1rem;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  /* Custom chevron (gray works on both themes) */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a857f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 14px;
}

.account-panel select:focus {
  outline: 2px solid var(--red);
  outline-offset: 1px;
}

.account-submit {
  width: 100%;
  display: block;
  text-align: center;
  padding: 1rem 2rem;
}

@media (max-width: 900px) {
  .account-layout {
    grid-template-columns: minmax(0, 1fr);
  }
}

.footer-bottom {
  border-top: 1px solid var(--gray-800);
  text-align: center;
  padding: 1rem;
  color: var(--gray-600);
  font-size: 0.8rem;
}

/* ---------- Cart drawer ---------- */
.cart-drawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  width: min(380px, 100%);
  background: var(--charcoal);
  border-left: 1px solid var(--red);
  transform: translateX(100%);
  transition: transform 0.3s ease;
  z-index: 200;
  display: flex;
  flex-direction: column;
}

.cart-drawer.open {
  transform: translateX(0);
}

.cart-drawer .cart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--gray-800);
}

.cart-drawer .cart-header h3 {
  text-transform: uppercase;
  letter-spacing: 2px;
}

.cart-close {
  background: none;
  border: none;
  color: var(--red-bright);
  font-size: 1.5rem;
  cursor: pointer;
}

.cart-items {
  flex: 1;
  overflow-y: auto;
  padding: 1.25rem;
}

.cart-empty {
  color: var(--gray-600);
  text-align: center;
  margin-top: 3rem;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.8rem;
}

.cart-item {
  display: flex;
  /* Thumb, text and the remove icon all top-align: the icon is
     anchored to the first line of the row, not centred against a
     two-line block. */
  align-items: flex-start;
  gap: 0.75rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--gray-800);
  padding-bottom: 1rem;
}

.cart-item .cart-thumb {
  width: 56px;
  height: 72px;
  background: var(--gray-800);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6rem;
  color: var(--gray-600);
  overflow: hidden;
  flex-shrink: 0;
}

.cart-item .cart-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.cart-item h4 {
  font-size: 0.9rem;
  text-transform: uppercase;
}

.cart-item .cart-meta {
  font-size: 0.8rem;
  color: var(--gray-400);
}

/* Takes the slack between the text and the remove icon, so the icon
   is pinned to the drawer's right edge however long the name is.
   min-width:0 lets a long name wrap instead of pushing the icon out. */
.cart-item .cart-info {
  flex: 1;
  min-width: 0;
}

/* Remove = a trash icon on the right of the row (was a red "Remove"
   word sitting under the item). Icon-only, so the accessible name
   comes from aria-label. Quiet by default, brand red on hover/focus
   so it reads as destructive without shouting down the whole row. */
.cart-item .cart-remove {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  background: none;
  border: 1px solid transparent;
  border-radius: 2px;
  color: var(--gray-400);
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}

.cart-item .cart-remove svg {
  width: 15px;
  height: 15px;
}

.cart-item .cart-remove:hover {
  color: var(--red-bright);
  border-color: var(--red);
  background: rgba(224, 23, 34, 0.1);
}

.cart-item .cart-remove:focus-visible {
  outline: 2px solid var(--red-bright);
  outline-offset: 2px;
}

.cart-footer {
  border-top: 1px solid var(--red);
  padding: 1.25rem;
}

/* The drawer's primary action. Flex-centring pins the label dead-centre
   of the red band (it used to clip at the baseline) and the slightly
   smaller size keeps the label comfortable inside the 380px column. */
.cart-footer .btn {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  line-height: 1;
  font-size: 0.82rem;
  padding: 1rem 2rem;
}

.cart-total {
  display: flex;
  justify-content: space-between;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}

/* "Continue Shopping" sits under Checkout: same full-width footprint,
   outlined instead of solid so it reads as the way BACK to the grid
   and never competes with the red primary above it. */
.cart-continue {
  display: block;
  width: 100%;
  margin-top: 0.7rem;
  text-align: center;
  font-size: 0.8rem;
}

/* Cart badge in header */
.cart-link {
  position: relative;
  color: var(--white);
  text-transform: uppercase;
  font-size: 0.85rem;
  letter-spacing: 2px;
}

.cart-count {
  background: var(--red);
  color: var(--white);
  border-radius: 999px;
  font-size: 0.7rem;
  padding: 0.1rem 0.45rem;
  margin-left: 0.35rem;
}

/* ---------- Toast ---------- */
.toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%) translateY(150%);
  opacity: 0; /* fully invisible while hidden: translateY alone leaves a red edge sliver at the viewport bottom */
  pointer-events: none;
  background: var(--red);
  color: var(--white);
  padding: 0.75rem 1.5rem;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.8rem;
  transition: transform 0.3s ease, opacity 0.3s ease;
  z-index: 300;
}

.toast.show {
  transform: translateX(-50%) translateY(0);
  opacity: 1;
  pointer-events: auto;
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .grain,
  .js .hero-tagline,
  .js .btn-drip,
  .btn-drip:hover::after,
  .splash-cursor-canvas {
    display: none !important;
  }

  .js .hero-tagline,
  .js .btn-drip {
    opacity: 1;
  }
}

/* ---------- Responsive ---------- */
@media (max-width: 768px) {
  .site-header {
    padding: 0.6rem 0.75rem 0;
  }

  .nav-inner {
    border-radius: 1.4rem;
    padding: 0.55rem 0.9rem;
  }

  .nav-toggle {
    display: block;
  }

  /* On mobile the dropdown carries Account, so the header
     icon yields its slot to the menu button. Compound selector
     beats .account-link in theme.css, which loads later. */
  .nav-actions .account-link {
    display: none;
  }

  /* Mobile dropdown: the pill unrolls into a card. It hugs its
     content rather than spanning the header - left:0/right:0 left
     a wide dead zone beside the short labels - and is right-aligned
     so it hangs under the menu button instead of drifting to one
     side. max-width:100% clamps it on very narrow screens. */
  .main-nav {
    display: none;
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    width: max-content;
    max-width: 100%;
    background: rgba(12, 12, 13, 0.96);
    border: 1px solid rgba(224, 23, 34, 0.3);
    border-radius: 1.4rem;
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    overflow: hidden;
  }

  .main-nav.open {
    display: block;
  }

  /* Reveal/hide motion: the card drops out of the pill (slight scale
     + fade) while the links stagger in from the right. Hiding plays a
     shorter lift via .closing — added by main.js for the exit beat,
     because display:none cannot animate. All motion lives behind
     prefers-reduced-motion: no-preference. */
  @media (prefers-reduced-motion: no-preference) {
    @keyframes nav-card-in {
      from { opacity: 0; transform: translateY(-12px) scale(0.96); }
      to   { opacity: 1; transform: translateY(0) scale(1); }
    }

    @keyframes nav-card-out {
      from { opacity: 1; transform: translateY(0) scale(1); }
      to   { opacity: 0; transform: translateY(-10px) scale(0.97); }
    }

    @keyframes nav-item-in {
      from { opacity: 0; transform: translateX(14px); }
      to   { opacity: 1; transform: translateX(0); }
    }

    .main-nav.open {
      animation: nav-card-in 0.36s cubic-bezier(0.22, 1, 0.36, 1) both;
    }

    .main-nav.closing {
      display: block;
      animation: nav-card-out 0.26s cubic-bezier(0.4, 0, 1, 1) both;
    }

    /* .main-nav and .gooey-nav-container are the SAME element in the
       markup, so the links are reached directly via nav ul li. */
    .main-nav.open nav ul li {
      animation: nav-item-in 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
    }

    .main-nav.open nav ul li:nth-child(1) { animation-delay: 0.06s; }
    .main-nav.open nav ul li:nth-child(2) { animation-delay: 0.11s; }
    .main-nav.open nav ul li:nth-child(3) { animation-delay: 0.16s; }
    .main-nav.open nav ul li:nth-child(4) { animation-delay: 0.21s; }
    .main-nav.open nav ul li:nth-child(5) { animation-delay: 0.26s; }
  }

  .gooey-nav-container nav ul {
    flex-direction: column;
    gap: 0;
    padding: 0.5rem;
  }

  .gooey-nav-container nav ul li a {
    display: block;
    padding: 0.8rem 1rem;
    border-bottom: 1px solid var(--gray-800);
  }

  .gooey-nav-container nav ul li:last-child a {
    border-bottom: none;
  }

  /* Gooey effect layer is desktop-only noise on mobile */
  .hero {
    --logo-w: min(88vw, 520px);
  }

  .product-detail {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   NEW DROP CAROUSEL - flat coverflow matching the reference
   shots (js/newdrop-carousel.js): the active slide is one big
   product shot with a caption row (name + "Graphic Tee" sub,
   price at the right); neighbor slides are dimmed front+back
   pairs. No arrows, no dots, no card chrome. Colors ride the
   variables so the porcelain light theme applies for free.
   ============================================================ */
.newdrop-carousel {
  position: relative;
}

.nd-stage {
  position: relative;
  /* Full-bleed: edge-to-edge, so the outer hoodies have room */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  height: clamp(470px, 50vw, 580px);
  touch-action: pan-y;
  overflow: hidden;
  cursor: grab; /* hold and swipe */
  user-select: none; /* no text selection while swiping */
  -webkit-user-select: none;
}

.nd-stage.nd-dragging { cursor: grabbing; }

/* While held: slides follow the pointer 1:1, so transitions off;
   on release the class drops and the snap animates. */
.newdrop-carousel.nd-dragging .nd-slide {
  transition: none;
}

/* No native image-drag ghosts inside the carousel */
.nd-slide img {
  -webkit-user-drag: none;
  user-drag: none;
}

/* Slides are absolutely centered; the JS sets translateX and
   opacity per position (flat - no rotateY / translateZ). */
.nd-slide {
  position: absolute;
  /* Centered track: the active product sits in the middle of
     the stage, neighbors trail on BOTH sides. */
  left: 50%;
  top: 0;
  width: min(450px, 86vw);
  margin-left: calc(min(450px, 86vw) / -2);
  /* Two-phase motion: SWIFT position glide (ease-out - fast out,
     gentle settle); the featured hoodie itself swaps in a beat
     AFTER the strip rests (JS), so the content never snaps
     mid-move. Opacity follows the phase-2 class swap. */
  transition: transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
  text-align: center;
}

/* Square boxes keep every product shot the same visual height
   no matter each PNG's native aspect. Narrow width param added:
   the crop stays full-height (contain), so the card keeps its
   400px vertical mass while its width slims down. */
.nd-slide img {
  width: 100%;
  height: min(400px, 70vw);
  object-fit: contain;
  filter: drop-shadow(0 20px 32px rgba(0, 0, 0, 0.3));
}

/* Active slide: one hero shot + caption row below.
   Narrower than tall on purpose: cards read as slim portrait
   panels while keeping the original 400px height. */
.nd-hero-link {
  display: block;
  width: min(340px, 60vw);
  margin: 0 auto;
}

.nd-hero-link .nd-hero, .nd-slide > .nd-hero {
  width: 100%;
}

.nd-slide .nd-hero {
  display: block;
  margin: 0 auto;
}

.nd-caption {
  display: none;
  align-items: baseline;
  justify-content: center;
  gap: 2.75rem;
  margin-top: 1.6rem;
}

.nd-name {
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 1.15rem;
  color: var(--white);
  text-align: left;
}

.nd-sub {
  display: block;
  margin-top: 0.4rem;
  font-size: 0.8rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  font-weight: normal;
  color: var(--gray-400);
}

.nd-price {
  font-size: 1.05rem;
  color: var(--gray-400);
}

.nd-slide.active .nd-caption {
  display: flex;
  animation: nd-reveal 0.45s ease 0.05s both;
}

.nd-slide.active .nd-hero-link {
  animation: nd-reveal 0.45s ease 0.05s both;
}

@keyframes nd-reveal {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Minimal swipe controls under the featured hoodie: hairline
   chevrons and a small position counter, riding the theme vars. */
.nd-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.4rem;
  margin-top: 1.4rem;
}

.nd-nav button {
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 9999px;
  border: 1px solid var(--gray-800);
  background: transparent;
  color: var(--white);
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.2s, color 0.2s;
}

.nd-nav button:hover {
  border-color: var(--red);
  color: var(--red-bright);
}

.nd-count {
  font-size: 0.72rem;
  letter-spacing: 2px;
  color: var(--gray-400);
  min-width: 3.2rem;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .nd-slide { transition: none; }
}

/* ============================================================
   LIGHT THEME — structural overrides
   (Variable flips live in css/theme.css. Dark mode is untouched:
   every rule here is scoped under html[data-theme="light"].)
   ============================================================ */

/* The floating pill goes porcelain: off-white glass, a neutral
   hairline border with a slightly stronger bottom edge (the "thin
   bottom border"), and a soft neutral shadow. Ink text comes free
   from the var flips (--white becomes ink in light mode). */
html[data-theme="light"] .nav-inner {
  background: rgba(250, 250, 250, 0.86);
  border-color: rgba(10, 10, 10, 0.12);
  border-bottom-color: rgba(10, 10, 10, 0.24);
  box-shadow: 0 10px 32px rgba(20, 20, 20, 0.08);
}

html[data-theme="light"] .site-header.scrolled .nav-inner {
  background: rgba(250, 250, 250, 0.78);
  border-color: rgba(10, 10, 10, 0.14);
  border-bottom-color: rgba(10, 10, 10, 0.26);
  box-shadow:
    0 10px 32px rgba(20, 20, 20, 0.1),
    0 0 24px rgba(196, 14, 24, 0.06);
}

/* Gooey nav on porcelain: the active pill + goo plate flip from
   white to brand red — a white pill would vanish on the off-white
   bar. (Labels/hover/active text already resolve correctly via the
   light-theme variable flips.) */
html[data-theme="light"] .gooey-nav-container nav ul li::after,
html[data-theme="light"] 
/* Hero goes light for real (the WebGL waves re-theme via JS): ink
   tagline (base var already flips), solid red CTA, and the wave
   canvas fades out toward the fold so the red glow owns the seam. */
/* Depth pass: white cards need red-undertoned shadows + darker borders
   to separate from the #fafafa base; footer gets its own tone; the
   inner-page header washes red instead of fading to dark red. */
html[data-theme="light"] .product-card {
  border-color: rgba(10, 10, 10, 0.1);
  box-shadow: 0 2px 14px rgba(196, 14, 24, 0.06);
}

html[data-theme="light"] .product-card:hover {
  border-color: var(--red);
  box-shadow: 0 10px 28px rgba(196, 14, 24, 0.12);
}

/* Homepage section pieces on porcelain. */
html[data-theme="light"] .site-footer {
  background-color: #f1eeec;
}

html[data-theme="light"] .page-header {
  --ph-glow: rgba(232, 18, 28, 0.12);
}

/* Grain reads as grit via multiply on the light base (still ~5%) */
html[data-theme="light"] .grain {
  opacity: 0.05;
  mix-blend-mode: multiply;
}

/* Solid red fills get white text in light mode (the ink --white flip
   would otherwise sit dark-on-dark-red), with hover states that stay
   readable on the light base. */
html[data-theme="light"] .btn,
html[data-theme="light"] .toast {
  color: #ffffff;
}

html[data-theme="light"] .btn:hover {
  color: var(--red-dark);
}

html[data-theme="light"] .size-btn.selected,
html[data-theme="light"] .size-btn:hover {
  color: #ffffff;
}

/* Mobile dropdown card matches the porcelain pill (its red-tinted
   border and blurred glass carry over as-is). */
@media (max-width: 768px) {
  html[data-theme="light"] .main-nav {
    background: rgba(250, 250, 250, 0.97);
  }
}


/* ============================================================
   PERMANENTLY DARK HEADER BAND - the grainient page-header keeps
   the dark palette in BOTH themes. In light theme the washed-out
   porcelain shader made the title images unreadable (user report),
   so the band is pinned to the dark look instead of re-themed.
   Also covers the reduced-motion case where the shader never
   starts and the CSS gradient shows. Title images inside the band
   always use the dark-theme PNG (white ink) - the band never goes
   light, so black ink would vanish into it.
   ============================================================ */
html[data-theme="light"] .page-header {
  --black: #0a0a0a;
  --ph-glow: #8f0d15;
  --red: #e01722;
  --gray-400: #8d8d97;
  color: #f2efec;
}


/* ============================================================
   SHOP TOOLBAR + CHROMELESS GRID - Aldren-style collection page:
   slim inline filter row (Color / Type / Sort by + live count)
   over a hairline rule, products as bare centered figures on the
   page background (no card chrome, no buttons).
   ============================================================ */
.shop-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1.2rem 1.6rem;
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--gray-800);
  margin-bottom: 2.4rem;
}

.filter-group {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.filter-label {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.68rem;
  color: var(--gray-400);
}

.filter-dropdown {
  position: relative;
}

.filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.72rem;
  color: var(--white);
  padding: 0.2rem 0;
}

.filter-btn .chev {
  width: 12px;
  height: 12px;
  stroke: currentColor;
  transition: transform 0.2s;
}

.filter-dropdown.open .chev {
  transform: rotate(180deg);
}

.filter-menu {
  position: absolute;
  top: calc(100% + 0.55rem);
  left: -0.75rem;
  min-width: 10rem;
  z-index: 30;
  background: var(--charcoal);
  border: 1px solid var(--gray-800);
  list-style: none;
  padding: 0.35rem 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}

.filter-dropdown.open .filter-menu {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.filter-menu li {
  padding: 0.5rem 0.95rem;
  font-size: 0.75rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--gray-400);
  cursor: pointer;
  white-space: nowrap;
}

.filter-menu li:hover {
  color: var(--white);
  background: var(--gray-800);
}

.filter-menu li[aria-selected="true"] {
  color: var(--red-bright);
}

.shop-count {
  margin-left: auto;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.68rem;
  color: var(--gray-400);
}

.shop-empty {
  color: var(--gray-400);
  letter-spacing: 1px;
  padding: 2.5rem 0;
}

/* Full-bleed shop section: toolbar + grid stretch toward the page
   edges (same recipe as the homepage carousel stage), with a
   comfortable inner edge padding. */
.shop-grid-section {
  width: 100vw;
  max-width: none;
  margin-left: calc(50% - 50vw);
  padding-left: 2rem;
  padding-right: 2rem;
}

/* The collection grid: all 5 products in one row on desktop
   (scaled down to fit the full-bleed width), 3 on laptop,
   2 on tablet, 1 on phones. No card chrome. */
.shop-grid-section .product-grid {
  grid-template-columns: repeat(5, 1fr);
  gap: 2.4rem 1.4rem;
}

.product-card {
  background: none;
  border: none;
  text-align: center;
}

.product-card[hidden] {
  display: none;
}

.product-card .product-media {
  background: none;
  overflow: hidden;
}

.product-card .product-img {
  transition: transform 0.4s ease;
}

.product-card:hover .product-img {
  transform: scale(1.03);
}

.product-info {
  padding: 1.15rem 0 0;
}

.product-info h3 {
  font-size: 0.85rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  margin-bottom: 0.25rem;
}

.product-info .price {
  color: var(--gray-400);
  font-size: 0.78rem;
}

@media (max-width: 1100px) {
  .shop-grid-section .product-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  .shop-count {
    margin-left: 0;
  }
}

@media (max-width: 760px) {
  .shop-grid-section .product-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 520px) {
  .shop-grid-section .product-grid {
    grid-template-columns: 1fr;
  }
}
/* ============================================================
   MOBILE ACCOUNT ENTRY
   The Account link belongs to the MOBILE dropdown only. Desktop
   keeps its account icon in the action cluster, and a fifth inline
   nav item collides with that cluster in the 680px scrolled pill
   (measured 14px overlap at 1440px).
   ============================================================ */
@media (min-width: 769px) {
  .main-nav nav ul li a[href="account.html"] {
    display: none;
  }
}

/* ============================================================
   HERO WATERMARK - the square mark sitting behind the elongated
   wordmark. It is a SIBLING of .hero-logo, not a child: the
   wrapper carries the squiggle displacement filter and
   overflow:hidden (anti-clip), and .hero-logo img{width:100%}
   would stretch it. Sibling + absolute avoids all three.
   Sits at z-index 1: above .waves-bg (0), below the wordmark (2).
   ============================================================ */
.hero-mark {
  position: absolute;
  left: 50%;
  /* Bottom edge = .hero padding-bottom + half the wordmark height, so the
     mark lands ON the wordmark centre. translateY(50%) then puts the
     mark's own centre at exactly that offset. Wordmark height is derived
     from its locked width: min(66vw,940px) x 709/1600. */
  bottom: calc(2.5rem + var(--logo-w) * 0.443125 / 2);
  transform: translate(-50%, 50%);
  /* The mark is bright red (RGB 230,30,38) on a dark-red hero, so plain
     alpha had no contrast to read against. mix-blend-mode:screen
     lifts it off the field and keeps it a watermark, not a second
     logo. Tuned by eye at 0.3. */
  width: clamp(210px, 30vw, 430px);
  height: auto;
  opacity: 0.3;
  mix-blend-mode: screen;
  z-index: 1;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* ============================================================
   SCROLL REVEAL - sections fade up into place once, on entry.
   Driven by js/scroll-reveal.js, which adds .reveal itself, so a
   JS failure leaves every section visible (no hidden state lives in
   the markup). The hidden state is scoped to
   (prefers-reduced-motion: no-preference) so reduced-motion users
   are never served blank content.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  /* The hidden state carries NO transition. The class is added by
     script after first paint, so a transition here would animate the
     section fading OUT to hidden and then back IN again - a visible
     flicker. Snapping to hidden is instant; only the .is-visible
     rule animates, so the reveal is a single one-way fade. */
  .reveal {
    opacity: 0;
    transform: translateY(26px);
  }

  .reveal.is-visible {
    opacity: 1;
    transform: none;
    transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
      transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
  }

  /* Shop grid: cards deal in one by one with a small stagger. Same
     safety model as .reveal — the class is added by script, and once
     the entrance transition finishes BOTH classes are stripped, so
     filter/sort reordering can never inherit a hidden state. */
  .reveal-card {
    opacity: 0;
    transform: translateY(22px) scale(0.98);
  }

  .reveal-card.is-visible {
    opacity: 1;
    transform: none;
    transition: opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
      transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
  }
}

/* The product page uses the site-standard centred container
   (margin: 0 auto inherited from .section) like every other page. */
/* ============================================================
   PRODUCT GALLERY - little boxes left of the main image
   The catalogue holds one shot per angle per product, so the
   strip is built from data and grows on its own when another
   shot is added. Vertical column beside the big image box on
   desktop; a horizontal row above it on narrow screens, where a
   column would squeeze the main image too far. The boxes carry
   no visible text - which shot is which is carried by the red
   ring on the active box, and by the aria-label for screen
   readers.
   ============================================================ */
.product-gallery {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
}

/* Pin the image to the box instead of letting it size the box. When the
   gallery stacks (narrow screens) .product-media becomes a column-flex
   item, and an in-flow img would resolve the height from its own
   intrinsic 3:4 ratio - stretching the box to 520px tall and breaking
   the 1:1 crop. .product-media is already position:relative. */
.product-gallery .product-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* The image no longer contributes to the box, so in the side-by-side
   layout the media box has to be told to take the leftover width. The
   stacking layout resets this below, where the cross axis already
   supplies the width and the main axis must come from the 1:1 ratio. */
.product-gallery .product-media {
  flex: 1 1 0;
  min-width: 0;
}

.product-thumbs {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  flex: 0 0 auto;
}

.product-thumb {
  position: relative;
  width: 76px;
  padding: 0;
  cursor: pointer;
  background: linear-gradient(160deg, var(--gray-800), var(--charcoal));
  border: 1px solid var(--gray-600);
  border-radius: 2px;
  overflow: hidden;
  transition: border-color 0.25s ease, transform 0.25s ease;
}

.product-thumb img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.product-thumb:hover {
  border-color: var(--red);
  transform: translateY(-2px);
}

/* The shot currently shown in the big box. */
.product-thumb.active {
  border-color: var(--red);
  box-shadow: 0 0 0 1px var(--red);
}

.product-thumb:focus-visible {
  outline: 2px solid var(--red-bright);
  outline-offset: 2px;
}

@media (max-width: 768px) {
  .product-gallery {
    /* Markup order is [thumbs, media], so a plain column puts the
       strip above the image - the side-by-side layout would leave
       the main shot squeezed on a narrow screen. */
    flex-direction: column;
    /* Stretch, don't shrink-to-fit: in a column flex the base
       align-items:flex-start would size the media box to the image's
       intrinsic width and push the page into horizontal overflow. */
    align-items: stretch;
    gap: 0.7rem;
  }

  .product-thumbs {
    flex-direction: row;
  }

  /* Height now comes from the 1:1 aspect ratio, not from flex growth. */
  .product-gallery .product-media {
    flex: none;
  }
}
/* ============================================================
   PRODUCT PAGE - price + buy controls
   The product page shows a single price: what you pay, nothing
   struck through beside it. Two small animations sit on the buy
   controls: the chosen size pops, and the quantity stepper
   pulses when the number changes. Both are inside
   prefers-reduced-motion: no-preference, so anyone who asked
   their OS to calm things down gets instant state changes
   instead of motion.
   ============================================================ */
.price-now {
  color: var(--red-bright);
  font-size: 1.5rem;
}

/* The description moved below the buy controls, so it reads as its own
   block rather than trailing straight off the Add to Cart button. */
.product-detail .description {
  margin: 1.75rem 0 0;
  padding-top: 1.5rem;
  border-top: 1px solid var(--gray-800);
}

@media (prefers-reduced-motion: no-preference) {
  /* The chosen size snaps into place. Re-adding .selected replays it. */
  @keyframes nf-size-pop {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.12); }
    100% { transform: scale(1); }
  }

  .size-btn.selected {
    animation: nf-size-pop 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  /* The whole quantity control flares when the number changes. It is
     the wrapper, not the inner input, that owns the border now. */
  @keyframes nf-qty-pulse {
    0%   { box-shadow: 0 0 0 0 var(--red); border-color: var(--gray-600); }
    35%  { box-shadow: 0 0 0 4px rgba(224, 23, 34, 0.28); border-color: var(--red); }
    100% { box-shadow: 0 0 0 0 rgba(224, 23, 34, 0); border-color: var(--gray-600); }
  }

  .quantity .qty-stepper.qty-bump {
    animation: nf-qty-pulse 0.7s ease-out;
  }
}

/* ============================================================
   PRODUCT PAGE - buy row
   Two ways to commit: keep it in the bag, or skip the browsing
   and go straight to Checkout. They sit side by side and share
   the row evenly; below ~420px they each take a full line so the
   labels never shrink into ellipses. Buy Now is the inverted
   face of the red Add to Cart button - --charcoal/--white swap
   meaning between themes, so it flips with the site.
   ============================================================ */
.product-detail .buy-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.product-detail .buy-row .btn {
  flex: 1 1 12rem;
}

.product-detail .buy-now {
  background-color: var(--charcoal);
  border-color: var(--charcoal);
  color: var(--white);
}

.product-detail .buy-now:hover {
  background-color: var(--red);
  border-color: var(--red);
  color: var(--white);
}

/* In light theme --charcoal is white, so the inverted surface has to be
   the dark ink instead, or the button reads as white-on-white. These
   selectors also outrank the blanket light-mode .btn white-text rule
   above, which exists for solid red buttons and would fight them. */
html[data-theme="light"] .product-detail .buy-now {
  background-color: var(--white);
  border-color: var(--white);
  color: #ffffff;
}

html[data-theme="light"] .product-detail .buy-now:hover {
  background-color: var(--red);
  border-color: var(--red);
  color: #ffffff;
}

/* ============================================================
   PRODUCT PAGE - specification sheet + similar products rail
   The spec sheet is a static dl rendered under the buy box; the
   similar rail (built from js/products.js) stacks beneath it. Both
   span the full product-detail width (grid-column 1/-1) on every
   screen — the old 340px third-column rail is gone now that the
   page reads as one continuous sheet: story, facts, then the rest
   of the catalogue.
   ============================================================ */
.product-specs {
  grid-column: 1 / -1;
  padding-top: 1.75rem;
  border-top: 1px solid var(--gray-800);
}

.specs-heading {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--gray-400);
  margin: 0 0 1.25rem;
}

.specs-list {
  margin: 0;
}

.spec-row {
  display: flex;
  gap: 1rem;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--gray-800);
}

.spec-row dt {
  flex: 0 0 8.5rem;
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--gray-400);
  padding-top: 0.15rem;
}

.spec-row dd {
  margin: 0;
  font-size: 0.9rem;
  color: var(--white);
}

.similar-rail {
  align-self: start;
  grid-column: 1 / -1;
  margin-top: 2.5rem;
}

/* Heading and the "View All" link share one row, so the rule underneath
   spans the whole width instead of stopping at the heading. */
.similar-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.5rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--gray-800);
}

.similar-heading {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--gray-400);
  margin: 0;
}

.similar-view-all {
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--gray-400);
  white-space: nowrap;
  flex: none;
  transition: color 0.2s;
}

.similar-view-all:hover {
  color: var(--red-bright);
}

.similar-view-all:focus-visible {
  outline: 2px solid var(--red-bright);
  outline-offset: 2px;
}

.similar-grid {
  /* auto-fit rather than a fixed count: the same rule gives 2 cards per
     row in the 340px rail, 4 across the full-width stacked position, and
     2 on a phone - and empty tracks collapse, so the four cards always
     spread evenly instead of stranding a gap at the end. */
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1.5rem 1.25rem;
}

.similar-card .similar-media {
  /* The shared .product-media is 3:4; the rail is narrow, so a slightly
     less tall crop keeps two cards per row readable. */
  aspect-ratio: 4 / 5;
  display: block;
  overflow: hidden;
}

.similar-card .product-img {
  transition: transform 0.4s ease;
}

.similar-card:hover .product-img {
  transform: scale(1.04);
}

.similar-info h3 {
  font-size: 0.75rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  margin: 0.9rem 0 0.2rem;
}

.similar-price {
  color: var(--gray-400);
  font-size: 0.78rem;
}

/* ============================================================
   PRODUCT PAGE - back to shop
   A bare text link read as an afterthought sitting above the buy
   controls, so it now gets the same treatment as everything else
   on the page: small, uppercase, letterspaced, boxed. The arrow
   steps left on hover to show which way it goes, which is the
   only moving part - and that is gated below.
   ============================================================ */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: 1.75rem;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--gray-800);
  background: var(--charcoal);
  color: var(--gray-400);
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}

.back-link:hover {
  color: var(--white);
  border-color: var(--red);
}

.back-link:focus-visible {
  outline: 2px solid var(--red-bright);
  outline-offset: 2px;
}

.back-arrow {
  display: inline-block;
  line-height: 1;
}

@media (prefers-reduced-motion: no-preference) {
  /* Transition sits on the resting arrow, not the hover rule, so it
     eases back out again instead of snapping. */
  .back-arrow {
    transition: transform 0.25s ease;
  }

  .back-link:hover .back-arrow {
    transform: translateX(-4px);
  }
}

@media (max-width: 520px) {
  /* Thumb-sized on phones: the desktop box is only 38px tall, which is
     under the 44px people expect to be able to hit. */
  .back-link {
    padding: 0.9rem 1.1rem;
  }
}

/* ============================================================
   CONTACT PAGE - email, channels, self-serve
   The three blocks sit in one column with generous spacing, and
   the channel cards share a single outer border with dividers
   between them, so the row reads as one banded strip rather
   than three boxes floating apart.
   ============================================================ */
.contact-blocks {
  max-width: 1000px;
}

.contact-block + .contact-block {
  margin-top: 3.5rem;
}

.contact-label {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--gray-400);
  margin: 0 0 0.9rem;
}

.contact-note {
  color: var(--gray-400);
  margin: 0 0 1.75rem;
  max-width: 46ch;
}

/* The 46ch cap is for the contact page's left-aligned lede; the
   empty-state pages (404, empty cart, empty index) are centred, so
   the capped block needs auto margins or it hugs the left. */
.cart-page-empty .contact-note,
.shop-empty .contact-note {
  margin-left: auto;
  margin-right: auto;
}

.contact-email {
  display: inline-block;
}

/* ---------- Channel cards ---------- */
.channel-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid var(--gray-800);
  /* The cards ARE a <ul> — strip the browser's default markers and
     the ul's default left padding, or a stray white bullet (and an
     indent) shows up beside every card. Same reset every other list
     on the site carries. */
  list-style: none;
  margin: 0;
  padding: 0;
}

.channel {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 1.4rem 1.25rem;
  color: var(--gray-400);
  transition: background-color 0.2s, color 0.2s;
}

/* The grid's children are the <li> wrappers, not the links inside them,
   so the divider has to hang off the li or it never matches. */
.channel-grid > li + li {
  border-left: 1px solid var(--gray-800);
}

.channel:hover {
  background: var(--gray-800);
  color: var(--white);
}

.channel:focus-visible {
  outline: 2px solid var(--red-bright);
  outline-offset: -2px;
}

.channel-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 1px solid var(--gray-600);
  border-radius: 50%;
  color: var(--red-bright);
}

.channel-icon svg {
  width: 1.1rem;
  height: 1.1rem;
}

.channel-text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0; /* lets the detail ellipsis instead of stretching the card */
}

.channel-name {
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--white);
}

.channel-detail {
  font-size: 0.78rem;
  color: var(--gray-400);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.channel-arrow {
  margin-left: auto;
  flex: none;
  color: var(--gray-600);
  transition: color 0.2s, transform 0.25s ease;
}

.channel:hover .channel-arrow {
  color: var(--red-bright);
}

@media (prefers-reduced-motion: no-preference) {
  /* The arrow slides only for people who have not asked their OS to
     calm motion down; the colour change above happens either way. */
  .channel:hover .channel-arrow {
    transform: translateX(4px);
  }
}

/* ---------- Self-serve row ---------- */
.selfserve-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.selfserve-row .btn {
  font-size: 0.72rem;
  padding: 0.75rem 1.5rem;
}

@media (max-width: 760px) {
  .channel-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Divider moves from the side to between rows. */
  .channel-grid > li + li {
    border-left: 0;
    border-top: 1px solid var(--gray-800);
  }
}

/* An outlined button has no red fill behind its label, so the blanket
   light-mode .btn rule above would leave it white-on-white. Give the
   outline variant its own ink, and keep it white once the hover fills
   the button red. */
html[data-theme="light"] .btn-outline {
  color: var(--red-bright);
}

html[data-theme="light"] .btn-outline:hover {
  color: #ffffff;
}

/* ============================================================
   CHECKOUT PAGE
   Form on the left, order summary pinned to the right on wide
   screens so the total stays visible while people fill the form
   in. Under 900px the summary drops below the form and stops
   sticking, since there is no room for two columns.
   ============================================================ */
.checkout-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 3rem;
  align-items: start;
}

.checkout-empty .btn {
  display: inline-block;
}

.checkout-group + .checkout-group {
  margin-top: 2.5rem;
}

.checkout-group .contact-label {
  margin-bottom: 1.1rem;
}

.checkout-group input,
.checkout-group textarea {
  width: 100%;
  margin-bottom: 1rem;
}

.checkout-notes-label {
  margin-bottom: 0.6rem;
}

.checkout-optional {
  color: var(--gray-600);
  letter-spacing: 1px;
}

.checkout-group textarea {
  resize: vertical;
  min-height: 7rem;
  font-family: var(--font-body);
}

.checkout-hint {
  color: var(--gray-600);
  font-size: 0.78rem;
  margin: -0.4rem 0 0;
}

.checkout-choice {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-transform: none;
  letter-spacing: 0;
  font-size: 0.95rem;
  color: var(--white);
  margin-bottom: 0.7rem;
  cursor: pointer;
}

.checkout-choice input {
  width: auto;
  margin: 0;
  accent-color: var(--red);
}

.checkout-submit {
  margin-top: 2rem;
}

/* ---------- Order summary ---------- */
.order-summary {
  position: sticky;
  top: 6rem;
  padding: 1.5rem;
  border: 1px solid var(--gray-800);
  background: var(--charcoal);
}

.order-summary .contact-label {
  margin-bottom: 1.25rem;
}

.summary-lines {
  list-style: none;
}

.summary-line {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.85rem 0;
}

.summary-line + .summary-line {
  border-top: 1px solid var(--gray-800);
}

.summary-thumb {
  flex: none;
  width: 3rem;
  height: 3.75rem;
  display: grid;
  place-items: center;
  background: linear-gradient(160deg, var(--gray-800), var(--charcoal));
  color: var(--gray-600);
  font-size: 0.65rem;
}

.summary-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.summary-info {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

.summary-name {
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
}

.summary-meta {
  font-size: 0.75rem;
  color: var(--gray-400);
}

.summary-price {
  margin-left: auto;
  flex: none;
  font-size: 0.85rem;
  color: var(--white);
}

.summary-total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 1.25rem 0 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--gray-800);
  font-family: var(--font-display);
  letter-spacing: 1px;
  text-transform: uppercase;
  font-size: 0.85rem;
}

#summary-total {
  color: var(--red-bright);
  font-size: 1.05rem;
}

.checkout-back {
  display: inline-block;
  margin-top: 1.25rem;
  font-size: 0.78rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--gray-400);
}

.checkout-back:hover {
  color: var(--red-bright);
}

@media (max-width: 900px) {
  .checkout-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Sticky is pointless once the summary sits under a full-height form. */
  .order-summary {
    position: static;
  }
}

/* ============================================================
   FOOTER SOCIALS - icon + label rows in the "Stalk Us" column.
   Feather-style stroke icons matching the contact channels, so the
   footer reads as the same family. Icons inherit the link color
   (gray at rest, white on hover) with a red flare on hover.
   ============================================================ */
.social-links a {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}

.social-links svg {
  width: 15px;
  height: 15px;
  flex: none;
  stroke: currentColor;
  transition: color 0.2s, transform 0.2s;
}

.social-links a:hover svg {
  color: var(--red-bright);
}

@media (prefers-reduced-motion: no-preference) {
  .social-links a:hover svg {
    transform: translateY(-1px);
  }
}

/* Drawer "View Cart" link: quiet text button under Checkout that
   opens the full-page cart. Full-width like Continue Shopping, but
   borderless so the hierarchy stays Checkout > Continue > View. */
.cart-view-full {
  display: block;
  width: 100%;
  margin-top: 0.55rem;
  text-align: center;
  font-size: 0.75rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--gray-400);
  padding: 0.4rem 0;
}

.cart-view-full:hover {
  color: var(--red-bright);
}

/* ============================================================
   CART PAGE - maximized cart following the checkout furniture:
   line rows in a charcoal panel on the left, sticky order summary
   on the right, stacking under 900px. Qty steppers reuse the
   product-page control at a smaller size; remove reuses the drawer
   trash treatment.
   ============================================================ */
.cart-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;
  gap: 2.5rem;
  align-items: start;
  /* Wider than the site-standard 1200px container: the screenshot showed
     dead gutters on both sides while the line card stayed cramped. */
  max-width: 1400px;
  width: calc(100% - 2rem);
}

.cart-panel {
  background: var(--charcoal);
  border: 1px solid var(--gray-800);
  padding: 2rem 2.25rem;
}

.cart-page-empty {
  text-align: center;
  padding: 1rem 0;
}

.cart-page-empty p {
  color: var(--gray-400);
  margin-bottom: 1.5rem;
}

.cart-line {
  display: flex;
  gap: 1.5rem;
  align-items: flex-start;
  padding: 1.5rem 0;
}

.cart-line + .cart-line {
  border-top: 1px solid var(--gray-800);
}

.cart-line-thumb {
  width: 112px;
  height: 136px;
  flex: none;
  background: var(--gray-800);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-size: 0.65rem;
  color: var(--gray-600);
}

.cart-line-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.cart-line-info {
  flex: 1;
  min-width: 0;
}

.cart-line-info h3 {
  font-size: 0.9rem;
  letter-spacing: 2px;
  text-transform: uppercase;
}

.cart-line-meta {
  color: var(--gray-400);
  font-size: 0.8rem;
  margin: 0.2rem 0 0.7rem;
}

.cart-line-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.7rem 1rem;
}

.cart-qty {
  display: inline-flex;
  align-items: stretch;
  background: var(--black);
  border: 1px solid var(--gray-600);
}

.cart-qty button {
  width: 2.2rem;
  min-height: 2.1rem;
  border: 0;
  background: transparent;
  color: var(--white);
  font-size: 1rem;
  cursor: pointer;
  line-height: 1;
}

.cart-qty button:hover:not(:disabled) {
  background: var(--red-dark);
  color: #fff;
}

.cart-qty button:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.cart-qty span {
  min-width: 2.2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-left: 1px solid var(--gray-600);
  border-right: 1px solid var(--gray-600);
  font-size: 0.9rem;
}

.cart-line-price {
  font-size: 0.9rem;
  color: var(--red-bright);
  margin-left: auto;
}

.cart-line-remove {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  background: none;
  border: 1px solid transparent;
  border-radius: 2px;
  color: var(--gray-400);
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}

.cart-line-remove svg {
  width: 15px;
  height: 15px;
}

.cart-line-remove:hover {
  color: var(--red-bright);
  border-color: var(--red);
  background: rgba(224, 23, 34, 0.1);
}

.cart-summary {
  position: sticky;
  top: 6rem;
  background: var(--charcoal);
  border: 1px solid var(--gray-800);
  padding: 2rem;
}

.cart-summary h2 {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--gray-400);
  margin: 0 0 1rem;
}

.cart-summary-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  color: var(--gray-400);
  font-size: 0.85rem;
  padding: 0.35rem 0;
}

.cart-summary-total {
  display: flex;
  justify-content: space-between;
  margin: 1rem 0 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--gray-800);
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.9rem;
}

.cart-summary-total strong {
  color: var(--red-bright);
}

.cart-summary .btn {
  width: 100%;
  text-align: center;
}

.cart-summary .cart-continue {
  margin-top: 0.7rem;
}

@media (max-width: 900px) {
  .cart-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  .cart-summary {
    position: static;
  }
}
