/* ============================================================================
   MASON'S VISION — DESIGN SYSTEM
   Single source of truth. Drop into a GeneratePress child theme as the
   primary stylesheet (or @import into style.css). Every page references
   these tokens and component classes — do not hard-code values in templates.

   Contents
   ─────────
   1.  Fonts
   2.  Design tokens (:root) — colour, type, spacing, radius, motion, z, layout
   3.  Reset & base
   4.  Typography (display, headings, body, eyebrow, meta)
   5.  Layout helpers (container, section, grid, hairline)
   6.  Buttons & links + states
   7.  Badges & tags
   8.  Form controls (swatches, chips, selects, inputs)
   9.  Product card
   10. Global header + nav + mobile drawer + bottom bar
   11. Global footer
   12. Cart drawer
   13. Placeholder image utility (remove once real imagery lands)
   14. Breakpoints reference
   ========================================================================== */

/* 1. FONTS ----------------------------------------------------------------- */
/* Self-host these in production (woff2) — CDN import shown for the comp.    */
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400&family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');

/* 2. DESIGN TOKENS --------------------------------------------------------- */
:root {
  /* — Brand colour (client palette) — */
  --mv-ink:        #1B1A18;   /* main black — page & header background      */
  --mv-default:    #CEC7BB;   /* default foreground — text, icons, lines    */
  --mv-highlight:  #E6CFA3;   /* highlight — accents, hairline, hover, gold */

  /* — Derived tones (opacity / shade of the three above) — */
  --mv-coal:        #14130f;  /* deeper panel background                    */
  --mv-charcoal:    #232119;  /* raised surface                            */
  --mv-line:        rgba(206,199,187,0.14);  /* hairline / divider          */
  --mv-line-strong: rgba(206,199,187,0.28);  /* visible border             */
  --mv-mute:        rgba(206,199,187,0.60);  /* secondary text             */
  --mv-faint:       rgba(206,199,187,0.40);  /* tertiary / meta text       */
  --mv-hi-soft:     rgba(230,207,163,0.60);  /* soft gold (dashed borders) */
  --mv-hi-tint:     rgba(230,207,163,0.08);  /* selected chip tint         */
  --mv-hi-deep:     #b89e6f;                 /* gold gradient base         */

  /* Button hover. A gold-filled button and an outlined one hover in opposite
     directions, so they cannot share a fill: the filled one deepens its gold
     and keeps its ink label, the outlined one takes a faint tint and lifts its
     label to gold. One shared translucent fill is what made both unreadable —
     it dropped the filled button's background to 32% gold over near-black
     while darkening the label onto it (1.29:1). */
  --mv-hi-fill:       rgba(230,207,163,0.14); /* outline hover fill — a tint  */
  --mv-hi-fill-solid: #b89e6f;                /* primary hover fill — deeper  */
  --mv-hi-text:       var(--mv-highlight);    /* outline hover label — light  */
  --mv-hi-text-on:    var(--mv-ink);          /* primary hover label — ink    */

  /* — Typography — */
  --mv-serif: "Cormorant Garamond", "Times New Roman", serif;  /* display  */
  --mv-sans:  "Inter", system-ui, -apple-system, sans-serif;   /* UI       */
  --mv-mono:  "JetBrains Mono", ui-monospace, monospace;       /* meta     */

  /* Fluid type scale — clamp(min, vw, max). Display steps reflow across bp. */
  --mv-fs-display:  clamp(3.5rem, 9vw, 7.5rem);   /* hero H1               */
  --mv-fs-h1:       clamp(2.75rem, 6vw, 5rem);    /* page title           */
  --mv-fs-h2:       clamp(2rem, 4vw, 3.5rem);     /* section heading      */
  --mv-fs-h3:       clamp(1.5rem, 2.4vw, 2rem);   /* block heading        */
  --mv-fs-h4:       clamp(1.125rem, 1.6vw, 1.375rem);
  --mv-fs-lede:     clamp(1.0625rem, 1.4vw, 1.1875rem); /* italic intro    */
  --mv-fs-body:     1.0625rem;                    /* 17px serif body      */
  --mv-fs-ui:       0.6875rem;                    /* 11px caps UI         */
  --mv-fs-meta:     0.625rem;                     /* 10px mono meta       */

  --mv-lh-tight: 0.95;
  --mv-lh-snug:  1.1;
  --mv-lh-body:  1.62;

  --mv-ls-caps:  0.28em;   /* tracking for UI caps    */
  --mv-ls-wide:  0.32em;   /* eyebrow tracking        */
  --mv-ls-meta:  0.20em;   /* mono meta tracking      */

  /* — Spacing scale (8pt-based, with half-steps) — */
  --mv-s1:  4px;
  --mv-s2:  8px;
  --mv-s3:  12px;
  --mv-s4:  16px;
  --mv-s5:  20px;
  --mv-s6:  24px;
  --mv-s8:  32px;
  --mv-s10: 40px;
  --mv-s12: 48px;
  --mv-s16: 64px;
  --mv-s20: 80px;
  --mv-s30: 120px;

  /* — Page gutter (responsive) — */
  --mv-gutter: 20px;          /* mobile  */
  --mv-maxw:   1440px;        /* desktop content cap */

  /* — Radius (square brand; round only for swatches/badges) — */
  --mv-radius-0: 0;
  --mv-radius-pill: 999px;

  /* — Motion — */
  --mv-ease: cubic-bezier(.2,.7,.2,1);
  --mv-dur-bg: .35s;
  --mv-dur-fg: .25s;

  /* — Elevation (used sparingly; brand avoids heavy shadow) — */
  --mv-shadow-drawer: -24px 0 60px rgba(0,0,0,0.5);

  /* — Z-index scale — */
  --mv-z-header: 50;
  --mv-z-bottombar: 45;
  --mv-z-drawer: 80;
  --mv-z-overlay: 70;
}

