/* ================================================================
   JAZZ PERFUMES — boutique (two pages: carousel + product)
   layout, tint system, typography
   ================================================================ */

:root {
  --tint1: #c9a227; /* scent accent (headings, indicator) */
  --tint2: #e5c97e; /* scent light tone (env tint, bg hue) */
  --bgc1: #2b1e0e;  /* scent backdrop mid tone (page glow center) */
  --bgc2: #0d0904;  /* scent backdrop base tone (page glow edge) */
  --gold: #c9a227;
  --ink: #ece4d4;   /* cream text on dark */
  --paper: #0b0908; /* near-black base */
}

/* Registering the glow colors lets them animate between scents. */
@property --bgc1 { syntax: '<color>'; inherits: true; initial-value: #2b1e0e; }
@property --bgc2 { syntax: '<color>'; inherits: true; initial-value: #0d0904; }
:root { transition: --bgc1 0.9s ease, --bgc2 0.9s ease; }

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  overscroll-behavior: none;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  /* No double-tap zoom anywhere — rapid bottle taps must never zoom the page.
     (touch-action intersects down the ancestor chain, so this covers all UI;
     .gamme_names narrows it to pan-x, the canvas below to none.) */
  touch-action: manipulation;
}

html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }

body {
  font-family: 'Inter', system-ui, sans-serif;
  color: var(--ink);
  background-color: color-mix(in srgb, var(--tint2) 12%, var(--paper));
  transition: background-color 0.7s ease;
  overflow-x: hidden;
}

h1, h2, h3, .nav_logo, .loader_logo, .button {
  font-family: 'Marcellus', 'Times New Roman', serif;
  font-weight: 400;
  text-transform: uppercase;
  line-height: 1;
  letter-spacing: 0.04em;
}

h2 {
  font-size: clamp(2.2rem, 4.6vw, 4rem);
  color: var(--tint1);
  transition: color 0.7s ease;
  margin-bottom: 1.2rem;
}

p { line-height: 1.6; }

/* ---------- Scene backdrop (scent-colored glow behind the bottles) ---------- */

.scene_backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: radial-gradient(
    120% 85% at 50% 40%,
    color-mix(in srgb, var(--bgc1) 42%, var(--paper)),
    color-mix(in srgb, var(--bgc2) 24%, var(--paper)) 58%,
    var(--paper)
  );
}

/* Optional per-scent theme photo, layered over the glow above — set via
   --backdrop-hook / --backdrop-full / --reveal in app.js (environment.
   setColor + the render loop). `none` for scents without a photo, so these
   two layers are fully transparent and invisible for every other scent.
   Two stacked pseudo-elements (not one swapped background-image) so the
   crossfade between the hook crop and the full photo is a plain opacity
   transition the browser composites cheaply every frame, instead of us
   re-drawing a canvas or juggling multiple background-image layers by hand. */
.scene_backdrop::before,
.scene_backdrop::after {
  content: '';
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
  background-position: center;
  /* `cover` so the photo wraps edge-to-edge (left side of the screen to the
     right side), not boxed into the middle. On a wide desktop viewport this
     crops a little off the top/bottom, which is fine. On a narrow/tall
     mobile viewport `cover` would instead crop LEFT/RIGHT — losing both
     flanks of the photo, which is what read as "bad cropping, out of
     frame" earlier — so mobile switches to `contain` below instead. */
  background-size: cover;
  /* Soften the photo's straight edges into the glow instead of a hard cut. */
  -webkit-mask-image: radial-gradient(120% 85% at 50% 40%, #000 0%, #000 40%, transparent 88%);
  mask-image: radial-gradient(120% 85% at 50% 40%, #000 0%, #000 40%, transparent 88%);
}
@media (max-width: 900px) {
  .scene_backdrop::before,
  .scene_backdrop::after {
    background-size: contain;
  }
}
.scene_backdrop::before {
  background-image: var(--backdrop-hook, none);
  opacity: calc(1 - var(--reveal, 0));
}
.scene_backdrop::after {
  background-image: var(--backdrop-full, none);
  opacity: var(--reveal, 0);
}

/* Luxury theme-backdrop animation (sandstorm): a WebGL canvas painted into the
   .scene_backdrop layer, masked like the photo so it reads as the space behind
   the bottles. Shown only for scents opting into `themeAnimation` (app.js fades
   it via display + the shader's uFade). Hidden by default. */
.scene_storm {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  -webkit-mask-image: radial-gradient(120% 85% at 50% 40%, #000 0%, #000 40%, transparent 88%);
  mask-image: radial-gradient(120% 85% at 50% 40%, #000 0%, #000 40%, transparent 88%);
  pointer-events: none;
}
@media (max-width: 900px) {
  .scene_storm { background-size: contain; }
}

/* ---------- WebGL layer ---------- */

main {
  position: fixed;
  inset: 0;
  z-index: 1;
  /* Every gesture on the 3D scene is custom (spin, tap, drag) — give the
     browser nothing: no native panning, no rubber-band, no zoom. */
  touch-action: none;
}
main canvas { display: block; width: 100% !important; height: 100% !important; }

/* ---------- Content sections ---------- */

.content { position: relative; z-index: 2; pointer-events: none; }

.section {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1.5rem, 5vw, 5rem);
  pointer-events: none; /* let drags fall through to the WebGL canvas */
}

.section a, .section button, .section details, .section summary,
.section input, .section form {
  pointer-events: auto;
}

/* ---------- Nav ---------- */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.2rem clamp(1.2rem, 4vw, 3rem);
  pointer-events: none;
}
.nav a { pointer-events: auto; }

.nav_logo {
  font-size: 1.5rem;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: 0.12em;
  display: flex;
  flex-direction: column;
  line-height: 1;
}
.nav_sub {
  font-size: 0.52rem;
  letter-spacing: 0.52em;
  text-transform: uppercase;
  color: var(--gold);
  margin-top: 0.25rem;
}

.nav_links { display: flex; gap: 2rem; }
.nav_links a {
  color: var(--ink);
  text-decoration: none;
  font-weight: 500;
  font-size: 0.9rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.nav_links a:hover { color: var(--gold); }

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--gold);
  color: #14100a;
  border: 0;
  border-radius: 999px;
  padding: 0.8rem 1.6rem;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-decoration: none;
  cursor: pointer;
}

/* ---------- Search (top right) ---------- */

.nav_right {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  pointer-events: auto;
}

.nav_search { position: relative; }

.search_input {
  font: inherit;
  font-size: 0.82rem;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid color-mix(in srgb, var(--ink) 28%, transparent);
  border-radius: 999px;
  padding: 0.55rem 1.1rem;
  width: clamp(11rem, 16vw, 16rem);
  transition: border-color 0.25s ease, background 0.25s ease;
}
.search_input::placeholder { color: color-mix(in srgb, var(--ink) 45%, transparent); }
.search_input:focus {
  outline: none;
  border-color: var(--gold);
  background: rgba(0, 0, 0, 0.55);
}
.search_input::-webkit-search-cancel-button { -webkit-appearance: none; }

.search_results {
  list-style: none;
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  width: max(100%, 19rem);
  background: rgba(12, 10, 8, 0.96);
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  border-radius: 1rem;
  overflow: hidden;
  backdrop-filter: blur(8px);
}
.search_results button {
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  cursor: pointer;
  font: inherit;
  color: var(--ink);
  padding: 0.65rem 1rem;
}
.search_results button:hover { background: rgba(255, 255, 255, 0.07); }
.search_results b {
  font-family: 'Marcellus', serif;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 0.85rem;
}
.search_results span {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 0.85rem;
  color: color-mix(in srgb, var(--ink) 60%, transparent);
}

@media (max-width: 700px) {
  /* Fragrances/Shop are reachable by tapping a bottle, but Contact had no other
     way in on a phone — the whole nav_links block used to be display:none, so
     the only contact link on the site sat on the product page. Keep just
     Contact, compacted, and give the search bar back the width it costs. */
  .nav_links { display: flex; gap: 0; }
  .nav_links a:not([data-contact-open]) { display: none; }
  /* An outlined gold pill, not 0.7rem of plain text — as bare text between the
     logo and the search bar it was there but nobody registered it as a way to
     reach us. Sized so 360px still fits logo + pill + search + bag. */
  .nav_links a[data-contact-open] {
    color: var(--gold);
    border: 1px solid color-mix(in srgb, var(--gold) 55%, transparent);
    border-radius: 999px;
    padding: 0.42rem 0.75rem;
    font-size: 0.62rem;
    letter-spacing: 0.1em;
    white-space: nowrap;
  }
  .nav_cta { display: none; }
  .search_input { width: clamp(5.5rem, 24vw, 8.5rem); padding: 0.5rem 0.8rem; font-size: 0.75rem; }
}

/* ---------- Loader ---------- */

.loader {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--paper);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2rem;
}
/* The real logo lockup, replacing the old "JAZZ / Perfumes" type. The file is a
   JPEG (no alpha) on a black field, so `screen` blends that field into the
   loader's own near-black background instead of showing a square edge. */
.loader_mark {
  width: min(22rem, 68vw);
  max-height: 56svh;
  object-fit: contain;
  mix-blend-mode: screen;
}
.loader_bar {
  width: min(260px, 50vw);
  height: 2px;
  background: rgba(236, 228, 212, 0.15);
  border-radius: 2px;
  overflow: hidden;
}
.loader_bar_fill {
  width: 100%;
  height: 100%;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
}

/* ---------- Scroll indicator ---------- */

.scroll_indicator {
  --p: 0;
  position: fixed;
  left: 0; bottom: 0;
  z-index: 10;
  width: 100%;
  height: 2px;
  background: var(--tint1);
  transform: scaleX(var(--p));
  transform-origin: left;
  transition: background-color 0.7s ease;
}

/* ---------- 0 · Hero ---------- */

.is-gamme {
  flex-direction: column;
  justify-content: space-between;
  /* clear the fixed nav so the bottom-right scent panel never rides into it */
  padding-top: clamp(6rem, 12vh, 9rem);
  padding-bottom: 2.2rem;
  text-align: center;
}

.gamme_topline {
  color: var(--ink);
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  letter-spacing: 0.06em;
  font-size: 1.15rem;
}

/* Scent details — bottom-right panel, clear of the bottles */
.gamme_side {
  text-align: right;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
  max-width: 20rem;
  flex-shrink: 0;
}

.gamme_side_index {
  font-size: 0.72rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold);
}
.gamme_side_num { color: var(--ink); }

.gamme_inspired {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 0.95rem;
  color: color-mix(in srgb, var(--ink) 62%, transparent);
}

.gamme_flavor_mask {
  overflow: hidden;
}
.gamme_flavor {
  display: inline-block;
  font-family: 'Marcellus', 'Times New Roman', serif;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: clamp(1.3rem, 2.4vw, 2rem);
  color: var(--ink);
  white-space: nowrap;
}

.gamme_notes {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 1.05rem;
  color: color-mix(in srgb, var(--ink) 75%, transparent);
}

.gamme_arrows {
  display: flex;
  gap: 0.7rem;
  margin-top: 0.4rem;
}

.gamme_arrow {
  pointer-events: auto;
  background: transparent;
  border: 1.5px solid color-mix(in srgb, var(--ink) 65%, transparent);
  border-radius: 999px;
  width: 3rem; height: 3rem;
  font-size: 1.1rem;
  cursor: pointer;
  color: var(--ink);
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.gamme_arrow:hover {
  background: var(--gold);
  border-color: var(--gold);
  color: #14100a;
}

/* Bottom shelf: catalogue pills on the left, scent panel bottom-right */
.gamme_bottom {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(1.5rem, 4vw, 4rem);
  width: 100%;
  text-align: left;
}

.gamme_bottom_left {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.7rem;
  min-width: 0;
}

.gamme_names {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 0.28rem 0.3rem;
  max-width: 58rem;
  /* ponytail: cap height so the hero bottom block can't grow tall enough
     (on short windows) to ride up into the fixed nav under space-between */
  max-height: 6.5rem;
  overflow-y: auto;
  scrollbar-width: thin;
  /* The section's pointer-events:none only re-enables the BUTTONS — the list
     itself must take pointer events too, or its scrollbar can't be grabbed
     (and wheel events over it target the window, i.e. the turntable). */
  pointer-events: auto;
  /* Reaching the list's end must not scroll-chain into the page itself. */
  overscroll-behavior: contain;
}

.gamme_name {
  pointer-events: auto;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--ink) 22%, transparent);
  border-radius: 999px;
  color: color-mix(in srgb, var(--ink) 72%, transparent);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.32rem 0.7rem;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.25s ease, border-color 0.25s ease, background 0.25s ease;
}
.gamme_name:hover {
  color: var(--ink);
  border-color: color-mix(in srgb, var(--ink) 55%, transparent);
}
.gamme_name.is-active {
  background: var(--tint1);
  border-color: var(--tint1);
  color: #14100a;
}