/* Responsive gutter bumps */
@media (min-width: 768px)  { :root { --mv-gutter: 36px; } }
@media (min-width: 1024px) { :root { --mv-gutter: 48px; } }

/* 3. RESET & BASE ---------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* Horizontal-overflow guard: keep the page pinned to the viewport so nothing
   can push it sideways on mobile (the symptom: the page drifts left/right on a
   phone). `overflow-x: clip` is used instead of `hidden` deliberately — `clip`
   does NOT establish a scroll container, so the sticky header keeps sticking to
   the viewport. Individual overflowing components (category bar, utility row)
   are still contained at source below; this is the safety net. */
html, body { overflow-x: clip; max-width: 100%; }
body {
  margin: 0;
  background: var(--mv-ink);
  color: var(--mv-default);
  font-family: var(--mv-sans);
  font-size: var(--mv-fs-body);
  line-height: var(--mv-lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
/* The hover state has to be reclaimed too, not just the resting one. `a` is a
   weaker selector than the parent theme's `a:hover`, so GeneratePress's link
   hover colour — picked for a light page — won every link that did not name a
   colour of its own, and painted it dark on this dark one. Matching its
   selector and loading after it hands the colour back to the component. Every
   mv- component that sets its own hover still wins on specificity. */
a:hover, a:focus, a:active { color: inherit; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
ul { margin: 0; padding: 0; list-style: none; }
:focus-visible { outline: 2px solid var(--mv-highlight); outline-offset: 3px; }

/* 4. TYPOGRAPHY ------------------------------------------------------------ */
.mv-display, .mv-h1, .mv-h2, .mv-h3, .mv-h4 {
  font-family: var(--mv-serif);
  font-weight: 300;
  letter-spacing: -0.015em;
  margin: 0;
  color: var(--mv-default);
  text-wrap: balance;
}
.mv-display { font-size: var(--mv-fs-display); line-height: var(--mv-lh-tight); }
.mv-h1      { font-size: var(--mv-fs-h1);      line-height: var(--mv-lh-tight); }
.mv-h2      { font-size: var(--mv-fs-h2);      line-height: var(--mv-lh-snug); }
.mv-h3      { font-size: var(--mv-fs-h3);      line-height: var(--mv-lh-snug); font-weight: 400; }
.mv-h4      { font-size: var(--mv-fs-h4);      line-height: 1.2; font-weight: 400; }

/* italic gold accent inside headings */
.mv-em { font-style: italic; color: var(--mv-highlight); font-weight: inherit; }
.mv-em--plain { font-style: italic; color: inherit; }

.mv-lede {
  font-family: var(--mv-serif);
  font-style: italic;
  font-weight: 300;
  font-size: var(--mv-fs-lede);
  line-height: 1.55;
  color: var(--mv-mute);
  margin: 0;
  text-wrap: pretty;
}
.mv-body {
  font-family: var(--mv-serif);
  font-weight: 300;
  font-size: var(--mv-fs-body);
  line-height: var(--mv-lh-body);
  color: var(--mv-mute);
  margin: 0;
  text-wrap: pretty;
}
.mv-eyebrow {
  font-family: var(--mv-sans);
  font-weight: 300;
  font-size: 0.6875rem;
  letter-spacing: var(--mv-ls-wide);
  text-transform: uppercase;
  color: var(--mv-highlight);
}
.mv-caps {
  font-family: var(--mv-sans);
  font-weight: 500;
  font-size: var(--mv-fs-ui);
  letter-spacing: var(--mv-ls-caps);
  text-transform: uppercase;
}
.mv-meta {
  font-family: var(--mv-mono);
  font-size: var(--mv-fs-meta);
  letter-spacing: var(--mv-ls-meta);
  text-transform: uppercase;
  color: var(--mv-faint);
}
.mv-price {
  font-family: var(--mv-serif);
  font-weight: 300;
  color: var(--mv-highlight);
}
.mv-price--italic { font-style: italic; color: var(--mv-mute); }

/* 5. LAYOUT HELPERS -------------------------------------------------------- */
.mv-container { width: 100%; max-width: var(--mv-maxw); margin-inline: auto; padding-inline: var(--mv-gutter); }
.mv-section   { padding-block: var(--mv-s16); }
@media (min-width: 1024px) { .mv-section { padding-block: var(--mv-s30); } }

.mv-stack > * + * { margin-top: var(--mv-s4); }
.mv-flow > * + * { margin-top: var(--mv-s6); }

/* Gold hairline divider — fades to transparent at both ends. Brand element. */
.mv-hairline {
  height: 1px;
  border: 0;
  margin: 0;
  background: linear-gradient(90deg, transparent, var(--mv-highlight) 30%, var(--mv-highlight) 70%, transparent);
  opacity: 0.55;
}
.mv-hairline--short { max-width: 80px; }
.mv-hairline--faint { opacity: 0.35; }

/* Responsive grids */
.mv-grid { display: grid; gap: var(--mv-s6); }
.mv-grid--2 { grid-template-columns: 1fr; }
.mv-grid--3 { grid-template-columns: 1fr; }
.mv-grid--4 { grid-template-columns: 1fr 1fr; }
@media (min-width: 768px) {
  .mv-grid--2 { grid-template-columns: 1fr 1fr; }
  .mv-grid--3 { grid-template-columns: repeat(3, 1fr); }
  .mv-grid--4 { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 1024px) {
  .mv-grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* Horizontal scroll rail (mobile category strips, sliders).
   Containment trio (shared by every scroll rail in the theme):
   - min-width:0 + max-width:100% → the rail box can never grow past its
     container, even as a flex/grid item (defeats the min-content blow-out).
   - overscroll-behavior-x:contain → a horizontal swipe stays *inside* the rail
     instead of chaining up and panning the whole page on touch. This is the
     actual fix for the page drifting sideways on mobile. */
.mv-rail {
  display: flex;
  gap: var(--mv-s4);
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.mv-rail::-webkit-scrollbar { height: 0; }
.mv-rail > * { scroll-snap-align: start; flex: 0 0 auto; }

/* 6. BUTTONS & LINKS ------------------------------------------------------- */
.mv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--mv-s3);
  padding: 15px 28px;
  font-family: var(--mv-sans);
  font-size: var(--mv-fs-ui);
  font-weight: 500;
  letter-spacing: var(--mv-ls-caps);
  text-transform: uppercase;
  border: 1px solid transparent;
  border-radius: var(--mv-radius-0);
  background: transparent;
  color: var(--mv-default);
  cursor: pointer;
  transition: background var(--mv-dur-bg) var(--mv-ease),
              color var(--mv-dur-fg) var(--mv-ease),
              border-color var(--mv-dur-fg) var(--mv-ease);
}
.mv-btn--sm { padding: 11px 18px; font-size: var(--mv-fs-meta); }
.mv-btn--block { width: 100%; }

/* Primary — gold fill. Hover: the gold deepens, the ink label stays put. */
.mv-btn--primary { background: var(--mv-highlight); border-color: var(--mv-highlight); color: var(--mv-ink); }
.mv-btn--primary:hover { background: var(--mv-hi-fill-solid); border-color: var(--mv-hi-fill-solid); color: var(--mv-hi-text-on); }

/* Outline — most common. Hover: faint gold tint, label lifts to gold. */
.mv-btn--outline { border-color: var(--mv-highlight); color: var(--mv-default); }
.mv-btn--outline:hover { background: var(--mv-hi-fill); color: var(--mv-hi-text); }

/* Ghost — neutral border for dense rows. */
.mv-btn--ghost { border-color: var(--mv-line-strong); color: var(--mv-default); }
.mv-btn--ghost:hover { background: rgba(206,199,187,0.10); }

.mv-btn:active { transform: translateY(0.5px); }
.mv-btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* Icon button (square) */
.mv-iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  border: 1px solid var(--mv-line-strong);
  color: var(--mv-default);
  transition: border-color var(--mv-dur-fg) var(--mv-ease), background var(--mv-dur-bg) var(--mv-ease);
}
.mv-iconbtn:hover { border-color: var(--mv-highlight); background: var(--mv-hi-tint); }
.mv-iconbtn--gold { border-color: var(--mv-highlight); color: var(--mv-highlight); }

/* Text link — fade gold underline grows from the left/centre on hover. */
.mv-link {
  position: relative;
  display: inline-block;
  font-family: var(--mv-sans);
  font-size: var(--mv-fs-ui);
  font-weight: 500;
  letter-spacing: var(--mv-ls-caps);
  text-transform: uppercase;
  color: var(--mv-default);
  padding-bottom: 4px;
  transition: color var(--mv-dur-fg) var(--mv-ease);
}
.mv-link::after {
  content: "";
  position: absolute; left: 0; bottom: 0;
  width: 30%; height: 1px;
  background: linear-gradient(90deg, var(--mv-highlight), transparent);
  transition: width var(--mv-dur-bg) var(--mv-ease);
}
.mv-link:hover { color: var(--mv-highlight); }
.mv-link:hover::after { width: 100%; }

/* 7. BADGES & TAGS --------------------------------------------------------- */
.mv-tag {
  display: inline-flex; align-items: center;
  font-family: var(--mv-mono);
  font-size: 0.5625rem;          /* 9px */
  letter-spacing: var(--mv-ls-meta);
  text-transform: uppercase;
  padding: 4px 8px;
  border: 1px solid var(--mv-line-strong);
  color: var(--mv-default);
  background: rgba(20,19,15,0.55);
}
.mv-tag--signature { color: var(--mv-highlight); border-color: var(--mv-highlight); }
.mv-tag--new       { color: var(--mv-highlight); border-color: var(--mv-highlight); background: transparent; }

/* Count pill (bag) */
.mv-pill {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 5px;
  font-family: var(--mv-sans); font-size: 0.5rem; font-weight: 600;
  color: var(--mv-ink); background: var(--mv-highlight);
  border-radius: var(--mv-radius-pill);
}

/* 7b. PAGE HERO ------------------------------------------------------------
   A photograph behind a page title. Same build as .home-hero, which keeps its
   own copy in home.css: that one reads a Featured image, carries CTAs and a
   numbered meta row, and runs 78vh as a cover. This is the shorter version for
   the pages you read rather than land on.

   Layering is DOM order, not z-index — the img comes first, the scrim after it,
   and __inner last, where position:relative lifts it above both. Reorder the
   markup and the scrim vanishes under the picture with no warning.

   Two layers because one cannot do both jobs. Measured across all five
   photographs, the h1 band needs ~0.64 uniform ink to clear AA-large — over the
   middle of the frame that would drown the picture the hero exists to show. So
   the linear scrim sets the mood and anchors the bottom edge, and the vignette
   carries the reading contrast, but only behind the copy. It rides __inner, so
   it tracks the text block across breakpoints instead of guessing at a fixed
   height, and fades out inside --mv-maxw so wide viewports keep the photograph
   bright at the edges.

   Below-3:1 across the h1 band, linear alone -> with the vignette:
     about 11.8% -> 0.0%   revelations 1.6% -> 0.0%   services 3.8% -> 0.2%
   ------------------------------------------------------------------------- */
.mv-phero { position: relative; min-height: 62vh; display: flex; align-items: center; overflow: hidden; }
.mv-phero__img { position: absolute; inset: 0; }
.mv-phero__img img { width: 100%; height: 100%; object-fit: cover; }
.mv-phero__scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(27,26,24,0.22) 0%, rgba(27,26,24,0.20) 45%, rgba(27,26,24,0.90) 100%); }
.mv-phero__inner { position: relative; width: 100%; text-align: center; padding-block: var(--mv-s12); background: radial-gradient(ellipse 66% 72% at 50% 42%, rgba(27,26,24,0.88) 0%, rgba(27,26,24,0.80) 55%, rgba(27,26,24,0) 100%); }

/* Left-aligned copy — By Revelations and the category archives, which share the
   same big left-set title. Below desktop the vignette stays wide and centred:
   the title wraps across the full column at that width, so there is no empty
   frame to leave lit, and cover crops a wide banner harder on a narrow
   viewport — which pushes the bright subject straight under the text. Measured:
   the left-offset vignette left bracelets at 2.2% below 3:1 on mobile and rings
   at 1.3%; widening it takes all six category banners to 0.00%. */
.mv-phero--start .mv-phero__inner { text-align: left; background: radial-gradient(ellipse 85% 78% at 50% 42%, rgba(27,26,24,0.88) 0%, rgba(27,26,24,0.80) 55%, rgba(27,26,24,0) 100%); }

@media (min-width: 1024px) {
  .mv-phero__inner { padding-block: var(--mv-s20); }
  /* Desktop has frame to spare beside the title, so the vignette moves to the
     text and leaves the right of the photograph lit. */
  .mv-phero--start .mv-phero__inner { background: radial-gradient(ellipse 62% 72% at 34% 42%, rgba(27,26,24,0.88) 0%, rgba(27,26,24,0.80) 55%, rgba(27,26,24,0) 100%); }
}

/* 8. FORM CONTROLS --------------------------------------------------------- */
/* Selectable chip (length, clasp, engraving…) */
.mv-chip {
  padding: 11px 16px;
  border: 1px solid var(--mv-line-strong);
  background: transparent;
  color: var(--mv-default);
  font-family: var(--mv-sans);
  font-size: var(--mv-fs-meta);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  transition: border-color var(--mv-dur-fg) var(--mv-ease), background var(--mv-dur-bg) var(--mv-ease), color var(--mv-dur-fg) var(--mv-ease);
}
.mv-chip:hover { border-color: var(--mv-hi-soft); }
.mv-chip[aria-pressed="true"], .mv-chip.is-active {
  border-color: var(--mv-highlight);
  background: var(--mv-hi-tint);
  color: var(--mv-highlight);
}
.mv-chip--serif { font-family: var(--mv-serif); font-size: 1rem; letter-spacing: 0; text-transform: none; padding: 11px 0; text-align: center; }
.mv-chip--dashed { border-style: dashed; border-color: var(--mv-hi-soft); color: var(--mv-highlight); }

/* Plating swatch */
.mv-swatch {
  width: 32px; height: 32px;
  border-radius: var(--mv-radius-pill);
  border: 1px solid var(--mv-line-strong);
  cursor: pointer;
  transition: box-shadow var(--mv-dur-fg) var(--mv-ease), border-color var(--mv-dur-fg) var(--mv-ease);
}
.mv-swatch.is-active { border: 2px solid var(--mv-highlight); box-shadow: 0 0 0 2px var(--mv-ink); }

/* Text input / textarea / select.
   The fields sit on a raised grey surface rather than the page: transparent on
   ink left them reading as decorative rules instead of things you can type in.
   --mv-charcoal is the existing "raised surface" tone, so no new colour enters
   the system. Focus still moves the border to gold. */
.mv-input, .mv-textarea, .mv-select {
  width: 100%;
  padding: 14px 16px;
  background: var(--mv-charcoal);
  border: 1px solid var(--mv-line-strong);
  color: var(--mv-default);
  font-family: var(--mv-serif);
  font-size: 1rem;
  transition: border-color var(--mv-dur-fg) var(--mv-ease);
}
.mv-input::placeholder, .mv-textarea::placeholder { color: var(--mv-faint); font-style: italic; }
.mv-input:focus, .mv-textarea:focus, .mv-select:focus { outline: none; border-color: var(--mv-highlight); }
.mv-textarea { min-height: 96px; resize: vertical; }
.mv-field-label { display: block; margin-bottom: var(--mv-s3); }

/* Quantity stepper */
.mv-qty { display: inline-flex; align-items: center; border: 1px solid var(--mv-line-strong); }
.mv-qty button { width: 40px; height: 40px; display: grid; place-items: center; color: var(--mv-default); }
.mv-qty button:hover { color: var(--mv-highlight); }
.mv-qty span { min-width: 40px; text-align: center; font-family: var(--mv-serif); font-size: 1.0625rem; }

/* 9. PRODUCT CARD ---------------------------------------------------------- */
.mv-card { display: flex; flex-direction: column; }

/* The media box carries the surface for every product in the house — grid,
   strips, rails, mega panel. It had none: an unfilled card was pure page, and a
   filled one would have been a bare <img>. Now it is the raised grey tone with a
   hairline, so the product display reads as one system whether or not the shot
   has landed yet. .mv-ph (§13) still paints its own gradient over this for the
   un-shot state — it is defined later, so it wins.
   The tag sits inset over the media, so overflow must clip rather than scroll. */
.mv-card__media { position: relative; aspect-ratio: 4/5; margin-bottom: var(--mv-s3); background: var(--mv-charcoal); border: 1px solid var(--mv-line); overflow: hidden; }
.mv-card__media .mv-tag { position: absolute; top: 10px; left: 10px; }

/* Product photography arrives at whatever aspect the shoot produced, but the
   card box is fixed at 4/5. Without this the <img> keeps its own ratio inside
   that box and the grid goes ragged the moment the media import lands. Same
   treatment .pdp-gallery__big > img already gets on the PDP. */
.mv-card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--mv-dur-bg) var(--mv-ease); }

/* Hover: the hairline warms to gold and the piece leans in slightly — the same
   gold-on-hover answer the text links give. */
.mv-card:hover .mv-card__media { border-color: var(--mv-hi-soft); }
.mv-card:hover .mv-card__media img { transform: scale(1.03); }
.mv-card:hover .mv-card__title { color: var(--mv-highlight); }
@media (prefers-reduced-motion: reduce) {
  .mv-card:hover .mv-card__media img { transform: none; }
}

.mv-card__title { font-family: var(--mv-serif); font-weight: 400; font-size: 1.0625rem; margin: 0; color: var(--mv-default); transition: color var(--mv-dur-fg) var(--mv-ease); }
.mv-card__row { display: flex; justify-content: space-between; align-items: baseline; }
.mv-card__price { font-family: var(--mv-serif); font-style: italic; font-weight: 300; font-size: 0.9375rem; color: var(--mv-mute); }

/* Model group (grouped width variants) */
.mv-modelgroup { border: 1px solid var(--mv-line); background: rgba(20,19,15,0.4); padding: var(--mv-s5); }
.mv-modelgroup__head { display: flex; align-items: center; gap: var(--mv-s3); flex-wrap: wrap; margin-bottom: var(--mv-s4); }
.mv-modelgroup__head h3 { font-family: var(--mv-serif); font-weight: 400; font-size: 1.625rem; margin: 0; color: var(--mv-default); }
.mv-modelgroup__count { margin-left: auto; }
.mv-modelgroup__variants { display: grid; grid-template-columns: 1fr 1fr; gap: var(--mv-s4); }
@media (min-width: 768px) { .mv-modelgroup__variants { grid-template-columns: repeat(4, 1fr); } }