.gamme_footnote {
  color: var(--ink);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  opacity: 0.55;
}

/* Stacking the shelf costs a whole extra row of height, which only exists in
   portrait — see the SHORT VIEWPORT note at the bottom of this file. */
@media (max-width: 900px) and (min-height: 541px) {
  .gamme_bottom {
    flex-direction: column-reverse;
    align-items: center;
    gap: 0.8rem;
  }
  .gamme_bottom_left { align-items: center; width: 100%; }
  .gamme_side {
    align-items: center;
    text-align: center;
    gap: 0.4rem;
  }
}

/* Short viewports get the swipe row too: the desktop list WRAPS into a
   6.5rem-tall block of pills, which is a quarter of a landscape phone's
   screen. One row + a sideways flick costs a fifth of that. */
@media (max-width: 900px), (max-height: 540px) {
  /* One swipeable row — every name reachable with a sideways flick. */
  .gamme_names {
    flex-wrap: nowrap;
    justify-content: flex-start;
    width: 100%;
    max-width: none;
    overflow-x: auto;
    padding-bottom: 0.35rem;
    pointer-events: auto;
    touch-action: pan-x;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .gamme_names::-webkit-scrollbar { display: none; }
  .gamme_names li { flex-shrink: 0; }
  .gamme_footnote { font-size: 0.62rem; text-align: center; }
}

/* ---------- 1 · Product page ---------- */

.is-profile {
  /* MUST fill a full viewport. The document is exactly two screens tall and
     this section is the scroll destination — when it was `min-content`, on
     tall windows the section came out SHORTER than the viewport, so
     max-scroll landed short of the section top and the site was stranded
     mid-transition (hero shelf stuck over the nav, side bottles half sunk).
     The old worry (content overrunning 100svh on SHORT windows and pushing
     "← All fragrances" below the fold) is handled by the max-height media
     query below, which compacts the layout instead of shrinking the section. */
  min-height: 100vh;
  min-height: 100svh;
  padding-top: 5rem;
  padding-bottom: 2rem;
  align-items: center;
}
.is-profile .product_layout { align-items: flex-start; }

/* Desktop: keep the whole product page (story + shop + back link) inside one
   viewport so no scroll is needed. Long names (19 chars) + long descs (94 chars)
   are allowed to wrap instead of forcing height.
   A SHORT viewport (a phone in landscape) gets these row rules too: it has the
   width for a row and none of the height for the phone column stack. */
@media (min-width: 901px), (max-height: 540px) {
  .is-profile { padding-top: 4.5rem; padding-bottom: 1.5rem; }
  .product_layout {
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.5rem 2.5rem;
    max-width: 70rem;
  }
  .product_info { max-width: 30rem; }
  .product_dyn { gap: 0.5rem; }
  .product_desc { max-width: 26rem; }
}

/* Short desktop windows: compact the product page so everything (down to
   "← All fragrances") fits inside the one hard viewport — the section itself
   must stay 100svh tall (see .is-profile above), so the CONTENT shrinks. */
@media (min-width: 901px) and (max-height: 820px), (max-height: 540px) {
  .is-profile { padding-top: 4rem; padding-bottom: 1rem; }
  .product_info h2 { font-size: clamp(1.6rem, 3.4vw, 2.6rem); }
  .product_dyn { gap: 0.4rem; }
  .product_photo { aspect-ratio: var(--photo-ratio, 4 / 3); }
  .product_shop { width: clamp(13rem, 18vw, 16rem); gap: 0.6rem; }
  .product_price { font-size: 1.3rem; }
  .product_buy { padding: 0.75rem 1.2rem; }
}

.product_layout {
  width: 100%;
  max-width: 90rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
}

/* Left — the story */
.product_info {
  max-width: 24rem;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.product_kicker {
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold);
}
.product_num { color: var(--ink); }

.product_inspired {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 1rem;
  color: color-mix(in srgb, var(--ink) 62%, transparent);
}

.product_name {
  font-family: 'Marcellus', 'Times New Roman', serif;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: clamp(1.5rem, 2.6vw, 2.3rem);
  line-height: 1.15;
  color: var(--ink);
}

.product_notes {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 1.1rem;
  color: color-mix(in srgb, var(--ink) 75%, transparent);
}

.product_desc {
  font-size: 0.95rem;
  color: color-mix(in srgb, var(--ink) 82%, transparent);
  max-width: 22rem;
}

.product_dyn {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.product_back {
  margin-top: 0.5rem;
  color: var(--ink);
  text-decoration: none;
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.7;
  transition: opacity 0.25s ease, color 0.25s ease;
  align-self: flex-start;
}
.product_back:hover { opacity: 1; color: var(--gold); }

/* "← All fragrances" and "Reviews ↓" share one line — on phones the bottom
   stack's height is budgeted to the svh and has no room for a second row. */
.product_footlinks { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.product_reviews { color: var(--gold); opacity: 0.85; }

/* Product-page prev/next arrows — same pill buttons as the hero */
.product_arrows {
  display: flex;
  gap: 0.7rem;
  margin-top: 0.9rem;
}
/* Reuse .gamme_arrow visuals; just size the product ones a touch smaller */
.product_arrow {
  width: 2.6rem; height: 2.6rem;
  font-size: 1rem;
}

/* Right — the shop */
.product_shop {
  width: clamp(15rem, 21vw, 19rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  text-align: center;
}

.product_photo {
  position: relative;
  width: 100%;
  /* Overwritten per scent by ui.js with the photo's own ratio (clamped so a very
     tall poster can't push the buy button off a short screen). 4/5 is the
     fallback for the placeholder state before any image has loaded. */
  aspect-ratio: var(--photo-ratio, 4 / 5);
  border: 1px solid color-mix(in srgb, var(--ink) 25%, transparent);
  border-radius: 1rem;
  overflow: hidden;
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  backdrop-filter: blur(4px);
  pointer-events: auto;
}
.product_img {
  width: 100%;
  height: 100%;
  /* cover is safe here ONLY because .product_photo's aspect-ratio is set to this
     image's own ratio by ui.js (--photo-ratio). Box and image agree, so cover
     fills it edge to edge and crops nothing. The posters arrive in three shapes
     (0.67 tall, 0.8, 1.33 wide) with the scent name set in type — a fixed box
     either sliced the headline off (cover) or left dead bars (contain). */
  object-fit: cover;
  display: block;
  cursor: zoom-in;
}
.product_photo_hint {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
}
.product_photo.is-missing .product_img { visibility: hidden; }
.product_photo.is-missing .product_photo_hint { display: flex; }
.product_photo_hint_title {
  font-family: 'Marcellus', serif;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  font-size: 0.85rem;
  color: color-mix(in srgb, var(--ink) 75%, transparent);
}
.product_photo_hint_sub {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 0.95rem;
  color: color-mix(in srgb, var(--ink) 55%, transparent);
}

.image_viewer {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(5, 4, 3, 0.92);
  backdrop-filter: blur(8px);
  cursor: zoom-out;
  touch-action: none;
  overscroll-behavior: contain;
}
.image_viewer[hidden] { display: none; }
.image_viewer_img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 0.7rem;
  box-shadow: 0 1.5rem 5rem rgba(0, 0, 0, 0.6);
  cursor: default;
}
.image_viewer_close {
  position: fixed;
  top: max(1rem, env(safe-area-inset-top));
  right: max(1rem, env(safe-area-inset-right));
  z-index: 1;
  width: 2.8rem;
  height: 2.8rem;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-size: 1.8rem;
  line-height: 1;
  cursor: pointer;
}

.product_shape_toggle {
  display: inline-flex;
  padding: 0.2rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--ink) 25%, transparent);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}
.shape_btn {
  font: inherit;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  cursor: pointer;
  border: none;
  border-radius: 999px;
  padding: 0.4rem 0.85rem;
  background: transparent;
  color: color-mix(in srgb, var(--ink) 70%, transparent);
  transition: background 0.2s ease, color 0.2s ease;
}
.shape_btn:hover { color: var(--ink); }
.shape_btn.is-active {
  background: var(--gold);
  color: #14100a;
  font-weight: 600;
}

.product_price {
  font-family: 'Marcellus', serif;
  font-size: 1.6rem;
  letter-spacing: 0.06em;
  color: var(--ink);
}
.product_size {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 1.05rem;
  color: color-mix(in srgb, var(--ink) 60%, transparent);
}

.product_buy {
  width: 100%;
  padding: 1rem 1.6rem;
  font-size: 0.9rem;
  transition: background 0.25s ease, transform 0.15s ease;
}
.product_buy:hover { transform: translateY(-1px); }
.product_buy.is-added { background: #86b07a; }

.product_ship {
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.55;
}

/* min-height gate: this whole block budgets the bottle the top ~55% of the
   screen and the text stack the bottom ~45%. That split only survives in
   PORTRAIT — see the SHORT VIEWPORT block at the bottom of this file. */
@media (max-width: 900px) and (min-height: 541px) {
  /* Bottle owns the top of the screen; the text stack is bottom-anchored and
     the section is HARD-CAPPED at one viewport — no perfume, however long its
     name or notes, can push "← All fragrances" below the fold (native
     scrolling is disabled on phones, so anything below the fold is lost). */
  .is-profile {
    height: 100svh;
    min-height: 100svh;
    justify-content: flex-end;
    padding-top: 0;
    padding-bottom: max(0.9rem, env(safe-area-inset-bottom));
    align-items: stretch;
    overflow: hidden;
    position: relative;   /* containing block for .product_arrows below */
  }
  /* Center the column — the desktop rule left it flex-start, which parked the
     photo/price/buy stack off-center to the left of the centered text. */
  .is-profile .product_layout { align-items: center; }
  .product_layout {
    flex-direction: column;
    justify-content: flex-end;
    height: 100%;
    /* Every gap/size below is a clamp() tied to svh, not a fixed rem: on a
       short viewport (small phone, or a phone rotated to landscape — still
       under the 900px breakpoint) everything scales down together instead of
       overflowing and getting clipped by .is-profile's overflow:hidden. */
    gap: clamp(0.4rem, 2svh, 0.8rem);
    padding-top: 0;
  }
  .product_info { max-width: 100%; text-align: center; align-items: center; gap: clamp(0.15rem, 1svh, 0.35rem); }
  .product_info h2 { display: none; } /* the bottle is the hero on phones */
  .product_dyn { gap: clamp(0.15rem, 1svh, 0.35rem); }
  .product_desc { display: none; } /* keep the phone screen breathable */
  .product_back { align-self: center; margin-top: 0.1rem; flex-shrink: 0; font-size: 0.72rem; }
  .product_kicker { font-size: 0.6rem; letter-spacing: 0.22em; }
  /* Longer fragrance names / "inspired by" lines / notes must never grow the
     text stack past what's above product_back — that pushes "← All
     fragrances" out of the hard-capped, non-scrolling viewport (see the
     .is-profile note above). Clamping each line count keeps every scent's
     block the same bounded height regardless of copy length. */
  .product_name {
    font-size: clamp(1.05rem, 4.6svh, 1.4rem); line-height: 1.1; max-width: 92vw;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .product_inspired {
    font-size: clamp(0.68rem, 2.6svh, 0.82rem);
    display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
  }
  .product_notes {
    font-size: clamp(0.72rem, 2.8svh, 0.88rem);
    display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
  }
  /* Paging arrows. These were hidden on phones on the grounds that swiping the
     bottle already pages the scent — but the swipe is invisible, so there was
     nothing on screen telling anyone they could move. They are pulled OUT of the
     bottom stack (whose height is budgeted to the svh and has no room) and hung
     beside the bottle instead, which is where the thumb already is.
     The strip itself is pointer-events:none so it cannot eat a swipe that
     starts between the two buttons. */
  .product_arrows {
    display: flex;
    justify-content: space-between;
    position: absolute;
    left: 0;
    right: 0;
    top: 34%;
    margin: 0;
    padding: 0 max(0.55rem, env(safe-area-inset-left));
    pointer-events: none;
    z-index: 6;
  }
  .product_arrow {
    pointer-events: auto;
    width: 2.9rem;
    height: 2.9rem;
    font-size: 1.15rem;
    background: rgba(10, 8, 6, 0.42);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  .product_shop { width: min(62vw, 14rem); gap: clamp(0.3rem, 1.6svh, 0.5rem); }
  /* No real product photos exist yet (every bottle is "coming soon"), so this
     placeholder box IS the photo slot for every scent on mobile — it was
     previously hidden entirely via `.is-missing { display: none }`, which
     made the shop panel look broken/incomplete. Kept small so it doesn't
     crowd the rest of the shop stack. */
  .product_photo {
    /* Phones drive off HEIGHT, so the per-scent ratio changes the box's width
       instead — the vertical budget of this hard-capped 100svh section is
       untouched no matter which poster loads. */
    width: auto;
    height: clamp(3.6rem, 10svh, 6rem);
    aspect-ratio: var(--photo-ratio, 4 / 3);
    align-self: center;
    border-radius: 0.6rem;
  }
  .product_photo_hint_title { font-size: 0.6rem; }
  .product_photo_hint_sub { font-size: 0.68rem; }
  .product_price { font-size: clamp(0.85rem, 3.4svh, 1.05rem); }
  .shape_btn { font-size: 0.58rem; padding: 0.3rem 0.6rem; }
  .product_buy { padding: 0.6rem 1rem; width: 100%; font-size: 0.8rem; }
  .product_ship { font-size: 0.58rem; }
  .product_contact { font-size: 0.62rem; flex-shrink: 0; }
}

/* ---------- 2 · Reviews page ---------- */

/* Same hard 100svh contract as the product page: this is a scroll destination,
   so a short section would strand max-scroll before its top. The bottle stays
   centered behind it (the timeline is already at its end here), so the content
   lives in one translucent card that reads over the glass. */
.is-reviews {
  min-height: 100vh;
  min-height: 100svh;
  padding-top: 5rem;
  padding-bottom: 2rem;
  align-items: center;
}

/* Same box as the contact popup (.contact_card) — near-opaque brown, cream
   hairline border, 1.25rem radius. It was translucent + blurred and read as a
   different component from every other panel on the site. */
.reviews_card {
  pointer-events: auto;
  width: min(40rem, 100%);
  max-height: min(76svh, 40rem);
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: clamp(1.6rem, 4vw, 2.4rem);
  border-radius: 1.25rem;
  text-align: left;
  background: rgba(14, 11, 9, 0.97);
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
}

.reviews_kicker {
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold);
}
/* Fixed gold like .contact_title — the h2 default is var(--tint1), which
   swings with the scent and turned the heading blue on the cool perfumes. */
.reviews_title {
  font-family: 'Marcellus', 'Times New Roman', serif;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: clamp(1.4rem, 3vw, 1.8rem);
  line-height: 1.15;
  color: var(--gold);
  margin-bottom: 0;
}
.reviews_score {
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  opacity: 0.75;
}
.reviews_score[hidden], .reviews_empty[hidden] { display: none; }

/* The only scrollable thing on the page — hence .reviews_list appearing in the
   wheel/touch exemption lists in app.js, so scrolling reviews doesn't page. */
.reviews_list:empty { display: none; }
.reviews_list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
.review {
  border-top: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
  padding-top: 0.8rem;
}
.review_head { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.review_stars { color: var(--gold); letter-spacing: 0.08em; }
.review_head b {
  font-family: 'Marcellus', serif;
  font-weight: 400;
  letter-spacing: 0.06em;
  font-size: 0.9rem;
}
.review_date { font-size: 0.72rem; opacity: 0.55; }
.review_text {
  margin-top: 0.3rem;
  font-size: 0.92rem;
  color: color-mix(in srgb, var(--ink) 82%, transparent);
}

.reviews_empty {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 1.05rem;
  color: color-mix(in srgb, var(--ink) 70%, transparent);
}

.reviews_actions { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; margin-top: 0.3rem; }
.reviews_back { margin-top: 0; align-self: auto; }

.reviews_demo {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #e0b25a;
  border: 1px dashed color-mix(in srgb, #e0b25a 45%, transparent);
  border-radius: 0.5rem;
  padding: 0.4rem 0.7rem;
  align-self: flex-start;
}
.reviews_demo[hidden] { display: none; }

/* ---- Write a review (Netlify Forms; posted by fetch in js/reviews.js) ---- */

/* The form REPLACES the list inside the card instead of sitting below it — the
   card is capped to one viewport and on a phone both together overflow it. */
.reviews_form { display: none; flex-direction: column; gap: 0.7rem; }
.reviews_card.is-writing .reviews_form { display: flex; }
.reviews_card.is-writing .reviews_list,
.reviews_card.is-writing .reviews_empty,
.reviews_card.is-writing .reviews_score,
.reviews_card.is-writing .reviews_demo,
.reviews_card.is-writing .reviews_actions { display: none; }

.reviews_hp { display: none; }

.reviews_form label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ink) 65%, transparent);
}
.reviews_form input,
.reviews_form select,
.reviews_form textarea {
  font: inherit;
  font-size: 0.9rem;
  letter-spacing: normal;
  text-transform: none;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid color-mix(in srgb, var(--ink) 24%, transparent);
  border-radius: 0.6rem;
  padding: 0.55rem 0.75rem;
  width: 100%;
  resize: vertical;
}
.reviews_form select option { background: #14100a; color: #f4ece0; }
.reviews_form input:focus,
.reviews_form select:focus,
.reviews_form textarea:focus { outline: none; border-color: var(--gold); }

.reviews_form_row { display: flex; gap: 0.7rem; }
.reviews_form_row label:first-child { flex: 1 1 auto; }
.reviews_form_row label:last-child { flex: 0 0 8rem; }

.reviews_form_foot { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.reviews_cancel {
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  margin-top: 0;
  align-self: auto;
}
.reviews_submit[disabled] { opacity: 0.6; cursor: default; }

.reviews_form_msg {
  font-size: 0.85rem;
  color: color-mix(in srgb, var(--ink) 80%, transparent);
}
.reviews_form_msg.is-error { color: #e2896b; }
.reviews_form_msg[hidden] { display: none; }

@media (max-width: 900px) {
  .reviews_form_row { flex-direction: column; }
  .reviews_form_row label:last-child { flex: 1 1 auto; }
}

@media (max-width: 900px) {
  .is-reviews {
    height: 100svh;
    overflow: hidden;
    padding-top: 4.5rem;
    padding-bottom: max(0.9rem, env(safe-area-inset-bottom));
  }
  .reviews_card { max-height: calc(100svh - 6.5rem); }
  .reviews_actions { justify-content: center; }
  .review_text { font-size: 0.85rem; }
}

/* ---------- legal.html (privacy / terms / trademarks) ----------
   A plain scrolling document, deliberately nothing like the WebGL pager: it
   has to be readable, printable and linkable, and none of the fixed-viewport
   machinery on the shop page suits that. */

.legal_body {
  background: var(--paper);
  /* Both of these UNDO shop-page globals, and both are load-bearing.
     `html, body { overflow-x: hidden }` makes BODY a scroll container — a
     non-visible value on one axis forces the other to `auto` — and this page's
     body fits its content exactly, so that container can never scroll. Then
     `overscroll-behavior: none` stops the gesture chaining up to HTML, which is
     the element that DOES scroll. Net effect: the page was completely frozen to
     wheel and touch while `html.scrollTop = n` still worked, which is the tell.
     A plain document needs neither rule. */
  overflow: visible;
  overscroll-behavior: auto;
}

.legal_head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.4rem clamp(1.2rem, 5vw, 3rem);
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
}
.legal_logo {
  font-family: 'Marcellus', serif;
  font-size: 1.4rem;
  letter-spacing: 0.12em;
  color: var(--ink);
  text-decoration: none;
  display: flex;
  flex-direction: column;
  line-height: 1;
}
.legal_logo_sub {
  font-size: 0.5rem;
  letter-spacing: 0.5em;
  text-transform: uppercase;
  color: var(--gold);
  margin-top: 0.25rem;
}
.legal_nav { display: flex; flex-wrap: wrap; gap: 0.4rem 1.4rem; }
.legal_nav a {
  color: color-mix(in srgb, var(--ink) 72%, transparent);
  text-decoration: none;
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.legal_nav a:hover { color: var(--gold); }

/* `main` is the fixed, full-viewport WebGL layer on the shop page — a <main>
   here inherits `position: fixed; inset: 0` and lands on top of the header.
   Undo all of it; this page is an ordinary document. */
.legal {
  position: static;
  inset: auto;
  z-index: auto;
  touch-action: auto;
  max-width: 46rem;
  margin: 0 auto;
  padding: clamp(2rem, 6vw, 4rem) clamp(1.2rem, 5vw, 3rem) 5rem;
  color: color-mix(in srgb, var(--ink) 88%, transparent);
}
.legal_updated {
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.5;
  margin-bottom: 2.5rem;
}
.legal_section { margin-bottom: 4rem; scroll-margin-top: 1.5rem; }
.legal h1 {
  font-family: 'Marcellus', serif;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: clamp(1.5rem, 4vw, 2.2rem);
  line-height: 1.2;
  color: var(--gold);
  margin-bottom: 1.4rem;
}
.legal h2 {
  font-family: 'Marcellus', serif;
  font-weight: 400;
  font-size: clamp(1rem, 2.4vw, 1.2rem);
  letter-spacing: 0.06em;
  text-transform: none;
  color: var(--ink);
  margin: 2.2rem 0 0.7rem;
}
.legal p { margin-bottom: 1rem; font-size: 0.95rem; line-height: 1.75; }
.legal ul { margin: 0 0 1.2rem 1.1rem; }
.legal li { margin-bottom: 0.55rem; font-size: 0.95rem; line-height: 1.7; }
.legal a { color: var(--gold); text-underline-offset: 3px; }
.legal strong { color: var(--ink); font-weight: 600; }

.legal_callout {
  border-left: 3px solid var(--gold);
  background: rgba(255, 255, 255, 0.035);
  padding: 1.1rem 1.3rem;
  border-radius: 0 0.6rem 0.6rem 0;
}
.legal_brands { font-size: 0.85rem; opacity: 0.75; }

/* Wide tables must scroll inside themselves — the page must never scroll
   sideways on a phone. */
.legal_table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.5rem 0 1.5rem;
  font-size: 0.88rem;
  display: block;
  overflow-x: auto;
}
.legal_table th, .legal_table td {
  border: 1px solid color-mix(in srgb, var(--ink) 15%, transparent);
  padding: 0.6rem 0.75rem;
  text-align: left;
  vertical-align: top;
  min-width: 9rem;
}
.legal_table th {
  color: var(--gold);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.legal_foot {
  border-top: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
  padding-top: 1.5rem;
  font-size: 0.85rem;
  opacity: 0.72;
}
.legal_foot p { margin-bottom: 0.4rem; }

/* Phones: a three-column table is unreadable in 428px, and sideways-scrolling
   a privacy policy is worse. Each row becomes its own labelled block. */
@media (max-width: 620px) {
  .legal_table, .legal_table tbody, .legal_table tr, .legal_table td { display: block; width: 100%; }
  .legal_table thead { display: none; }
  .legal_table tr {
    border: 1px solid color-mix(in srgb, var(--ink) 15%, transparent);
    border-radius: 0.6rem;
    padding: 0.4rem 0.2rem;
    margin-bottom: 0.9rem;
  }
  .legal_table td { border: 0; min-width: 0; padding: 0.35rem 0.75rem; }
  .legal_table td::before {
    content: attr(data-label);
    display: block;
    font-size: 0.62rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gold);
    margin-bottom: 0.15rem;
  }
}

/* ---------- SplitText masks ---------- */

[data-anim] .line { will-change: transform; }

/* ---------- Button char-roll ---------- */

.button .button_text { overflow: hidden; display: inline-flex; position: relative; }
.button .layer-bottom { position: absolute; top: 0; left: 0; }

/* ---------- Contact overlay (details filled from js/ui.js CONTACT) ---------- */

.product_contact {
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.7;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.product_contact:hover { color: var(--gold); opacity: 1; }

.contact_overlay {
  position: fixed;
  inset: 0;
  z-index: 40; /* above nav (10), below the loader (50) */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.contact_overlay[hidden] { display: none; }

.contact_backdrop {
  position: absolute;
  inset: 0;
  background: rgba(8, 6, 4, 0.72);
  backdrop-filter: blur(6px);
}

.contact_card {
  position: relative;
  width: min(26rem, 92vw);
  background: rgba(14, 11, 9, 0.97);
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  border-radius: 1.25rem;
  padding: clamp(1.6rem, 4vw, 2.4rem);
  text-align: center;
}

.contact_close {
  position: absolute;
  top: 0.8rem;
  right: 0.95rem;
  background: transparent;
  border: 0;
  color: var(--ink);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.6;
}
.contact_close:hover { opacity: 1; color: var(--gold); }

.contact_title {
  font-size: clamp(1.4rem, 3vw, 1.8rem);
  color: var(--gold);
  margin-bottom: 0.3rem;
}

.contact_tagline {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 1rem;
  color: color-mix(in srgb, var(--ink) 65%, transparent);
  margin-bottom: 1.4rem;
}

.contact_list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  text-align: left;
}
.contact_list li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}
.contact_list li:last-child { border-bottom: 0; padding-bottom: 0; }

.contact_label {
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.55;
  white-space: nowrap;
}

.contact_value { font-size: 0.92rem; }
.contact_value a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.contact_value a:hover { color: var(--gold); }
/* Trademark disclaimer + policy links. They live in the contact panel because
   it is reachable from every page on both layouts and has no height budget to
   blow — unlike the two 100svh sections. */
.contact_legal_note {
  margin-top: 1.4rem;
  padding-top: 1.1rem;
  border-top: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
  font-size: 0.72rem;
  line-height: 1.6;
  text-align: left;
  color: color-mix(in srgb, var(--ink) 55%, transparent);
}
.contact_legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  margin-top: 0.7rem;
}
.contact_legal a {
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  text-decoration: none;
  opacity: 0.85;
}
.contact_legal a:hover { opacity: 1; text-decoration: underline; }

.gamme_footnote a { color: inherit; text-underline-offset: 2px; }

.contact_value.is-pending {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: color-mix(in srgb, var(--ink) 45%, transparent);
}

/* ---------- Bag button + bag/checkout overlay (js/cart.js) ---------- */

.cart_btn {
  position: relative;
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.6rem;
  height: 2.6rem;
  padding: 0;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--ink) 28%, transparent);
  background: rgba(255, 255, 255, 0.07);
  color: var(--ink);
  cursor: pointer;
  transition: border-color 0.25s ease, color 0.25s ease;
}
.cart_btn:hover { border-color: var(--gold); color: var(--gold); }
.cart_btn svg { width: 1.25rem; height: 1.25rem; }

.cart_count {
  position: absolute;
  top: -0.25rem;
  right: -0.25rem;
  min-width: 1.15rem;
  height: 1.15rem;
  padding: 0 0.28rem;
  border-radius: 999px;
  background: var(--gold);
  color: #14100a;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1.15rem;
  text-align: center;
}
.cart_count[hidden] { display: none; }

.cart_overlay {
  position: fixed;
  inset: 0;
  z-index: 41; /* one above the contact overlay */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.cart_overlay[hidden] { display: none; }

.cart_panel {
  position: relative;
  width: min(30rem, 94vw);
  max-height: min(88svh, 46rem);
  overflow-y: auto;
  background: rgba(14, 11, 9, 0.97);
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  border-radius: 1.25rem;
  padding: clamp(1.5rem, 4vw, 2.2rem);
}
.cart_pane[hidden] { display: none; }
.cart_panel .contact_title { text-align: center; margin-bottom: 1.2rem; }

.cart_items { list-style: none; display: flex; flex-direction: column; }
.cart_item {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 0.9rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}
.cart_item_info { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.cart_item_info b {
  font-family: 'Marcellus', serif;
  font-weight: 400;
  font-size: 0.92rem;
  letter-spacing: 0.06em;
}
/* The chosen bottle shape is the one thing a shopper cannot re-check from a
   photo, so it gets the gold pill rather than the muted sub-line. */
.cart_item_shape {
  align-self: flex-start;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  border: 1px solid color-mix(in srgb, var(--gold) 45%, transparent);
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  margin: 0.1rem 0;
}
.cart_item_size {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 0.8rem;
  color: color-mix(in srgb, var(--ink) 55%, transparent);
}

.cart_qty {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  border: 1px solid color-mix(in srgb, var(--ink) 22%, transparent);
  border-radius: 999px;
  padding: 0.15rem;
}
.cart_qty button {
  width: 1.6rem;
  height: 1.6rem;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.cart_qty button:hover { background: rgba(255, 255, 255, 0.1); color: var(--gold); }
.cart_qty span { min-width: 1.1rem; text-align: center; font-size: 0.85rem; }

.cart_item_price { font-size: 0.9rem; white-space: nowrap; }

.cart_empty,
.cart_sent_lead,
.cart_pay_note {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: color-mix(in srgb, var(--ink) 60%, transparent);
  text-align: center;
}
.cart_empty { padding: 1.5rem 0; }
.cart_empty[hidden], .cart_foot[hidden] { display: none; }

.cart_foot { padding-top: 1.1rem; }
.cart_total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 0.35rem;
}
.cart_total span { font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.55; }
.cart_total b { font-family: 'Marcellus', serif; font-weight: 400; font-size: 1.35rem; }
.cart_ship_note {
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.5;
  margin-bottom: 1rem;
}
.cart_checkout, .cart_place, .cart_done { width: 100%; padding: 0.9rem 1.6rem; }
.cart_checkout:disabled { opacity: 0.6; cursor: progress; }
.cart_done { margin-top: 1.2rem; }

.cart_form { display: flex; flex-direction: column; gap: 0.8rem; }
.cart_form label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.65rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.7;
}
.cart_optional { text-transform: none; letter-spacing: 0.04em; opacity: 0.7; }
.cart_form input,
.cart_form textarea {
  font: inherit;
  font-size: 0.9rem;
  letter-spacing: normal;
  text-transform: none;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid color-mix(in srgb, var(--ink) 22%, transparent);
  border-radius: 0.6rem;
  padding: 0.6rem 0.8rem;
  resize: vertical;
}
.cart_form input:focus, .cart_form textarea:focus { outline: none; border-color: var(--gold); }

.cart_form_err {
  font-size: 0.78rem;
  color: #e08a7a;
  text-align: center;
}
.cart_form_err[hidden] { display: none; }
.cart_pay_note { font-size: 0.88rem; line-height: 1.35; }

.cart_actions { display: flex; align-items: center; gap: 0.9rem; margin-top: 0.2rem; }
.cart_back {
  flex-shrink: 0;
  background: transparent;
  border: 0;
  color: var(--ink);
  font: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
  cursor: pointer;
}
.cart_back:hover { color: var(--gold); opacity: 1; }

.cart_summary {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 0.76rem;
  line-height: 1.5;
  white-space: pre-wrap;
  color: color-mix(in srgb, var(--ink) 85%, transparent);
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
  border-radius: 0.8rem;
  padding: 0.9rem 1rem;
  margin: 1rem 0;
  max-height: 15rem;
  overflow-y: auto;
}
.cart_send { display: flex; flex-direction: column; gap: 0.6rem; }
.cart_send .button { width: 100%; }
.cart_send .button[hidden] { display: none; }
.cart_send_copy {
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--ink) 28%, transparent);
  border-radius: 999px;
  padding: 0.75rem 1.6rem;
  color: var(--ink);
  font: inherit;
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  cursor: pointer;
}
.cart_send_copy:hover { border-color: var(--gold); color: var(--gold); }
.cart_sent_note {
  margin-top: 0.9rem;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  opacity: 0.5;
}