/* 10. GLOBAL HEADER -------------------------------------------------------- */
.mv-header { position: sticky; top: 0; z-index: var(--mv-z-header); background: rgba(27,26,24,0.96); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--mv-line); }
.mv-header__utility { display: flex; justify-content: space-between; align-items: center; gap: var(--mv-s4); padding: 8px var(--mv-gutter); font-size: 0.5625rem; letter-spacing: 0.22em; text-transform: uppercase; color: var(--mv-mute); border-bottom: 1px solid var(--mv-line); }
.mv-header__utility-links { display: flex; gap: var(--mv-s8); flex: 0 0 auto; }
/* These links had no hover at all. Gold is the colour .mv-link already draws in
   the rule under itself, so every text link in the house now answers the same
   way to the pointer. */
.mv-header__utility a { transition: color var(--mv-dur-fg) var(--mv-ease); }
.mv-header__utility a:hover { color: var(--mv-highlight); }
/* The utility row is a single non-wrapping line; on phones the shipping promo +
   the three links together exceed the viewport and pushed the page sideways.
   Below 768px the promo line shrinks (and truncates if needed) while the links
   stay intact — the row contains itself rather than overflowing. min-width:0 is
   required for a flex child to be allowed to shrink below its content width. */
.mv-header__utility > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 767.98px) {
  .mv-header__utility-links { gap: var(--mv-s4); }
}
.mv-header__bar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: 14px var(--mv-gutter); }
.mv-header__nav-left { display: none; gap: var(--mv-s8); }
.mv-header__actions { display: flex; gap: var(--mv-s5); justify-content: flex-end; align-items: center; }
.mv-header__action { position: relative; display: inline-flex; color: var(--mv-default); }
.mv-header__action .mv-pill { position: absolute; top: -5px; right: -8px; }
.mv-header__burger { display: inline-flex; color: var(--mv-default); }

/* Search panel (header.php).
   The <details> is deliberately left static so the panel's containing block is
   the sticky .mv-header itself — that's what lets it span the full header width
   and drop below the whole header (bar + category rail) rather than dangle off
   the icon. Square, hairline, no shadow. */
.mv-search { position: static; }
.mv-search__toggle { list-style: none; cursor: pointer; }
.mv-search__toggle::-webkit-details-marker { display: none; }
.mv-search[open] .mv-search__toggle { color: var(--mv-highlight); }
.mv-search__panel { position: absolute; left: 0; right: 0; top: 100%; padding-block: var(--mv-s6); background: var(--mv-coal); border-top: 1px solid var(--mv-line); border-bottom: 1px solid var(--mv-line-strong); }
.mv-search__form { display: flex; align-items: stretch; gap: var(--mv-s3); }
.mv-search__input { flex: 1; min-width: 0; }  /* .mv-input is width:100%; let it flex instead. */
.mv-search__submit { flex: 0 0 auto; }
/* Drops down from the header. A closed <details> takes its panel out of the box
   tree entirely, so there is only ever an entry animation to play. */
@keyframes mv-search-drop {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.mv-search[open] .mv-search__panel { animation: mv-search-drop var(--mv-dur-bg) var(--mv-ease); }
@media (prefers-reduced-motion: reduce) {
  .mv-search[open] .mv-search__panel { animation: none; }
}

/* Logo */
.mv-logo { display: inline-flex; flex-direction: column; align-items: center; gap: 3px; line-height: 1; }
.mv-logo__mark { display: block; }
.mv-logo__word { font-family: var(--mv-serif); font-weight: 500; letter-spacing: 0.16em; color: var(--mv-highlight); text-transform: uppercase; font-size: 1.125rem; }
.mv-logo__word em { font-style: italic; font-weight: 400; }
.mv-logo__sub { font-family: var(--mv-serif); font-style: italic; font-weight: 300; font-size: 0.5625rem; letter-spacing: 0.45em; color: var(--mv-default); opacity: 0.75; margin-left: 0.45em; }
/* An uploaded logo. height:auto with a max-height caps it without touching the
   ratio — the upload is whatever size the client had, and a fixed height would
   stretch it. The header bar is the constraint; the footer has room, so it caps
   higher. Requires a transparent background: a logo carrying its own paints a
   rectangle onto the header rather than sitting on it. */
.mv-logo--custom { display: inline-flex; }
.mv-logo__img { width: auto; height: auto; max-height: 40px; max-width: 220px; object-fit: contain; }
.mv-footer .mv-logo__img { max-height: 52px; }

/* Primary category carousel — the collections bar. A horizontally scrolling
   rail that never overflows the viewport: native swipe/scroll on touch, plus
   step arrows on desktop (pointer). Brand styling only — hairline borders, no
   shadows. The rail (.mv-header__nav) is the scroll track; arrows are siblings
   that JS shows only when the content actually overflows. */
.mv-catbar { position: relative; display: flex; align-items: center; justify-content: center; gap: var(--mv-s3); padding: 0 var(--mv-gutter) 14px; }
.mv-header__nav { display: flex; gap: var(--mv-s10); flex: 0 1 auto; min-width: 0; max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain; scroll-behavior: smooth; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.mv-header__nav::-webkit-scrollbar { height: 0; }
.mv-header__nav > .mv-navlink { flex: 0 0 auto; scroll-snap-align: start; white-space: nowrap; }
/* Step arrows: hidden by default (mobile swipes); revealed ≥1024px. A hairline
   square — no shadow. `[hidden]` (set by JS when there's nothing to scroll) and
   `:disabled` (at an end of travel) keep them honest. */
.mv-catbar__arrow { display: none; flex: 0 0 auto; align-items: center; justify-content: center; width: 30px; height: 30px; color: var(--mv-default); border: 1px solid var(--mv-line); opacity: 0.7; transition: opacity var(--mv-dur-fg) var(--mv-ease), border-color var(--mv-dur-fg) var(--mv-ease); }
.mv-catbar__arrow svg { display: block; }
.mv-catbar__arrow:hover { opacity: 1; border-color: var(--mv-highlight); }
.mv-catbar__arrow:disabled { opacity: 0.2; cursor: default; border-color: var(--mv-line); }
.mv-catbar__arrow[hidden] { display: none; }
.mv-navlink {
  position: relative; font-family: var(--mv-sans); font-size: var(--mv-fs-ui);
  letter-spacing: var(--mv-ls-wide); text-transform: uppercase; color: var(--mv-default);
  opacity: 0.82; padding-bottom: 6px; transition: opacity var(--mv-dur-fg) var(--mv-ease);
}
.mv-navlink::after {
  content: ""; position: absolute; left: 50%; bottom: 0; width: 0; height: 1px;
  transform: translateX(-50%);
  background: linear-gradient(90deg, transparent, var(--mv-highlight) 30%, var(--mv-highlight) 70%, transparent);
  transition: width var(--mv-dur-bg) var(--mv-ease);
}
/* Names its own colour rather than leaning on opacity alone: a rule that only
   lifts opacity leaves the colour to whatever else matches, which is how the
   parent theme's dark hover reached these. Gold also makes hover legible as
   hover, not just as "slightly less faded". */
.mv-navlink:hover, .mv-navlink[aria-current="page"] { opacity: 1; color: var(--mv-highlight); }
.mv-navlink:hover::after, .mv-navlink[aria-current="page"]::after { width: 110%; }

/* Mobile menu (off-canvas) — same brand pattern as the cart drawer: an ink
   panel sliding in from the left with the dimming overlay. Holds the category +
   utility links stacked vertically. Hidden on desktop (inline navs take over).
   Lives at body level in header.php (outside the sticky header's backdrop
   filter) so its fixed positioning isn't trapped in a stacking context. */
.mv-menu {
  position: fixed; top: 0; left: 0; z-index: var(--mv-z-drawer);
  width: min(360px, 86vw); height: 100%;
  background: var(--mv-ink); border-right: 1px solid var(--mv-line-strong);
  box-shadow: var(--mv-shadow-drawer);
  transform: translateX(-100%); transition: transform var(--mv-dur-bg) var(--mv-ease);
  flex-direction: column; overflow-y: auto;
  /* `display` is set per-breakpoint below: flex < 1024px, none ≥ 1024px. */
}
/* Hardening: the open state asserts `display:flex` itself, so the drawer can't
   be left invisible by a stale/parent `display:none` on `.mv-menu`. Has no
   `!important`, so the desktop `display:none !important` hide still wins ≥1024. */
.mv-menu.is-open { display: flex; transform: translateX(0); }
.mv-menu__head { display: flex; justify-content: space-between; align-items: center; padding: var(--mv-s6) var(--mv-gutter) var(--mv-s5); border-bottom: 1px solid var(--mv-line); }
.mv-menu__nav { display: flex; flex-direction: column; padding: var(--mv-s2) var(--mv-gutter); }
.mv-menu__nav a { display: flex; justify-content: space-between; align-items: center; gap: var(--mv-s4); padding: 14px 0; font-family: var(--mv-sans); font-size: 0.8125rem; letter-spacing: var(--mv-ls-caps); text-transform: uppercase; color: var(--mv-default); border-bottom: 1px solid var(--mv-line); }
.mv-menu__nav a:last-child { border-bottom: 0; }
.mv-menu__nav a[aria-current="page"] { color: var(--mv-highlight); }
.mv-menu__nav a { transition: color var(--mv-dur-fg) var(--mv-ease); }
.mv-menu__nav a:hover { color: var(--mv-highlight); }
.mv-menu__nav--utility { padding-top: 0; padding-bottom: var(--mv-s8); }
.mv-menu__nav--utility a { font-size: 0.6875rem; color: var(--mv-mute); }

/* Shop-by-plating chips in the drawer — the mobile counterpart of the desktop
   mega panel's plating row (inc/nav.php). Both link onto the same layered-nav
   query var the category bar's filter uses. */
.mv-menu__plating { padding: var(--mv-s5) var(--mv-gutter); border-top: 1px solid var(--mv-line); }
.mv-menu__plating-title { margin: 0 0 var(--mv-s3); font-family: var(--mv-sans); font-size: 0.5625rem; letter-spacing: var(--mv-ls-caps); text-transform: uppercase; color: var(--mv-highlight); }
.mv-menu__plating-links { display: flex; flex-wrap: wrap; gap: var(--mv-s2); }
/* .mv-chip is authored for <button>; these are anchors, so restate the box. */
.mv-menu__plating-links .mv-chip { display: inline-flex; align-items: center; }

/* Desktop: reveal the utility nav + carousel arrows, hide burger + mobile menu */
@media (min-width: 1024px) {
  .mv-header__nav-left { display: flex; }
  .mv-catbar__arrow { display: inline-flex; }
  .mv-header__burger { display: none; }
  .mv-menu,
  [data-menu-overlay] { display: none !important; }
}

/* Mobile (< 1024px): the burger + drawer drive the menu, but the category
   carousel stays — it's a self-contained scroll rail (swipe), so it can no
   longer overflow the viewport the way the old static nav did. Only the
   utility text nav (its links live in the drawer) collapses here. */
@media (max-width: 1023.98px) {
  .mv-header .mv-header__nav-left { display: none; }
  .mv-header .mv-header__burger { display: inline-flex; }

  /* The off-canvas menu is laid out (display:flex) only on mobile, parked
     off-screen; `is-open` slides it in. The ≥1024px rule above keeps it
     display:none on desktop, so without this it never rendered on mobile —
     `is-open` was only changing transform on a never-displayed element. */
  .mv-menu { display: flex; transform: translateX(-100%); }
  .mv-menu.is-open { transform: translateX(0); }
}

/* Mobile bottom bar */
/* Four items: Home, Shop, Search, Bag. The comp drew five — "Saved" sat
   between Search and Bag — but this build has no wishlist to save anything to,
   so the item was cut rather than shipped pointing nowhere. Restore the fifth
   column here if one is ever built. */
.mv-bottombar { position: sticky; bottom: 0; z-index: var(--mv-z-bottombar); display: grid; grid-template-columns: repeat(4, 1fr); background: rgba(20,19,15,0.97); backdrop-filter: blur(10px); border-top: 1px solid var(--mv-line-strong); padding: 10px 8px 12px; }
.mv-bottombar a { display: flex; flex-direction: column; align-items: center; gap: 5px; color: var(--mv-mute); font-size: 0.53rem; letter-spacing: 0.12em; text-transform: uppercase; }
.mv-bottombar a[aria-current="page"] { color: var(--mv-highlight); }
.mv-bottombar__ico { position: relative; }
.mv-bottombar__ico .mv-pill { position: absolute; top: -5px; right: -7px; }
@media (min-width: 1024px) { .mv-bottombar { display: none; } }

/* 11. GLOBAL FOOTER -------------------------------------------------------- */
.mv-footer { background: var(--mv-coal); color: var(--mv-default); padding: var(--mv-s16) var(--mv-gutter) var(--mv-s8); border-top: 1px solid var(--mv-line-strong); }
.mv-footer__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--mv-s6); margin-bottom: var(--mv-s8); }
.mv-footer__brand { grid-column: 1 / -1; }
.mv-footer__brand .mv-body { margin-top: var(--mv-s5); max-width: 280px; }
.mv-footer h4 { font-family: var(--mv-sans); font-size: 0.5625rem; letter-spacing: var(--mv-ls-caps); text-transform: uppercase; color: var(--mv-highlight); font-weight: 500; margin: 0 0 var(--mv-s3); }
.mv-footer li { font-family: var(--mv-serif); font-size: 0.9375rem; color: var(--mv-mute); margin-bottom: 9px; }
/* Same hover contract as the utility row and .mv-link: gold on hover. Every
   footer link was inert to the pointer before. */