@media (max-width: 700px) {
  .cart_item { grid-template-columns: 1fr auto; row-gap: 0.5rem; }
  .cart_item_price { grid-column: 2; text-align: right; }
  .cart_panel { padding: 1.4rem 1.1rem; }
}

/* ---------- SHORT VIEWPORT (a phone held sideways) ----------
   Every phone rule above is gated on `max-width: 900px`, which is really a
   PORTRAIT test: a phone in landscape (844x390) matches it while having less
   than half the height those rules budget for. The result was the text stack
   printed straight over the bottle and the buy button pushed off the bottom.
   A landscape phone is WIDE, so it wants the desktop ROW — story left, bottle
   alone in the middle, shop right — which the `(max-height: 540px)` arm on the
   two `.is-profile` blocks above already hands it. Everything here is the
   vertical squeeze on top of that: the chrome shrinks so the bottle keeps the
   middle of the screen to itself.
   540px is the cut because portrait phones start at 568px tall (iPhone SE) and
   landscape phones top out around 480px (S22 Ultra). Tablets in landscape are
   both taller than this and wider than 900px, so they stay on the desktop path.
   Height-gated, not `orientation: landscape`, because the URL bar collapsing
   does not change orientation but a squeezed desktop window is still short. */
@media (max-height: 540px) {
  /* The fixed nav is the single biggest fixed cost on a 390px-tall screen. */
  .nav { padding: 0.55rem clamp(0.8rem, 3vw, 2rem); }
  .nav_logo { font-size: 1.15rem; }
  .nav_sub { display: none; }
  .button { padding: 0.5rem 1.1rem; font-size: 0.75rem; }
  .search_input { padding: 0.4rem 0.9rem; font-size: 0.75rem; }

  /* --- Hero --- */
  .is-gamme { padding-top: 3.2rem; padding-bottom: 0.7rem; }
  .gamme_topline { font-size: 0.85rem; }
  /* Single swipeable row (see the max-width:900px block); cap it to one row's
     height so it can never grow a second row into the bottles. */
  .gamme_names { max-height: 2.1rem; }
  .gamme_flavor { font-size: 1.15rem; }
  .gamme_inspired, .gamme_notes { font-size: 0.78rem; }
  .gamme_arrows { margin-top: 0.2rem; }
  .gamme_arrow { width: 2.3rem; height: 2.3rem; font-size: 0.9rem; }
  .gamme_footnote { display: none; }

  /* --- Product page --- */
  /* Same hard cap as the portrait phone rules: native scrolling is off on
     touch devices, so a section that outgrows the viewport both hides its own
     buy button AND desyncs the section map from the page boundaries. */
  .is-profile {
    height: 100svh;
    overflow: hidden;
    padding-top: 3.2rem;
    padding-bottom: max(0.7rem, env(safe-area-inset-bottom));
  }
  .is-profile .product_layout { align-items: center; }
  /* space-between, NOT the desktop block's `center` — centering slides the two
     panels together over the bottle, which is the whole problem being fixed. */
  .product_layout {
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: 1rem;
    max-width: 100%;
  }
  .product_info { max-width: 17rem; gap: 0.3rem; }
  .product_info h2 { display: none; }
  .product_desc { display: none; }
  .product_dyn { gap: 0.3rem; }
  .product_kicker { font-size: 0.58rem; letter-spacing: 0.2em; }
  .product_name { font-size: 1.05rem; line-height: 1.15; }
  .product_inspired { font-size: 0.72rem; }
  .product_notes { font-size: 0.78rem; }
  .product_back { margin-top: 0.2rem; font-size: 0.68rem; }
  .product_arrows { margin-top: 0.45rem; gap: 0.5rem; }
  .product_arrow { width: 2.3rem; height: 2.3rem; font-size: 0.9rem; }
  .product_shop { width: 12rem; gap: 0.35rem; }
  /* Height-driven, like the portrait rule: the per-scent poster ratio changes
     the box's WIDTH so no scent can grow this column past the viewport. */
  .product_photo {
    width: auto;
    height: clamp(3rem, 22svh, 5.5rem);
    aspect-ratio: var(--photo-ratio, 4 / 3);
    align-self: center;
  }
  .product_photo_hint_title { font-size: 0.55rem; }
  .product_photo_hint_sub { font-size: 0.62rem; }
  .shape_btn { font-size: 0.55rem; padding: 0.25rem 0.5rem; }
  .product_price { font-size: 0.95rem; }
  .product_buy { padding: 0.5rem 1rem; font-size: 0.75rem; }
  .product_ship { font-size: 0.55rem; }
  .product_contact { font-size: 0.6rem; }

  /* --- Reviews --- */
  .is-reviews { padding-top: 3.2rem; padding-bottom: 0.7rem; }
  .reviews_card { max-height: calc(100svh - 4.4rem); padding: 1rem 1.2rem; gap: 0.45rem; }
  .reviews_title { font-size: 1.15rem; }
}