.mv-footer li a, .mv-footer__legal a { transition: color var(--mv-dur-fg) var(--mv-ease); }
.mv-footer li a:hover, .mv-footer__legal a:hover { color: var(--mv-highlight); }
.mv-footer__legal { display: flex; flex-direction: column; gap: var(--mv-s3); margin-top: var(--mv-s5); font-size: 0.5625rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--mv-faint); text-align: center; }
/* The link cluster is its own flex row, so the parent's text-align:center could
   never reach it — the four links packed hard left under a centred © line, and
   wrapped off a narrow screen because they couldn't wrap at all. */
.mv-footer__legal-links { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--mv-s3) var(--mv-s6); }
@media (min-width: 768px) {
  .mv-footer__grid { grid-template-columns: 1.4fr repeat(4, 1fr); gap: var(--mv-s12); }
  .mv-footer__brand { grid-column: auto; }
  .mv-footer__legal { flex-direction: row; justify-content: space-between; text-align: left; }
  .mv-footer__legal-links { justify-content: flex-start; }
}

/* 12. CART DRAWER ---------------------------------------------------------- */
.mv-overlay { position: fixed; inset: 0; z-index: var(--mv-z-overlay); background: rgba(10,9,8,0.6); opacity: 0; visibility: hidden; transition: opacity var(--mv-dur-bg) var(--mv-ease), visibility var(--mv-dur-bg); }
.mv-overlay.is-open { opacity: 1; visibility: visible; }
/* Height: 100% resolves against the viewport for a fixed element, but on mobile
   that tracks the *large* viewport, so the foot hides behind the address bar.
   100dvh follows the visible viewport instead; the 100% above is the fallback
   for engines that don't know dvh. */
.mv-cart { position: fixed; top: 0; right: 0; z-index: var(--mv-z-drawer); width: min(440px, 92vw); height: 100%; height: 100dvh; background: var(--mv-ink); border-left: 1px solid var(--mv-line-strong); box-shadow: var(--mv-shadow-drawer); transform: translateX(100%); transition: transform var(--mv-dur-bg) var(--mv-ease); display: flex; flex-direction: column; }
.mv-cart.is-open { transform: translateX(0); }

/* The WooCommerce fragment wrapper (inc/cart.php) sits between .mv-cart and the
   head/body/foot that the design reference had as its direct children — and the
   rules below were authored for that reference markup, so the wrapper silently
   orphaned them: it is a plain block, so .mv-cart__body's flex:1 was resolving
   inside a non-flex parent and doing nothing. The body then sized to its content,
   never overflowed *itself*, never scrolled, and pushed the foot (with Checkout)
   past the bottom of the viewport. The wrapper has to carry the column itself.

   min-height:0 is the load-bearing part: a column flex item defaults to
   min-height:auto, which refuses to shrink below its content — so both the
   wrapper and the body would grow to fit all nine items instead of scrolling.
   The scroll must come from the body, never from the drawer growing. */
.mv-cart__fragment { flex: 1; min-height: 0; display: flex; flex-direction: column; }

.mv-cart__head { flex: 0 0 auto; display: flex; justify-content: space-between; align-items: center; padding: var(--mv-s6) var(--mv-s6) var(--mv-s5); border-bottom: 1px solid var(--mv-line); }
/* overscroll-behavior keeps a swipe that reaches the end of the list from
   chaining into the page behind it — the same guard the rails use. */
.mv-cart__body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; -webkit-overflow-scrolling: touch; padding: var(--mv-s5) var(--mv-s6); }
.mv-cart__item { display: grid; grid-template-columns: 72px 1fr auto; gap: var(--mv-s4); padding: var(--mv-s4) 0; border-bottom: 1px solid var(--mv-line); }
/* Fixed 4/5 box in a 72px column, but the only global img rule is
   max-width:100% — so real photography would keep its own aspect inside it and
   leave the line items ragged. Same treatment as .mv-card__media img and
   .pdp-gallery__big > img. */
.mv-cart__item-media { aspect-ratio: 4/5; }
.mv-cart__item-media img { width: 100%; height: 100%; object-fit: cover; }
/* flex:0 0 auto — the foot must never be the thing that gives when the list is
   long. Checkout stays on screen at any item count. */
.mv-cart__foot { flex: 0 0 auto; padding: var(--mv-s5) var(--mv-s6) var(--mv-s6); border-top: 1px solid var(--mv-line-strong); }
.mv-cart__line { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: var(--mv-s3); }

/* 13. PLACEHOLDER IMAGE ---------------------------------------------------- */
/* Visual stand-in for un-shot photography. Delete this rule + the data-label
   attributes once real <img> elements are wired in. */
.mv-ph {
  position: relative;
  background:
    repeating-linear-gradient(135deg, rgba(230,207,163,0.05) 0 2px, transparent 2px 12px),
    linear-gradient(180deg, #232119 0%, #14130f 100%);
  border: 1px solid var(--mv-line);
  overflow: hidden;
}
.mv-ph::after {
  content: attr(data-label);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 14px;
  font-family: var(--mv-mono); font-size: 0.5625rem; letter-spacing: 0.12em;
  color: rgba(230,207,163,0.5); text-transform: uppercase;
}

/* 14. BREAKPOINTS REFERENCE ----------------------------------------------- */
/*  Mobile   : base styles, < 768px   (single column, hamburger, bottom bar) */
/*  Tablet   : >= 768px                (2–3 col grids, inline footer)         */
/*  Desktop  : >= 1024px               (full nav, 4 col, max-width 1440)      */
/*  Author mobile-first; layer enhancements with min-width queries only.     */
