/* ============================================================
   REUSABLE COMPONENTS  (client-agnostic)
   ------------------------------------------------------------
   Styles reference the token contract in lib/tokens.css only —
   no client colours, fonts, copy, or image paths in this file.
   Load order: tokens.css -> components.css -> site/theme.css

   Breakpoints mirror --bp-* (CSS cannot interpolate variables
   into @media): 375 / 768 / 1024 / 1440 / 1920.
   ============================================================ */

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

/* ---------- THE FIXED HEADER'S HEIGHT, IN ONE PLACE -------- */
/* Two things must agree about how tall the header is: the header
   itself, and the scroll offset that keeps anchor targets out from
   under it. They used to be two literals — min-height on
   .site-header__inner and a hardcoded 88px here, commented "fixed
   header height". Only one of them was 88: the header is 72 until
   1024px, so the offset was over by 16 on every phone and exactly
   right on desktop, leaving headings flush against the header there.

   Neither number could tell you it had drifted from the other. Now
   there is one number and both read it. */
:root { --header-h: 72px; }
@media (min-width: 1024px) { :root { --header-h: 88px; } }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* +16: one pixel of it is the header's bottom hairline, which
     min-height does not include; the other fifteen are breathing room,
     so a heading does not land welded to the header's underside.
     Fifteen is what phones already had — this makes desktop match
     rather than changing what was working. */
  scroll-padding-top: calc(var(--header-h) + 16px);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--c-paper);
  color: var(--c-ink);
  font-family: var(--font-ui);
  font-size: var(--t-base);
  font-weight: var(--fw-normal);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
img, picture, video, svg { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
ul, ol { list-style: none; }
::selection { background: var(--c-metal-text); color: var(--c-paper); }

h1, h2, h3, h4, .display { font-family: var(--font-display); font-weight: var(--fw-normal); }

/* Focus: never removed, always visible, clears 3:1 on both grounds. */
:focus-visible {
  outline: 2px solid var(--c-focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
.on-ink :focus-visible { outline-color: var(--c-on-ink); }

.skip-link {
  position: absolute; left: var(--s-4); top: -100px;
  z-index: var(--z-skiplink);
  background: var(--c-ink); color: var(--c-paper);
  padding: var(--s-3) var(--s-5);
  font-size: var(--t-sm); letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  transition: top var(--dur-fast) var(--ease-out);
}
.skip-link:focus { top: var(--s-4); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ---------- LAYOUT PRIMITIVES ------------------------------ */
.wrap      { width: 100%; max-width: var(--w-content); margin-inline: auto; padding-inline: var(--page-pad); }
.wrap-wide { width: 100%; max-width: var(--w-wide);    margin-inline: auto; padding-inline: var(--page-pad); }
.wrap-narrow { width: 100%; max-width: var(--w-narrow); margin-inline: auto; padding-inline: var(--page-pad); }

.section        { padding-block: var(--section-y); position: relative; }
.section--tight { padding-block: var(--section-y-tight); }
.section--loose { padding-block: var(--section-y-loose); }
.section--flush { padding-block: 0; }

.on-ink { background: var(--c-ink-ground); color: var(--c-on-ink); }
.on-ink h1, .on-ink h2, .on-ink h3 { color: var(--c-on-ink); }
.on-bone  { background: var(--c-bone); }
.on-smoke { background: var(--c-smoke); }
.ruled-top { border-top: var(--bw-hair) solid var(--c-line); }
.on-ink.ruled-top, .on-ink .ruled-top { border-color: var(--c-line-on-ink); }

/* ---------- TYPE PATTERNS ---------------------------------- */
.kicker {
  font-family: var(--font-ui);
  font-size: var(--t-2xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--c-metal-text);
  display: flex; align-items: center; gap: var(--s-3);
}
.on-ink .kicker { color: var(--c-metal-on-ink); }
.kicker::before {
  content: ''; width: 28px; height: 1px; flex: none;
  background: currentColor; opacity: 0.75;
}
.kicker--bare::before { display: none; }

.h-display { font-size: var(--t-4xl); line-height: var(--lh-tight); letter-spacing: var(--tr-tight); }
.h-1       { font-size: var(--t-3xl); line-height: var(--lh-tight); letter-spacing: var(--tr-tight); }
.h-2       { font-size: var(--t-2xl); line-height: var(--lh-snug);  letter-spacing: var(--tr-tight); }
.h-3       { font-size: var(--t-xl);  line-height: var(--lh-snug); }
.h-4       { font-size: var(--t-lg);  line-height: var(--lh-snug); }
.lede      { font-size: var(--t-md);  line-height: var(--lh-relaxed); color: var(--c-ink-2); max-width: var(--w-text); }
.on-ink .lede { color: var(--c-on-ink-2); }
.body      { color: var(--c-ink-2); max-width: var(--w-text); }
.on-ink .body { color: var(--c-on-ink-2); }
.muted     { color: var(--c-ink-3); }
.on-ink .muted { color: var(--c-on-ink-3); }
.caption   { font-size: var(--t-xs); line-height: var(--lh-normal); color: var(--c-ink-3); }
.on-ink .caption { color: var(--c-on-ink-3); }
.num {
  font-family: var(--font-ui); font-size: var(--t-2xs);
  letter-spacing: var(--tr-label); color: var(--c-metal-text);
  font-variant-numeric: tabular-nums;
}
.on-ink .num { color: var(--c-metal-on-ink); }
em.italic { font-style: italic; }

/* Section header: heading left, supporting text right. Not centred. */
.sec-head {
  display: grid; grid-template-columns: 1fr; gap: var(--s-5);
  margin-bottom: var(--s-9);
}
.sec-head__aside { align-self: end; }
@media (min-width: 768px) {
  .sec-head { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: var(--s-11); align-items: end; }
}

/* ---------- BUTTONS ---------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: 48px; padding: var(--s-3) var(--s-7);
  font-family: var(--font-ui); font-size: var(--t-sm); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-wide); text-transform: uppercase;
  border: var(--bw-hair) solid transparent;
  border-radius: var(--radius-none);
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.btn--solid  { background: var(--c-ink); color: var(--c-paper); }
.btn--solid:hover  { background: var(--c-metal-text); }
.btn--ghost  { border-color: var(--c-line-strong); color: var(--c-ink); }
.btn--ghost:hover  { border-color: var(--c-ink); background: var(--c-ink); color: var(--c-paper); }
.on-ink .btn--solid { background: var(--c-on-ink); color: var(--c-ink); }
.on-ink .btn--solid:hover { background: var(--c-metal-on-ink); }
.on-ink .btn--ghost { border-color: var(--c-line-on-ink); color: var(--c-on-ink); }
.on-ink .btn--ghost:hover { border-color: var(--c-on-ink); background: var(--c-on-ink); color: var(--c-ink); }

/* Text link with a rule that draws on hover. */
.link-rule {
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-height: 44px;
  font-size: var(--t-sm); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-wide); text-transform: uppercase;
  color: var(--c-metal-text); position: relative;
}
.on-ink .link-rule { color: var(--c-metal-on-ink); }
.link-rule::after {
  content: ''; position: absolute; left: 0; bottom: 12px;
  width: 100%; height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}
.link-rule:hover::after, .link-rule:focus-visible::after { transform: scaleX(1); }

/* ---------- LEVEL SWATCHES --------------------------------- */
/* Colour-ramp swatches. The full ten-step chart that used to sit in
   the hero foot rail is gone, but these are still the paint for the
   three-swatch rails on the pathway cards (.pathway__rail span sets
   the geometry, these set the colour). Do not delete without checking
   .pathway__rail first. */
.lv1{background:var(--level-1)} .lv2{background:var(--level-2)} .lv3{background:var(--level-3)}
.lv4{background:var(--level-4)} .lv5{background:var(--level-5)} .lv6{background:var(--level-6)}
.lv7{background:var(--level-7)} .lv8{background:var(--level-8)} .lv9{background:var(--level-9)}
.lv10{background:var(--level-10)}

/* ---------- HEADER / NAVIGATION ---------------------------- */
.site-header {
  position: fixed; inset-inline: 0; top: 0; z-index: var(--z-nav);
  background: color-mix(in srgb, var(--c-paper) 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: var(--bw-hair) solid var(--c-line);
  transition:
    background var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}

/* ---------- header over the hero ----------
   At the top of the page the bar dissolves into the photograph: no
   panel, no blur, no rule, white type. It returns to the frosted bar
   the moment the hero has scrolled past.

   It has to return. The header is position:fixed over a page that is
   mostly bone and white below the fold, so white type held all the way
   down would be invisible against most of the site. `is-atop` is added
   by main.js only while the hero is actually behind the bar.

   `on-ink` is added alongside it rather than restating anything: the
   inverted button, rule and text colours already exist under that
   class, and this reuses them. The background it would paint is
   overridden here — .site-header.is-atop outweighs .on-ink. */
.site-header.is-atop {
  background: transparent;
  backdrop-filter: none;
  border-bottom-color: transparent;
  color: var(--c-on-ink);
}
.site-header.is-atop .nav a { color: var(--c-on-ink); }
.site-header.is-atop .nav a:hover { color: #fff; }

/* The wordmark is black ink with alpha derived from its own luminance,
   so on a dark hero it would be a black mark on a black photograph.
   invert(1) turns the ink white and leaves the alpha — and therefore
   the anti-aliasing on those thin strokes — untouched. */
.site-header.is-atop .wordmark img { filter: invert(1); }

.site-header.is-atop .icon-btn {
  border-color: var(--c-line-on-ink);
  color: var(--c-on-ink);
}
.site-header.is-atop .icon-btn:hover {
  background: var(--c-on-ink); color: var(--c-ink); border-color: var(--c-on-ink);
}
.site-header.is-atop .icon-btn--bare { border-color: transparent; }
.site-header.is-atop .icon-btn--bare:hover {
  background: none; color: var(--c-metal-on-ink);
}
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-5);
  /* The single source of truth, declared with scroll-padding-top at the
     top of this file. Changing the header's height there moves the
     anchor offset with it. */
  min-height: var(--header-h);
}
/* No breakpoint override here any more — --header-h changes at 1024
   and this reads it, so the header and the scroll offset cannot get
   out of step. */

.wordmark {
  font-family: var(--font-ui);
  font-size: var(--t-sm); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-label); text-transform: uppercase;
  display: inline-flex; align-items: center; min-height: 44px;
  white-space: nowrap;
}
.wordmark b { font-weight: var(--fw-medium); }
.wordmark span { color: var(--c-metal-text); }
/* Wordmark: the salon's real logo image, sized to the bar. */
.wordmark picture { display: block; }
.wordmark img { height: 30px; width: auto; }
@media (min-width: 1024px) { .wordmark img { height: 40px; } }


.nav { display: none; }
@media (min-width: 1024px) {
  .nav { display: flex; align-items: center; gap: clamp(14px, 1.6vw, 30px); }
}
.nav a {
  position: relative; display: inline-flex; align-items: center;
  min-height: 44px; padding-inline: 2px;
  font-size: var(--t-2xs); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-wide); text-transform: uppercase;
  color: var(--c-ink-2);
  transition: color var(--dur-fast) var(--ease-out);
}
.nav a:hover { color: var(--c-ink); }
.nav a::after {
  content: ''; position: absolute; left: 0; bottom: 20px; width: 100%; height: 1px;
  background: var(--c-metal); transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}
.nav a:hover::after, .nav a:focus-visible::after { transform: scaleX(1); }

.header-actions { display: flex; align-items: center; gap: var(--s-2); }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-width: 48px; min-height: 48px; padding-inline: var(--s-3);
  font-size: var(--t-2xs); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-wide); text-transform: uppercase;
  border: var(--bw-hair) solid var(--c-line-strong);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.icon-btn:hover { background: var(--c-ink); color: var(--c-paper); border-color: var(--c-ink); }
.icon-btn--bare { border-color: transparent; }
.icon-btn--bare:hover { background: none; color: var(--c-metal-text); }
.cart-count { font-variant-numeric: tabular-nums; }

.nav-book { display: none; }
@media (min-width: 768px) { .nav-book { display: inline-flex; } }
.menu-toggle { display: inline-flex; }
@media (min-width: 1024px) { .menu-toggle { display: none; } }

.burger { width: 18px; height: 10px; position: relative; }
.burger::before, .burger::after {
  content: ''; position: absolute; left: 0; width: 100%; height: 1px;
  background: currentColor; transition: transform var(--dur-base) var(--ease-out);
}
.burger::before { top: 0; }
.burger::after  { bottom: 0; }
[aria-expanded="true"] .burger::before { transform: translateY(4.5px) rotate(45deg); }
[aria-expanded="true"] .burger::after  { transform: translateY(-4.5px) rotate(-45deg); }

/* Mobile menu panel */
.menu-panel {
  position: fixed; inset: 0; z-index: var(--z-drawer);
  background: var(--c-ink-ground); color: var(--c-on-ink);
  display: flex; flex-direction: column;
  padding: 88px var(--page-pad) var(--s-9);
  overflow-y: auto;
  opacity: 0; visibility: hidden;
  /* visibility is discrete and would otherwise flip at 50% of the
     fade — too late to move focus into the panel. Delay it on close,
     apply it instantly on open. */
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s var(--dur-base);
}
.menu-panel[data-open="true"] {
  opacity: 1; visibility: visible;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s;
}
.menu-panel__list { display: flex; flex-direction: column; margin-top: var(--s-6); }
.menu-panel__list a {
  display: flex; align-items: baseline; gap: var(--s-4);
  padding-block: var(--s-4);
  border-bottom: var(--bw-hair) solid var(--c-line-on-ink);
  font-family: var(--font-display); font-size: var(--t-xl);
  line-height: var(--lh-snug);
}
.menu-panel__list a .num { flex: none; }
.menu-panel__foot { margin-top: auto; padding-top: var(--s-9); display: grid; gap: var(--s-3); }

/* ---------- HERO ------------------------------------------- */
.hero {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column;
  background: var(--c-ink-ground); color: var(--c-on-ink);
  overflow: hidden;
  padding-top: 72px;
}
/* Mobile: media in normal flow as a band. */
.hero-media { position: relative; height: 46svh; min-height: 240px; }
@media (min-width: 768px) {
  .hero {
    min-height: min(92svh, 940px);
    justify-content: flex-end;
    padding-top: 132px;
  }
  .hero-media { position: absolute; height: auto; min-height: 0; }
}
.hero-media { inset: 0; z-index: var(--z-below); }
/* <picture> is a block with auto height, so a percentage height on
   the img inside it has nothing to resolve against. Give the
   wrapper the height explicitly wherever the img must fill. */
.hero-media picture { display: block; width: 100%; height: 100%; }
.hero-media img { width: 100%; height: 100%; object-fit: cover; }
/* MOBILE: the photograph is a defined band and the copy sits on
   solid ink beneath it. Type over a bright, high-key photograph
   cannot be made to clear AA at any scrim strength that still
   leaves a photograph visible — so the two are separated instead
   of stacked. DESKTOP: full-bleed cinematic, copy on the heavily
   scrimmed left third. */
.hero-media::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(14,13,11,0.96) 0%, rgba(14,13,11,0.28) 55%, rgba(14,13,11,0.16) 100%);
}
@media (min-width: 768px) {
  .hero-media::after {
    background:
      linear-gradient(to right, rgba(14,13,11,0.96) 0%, rgba(14,13,11,0.86) 42%, rgba(14,13,11,0.28) 100%),
      linear-gradient(to top, rgba(14,13,11,0.90) 0%, rgba(14,13,11,0.34) 52%, rgba(14,13,11,0.58) 100%);
  }
}
/* The champagne accent cannot clear AA over the photograph even under a
   heavy scrim (measured 2.7:1). In the hero only, the kicker runs bone. */
.hero .kicker { color: var(--c-on-ink); }
.hero__body { padding-top: var(--s-8); padding-bottom: var(--s-9); }
@media (min-width: 768px) { .hero__body { padding-top: 0; } }
.hero__title { font-size: var(--t-5xl); line-height: 0.94; letter-spacing: var(--tr-tight); }
.hero__title .italic { display: block; }
.hero__lede { margin-top: var(--s-6); max-width: 46ch; }
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-8); }
/* Stacked buttons match width; ragged edges read as an accident. */
.hero__cta .btn { flex: 1 1 100%; }
@media (min-width: 560px) { .hero__cta .btn { flex: 0 0 auto; } }
/* on-ink-2, not -3: this sits over photography on desktop and the
   muted tone cannot clear AA there. */
.hero__note { margin-top: var(--s-5); font-size: var(--t-xs); color: var(--c-on-ink-2); max-width: 52ch; }
.hero__note a { color: var(--c-metal-on-ink); text-decoration: underline; text-underline-offset: 3px; }

/* Hero foot rail: the locator line under the hero copy. It used to
   carry a second column for the colour level chart; with that removed
   the rail is a single full-width track, so no empty column or gap is
   reserved at desktop widths. */
.hero__rail {
  border-top: var(--bw-hair) solid var(--c-line-on-ink);
  display: grid; grid-template-columns: 1fr; gap: var(--s-4);
  padding-block: var(--s-5);
}
.hero__rail dl { display: flex; flex-wrap: wrap; gap: var(--s-6) var(--s-9); }
/* Scoped to the list so it only formats the dt/dd pairs. */
.hero__rail dl > div { display: grid; gap: 2px; }
.hero__rail dt { font-size: var(--t-3xs); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--c-on-ink-3); }
.hero__rail dd { font-family: var(--font-display); font-size: var(--t-lg); }

/* ---------- PROOF BAND ------------------------------------- */
.proof {
  display: grid; grid-template-columns: 1fr; gap: var(--s-6);
  align-items: center;
}
@media (min-width: 768px)  { .proof { grid-template-columns: repeat(3, 1fr); gap: var(--s-7); } }
.proof__item { display: grid; gap: var(--s-2); }
.proof__item dt { font-size: var(--t-3xs); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--c-metal-on-ink); }
.proof__item dd { font-family: var(--font-display); font-size: var(--t-lg); line-height: var(--lh-snug); }
.proof__item p  { font-size: var(--t-xs); color: var(--c-on-ink-3); }

.marquee { overflow: hidden; border-block: var(--bw-hair) solid var(--c-line-on-ink); padding-block: var(--s-4); }
.marquee__track {
  display: flex; gap: var(--s-11); width: max-content;
  animation: marquee 44s var(--ease-linear) infinite;
}
.marquee__track span {
  font-size: var(--t-2xs); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--c-on-ink-3); white-space: nowrap;
}
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .marquee { overflow-x: auto; }
  .marquee__track { animation: none; }
}

/* ---------- ARCHIVE WALL (staggered media grid) ------------ */
/* An editorial grid of equal-width columns. Cards share a width but
   NOT a height: each photograph keeps its own proportions, so nothing
   is cropped to fit and nothing is letterboxed inside an oversized
   frame. Row bottoms are therefore slightly ragged — that is the
   trade for showing every hairstyle whole.

   `align-items: start` pins every card to the top of its row, so a
   taller photograph or a two-line caption lengthens only its own card
   and never nudges its neighbours. `minmax(0, 1fr)` stops a long
   unbroken word in a caption from widening its column.
   Columns: 2 on mobile, 4 from 1024. */
.archive {
  /* One knob for the gallery's image border — the only paint in the
     whole card stack. Override per client in theme.css. */
  --gallery-border-color: var(--c-line);
  display: grid;
  /* TWO COLUMNS FROM THE NARROWEST SCREEN, not one.
     One column of 60 colour studies is around nine screenfuls of
     scrolling on a phone to see what fits on one laptop page. It also
     makes each card full-bleed, which asks for ~1080 device pixels on
     a 3x display — so the browser fetches the 1200px original and the
     visitor waits for detail their thumb is covering. Two columns
     halves the scrolling AND drops each card to the 800px variant.
     Tapping still opens the full image in the dialog, which is where
     the detail is actually wanted. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-3);
  align-items: start;
}
@media (min-width: 480px)  { .archive { gap: var(--s-4); } }
@media (min-width: 768px)  { .archive { gap: var(--s-5); } }
@media (min-width: 1024px) { .archive { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ============================================================
   FOLDERS — the archive's landing layer
   ------------------------------------------------------------
   A wall of covers, one per family that has work in it. Clicking
   one drops that family's plates in underneath it.

   The whole "expand in place" behaviour is this grid plus one
   rule, with no JavaScript layout maths: the tile and its panel
   are SIBLINGS, both direct children of .folders, and the panel
   spans every column. Auto-placement then puts the panel on the
   line below its own tile and pushes the rest down. A closed
   panel carries [hidden], so it is display:none and takes part
   in nothing.
   ============================================================ */
.folders {
  display: grid;
  /* TWO COLUMNS ON PHONES, not one.
     These are the folder COVERS, not the plates inside an opened
     folder. One column made each cover full-bleed and taller than a
     phone viewport, so the archive alone ran to 8.5 screenfuls —
     about a third of the whole page — before a visitor had opened
     anything. Two columns turns that into a contact sheet you can
     scan, which is what a cover is for. Opening a folder is
     unaffected. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-3);
  align-items: start;
}
@media (min-width: 480px)  { .folders { gap: var(--s-4); } }
@media (min-width: 768px)  { .folders { gap: var(--s-5); } }
@media (min-width: 1024px) { .folders { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* The heading exists for document structure — the folder list should
   read as headings to a screen reader — but must not impose type
   styling or spacing on the tile inside it. */
.folder__h { margin: 0; font: inherit; }

.folder {
  display: grid;
  gap: var(--s-3);
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  color: inherit;
}

/* Deliberately taller than the square plates below. The cover is a
   portrait of a person, and 4:5 keeps a head and the length of the
   hair in frame where a square would cut one or the other. It also
   stops a cover reading as just another plate. */
.folder__shot {
  display: block;
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--c-paper);
  outline: var(--bw-hair) solid var(--gallery-border-color, var(--c-line));
  outline-offset: calc(-1 * var(--bw-hair));
}
.folder__shot picture { display: block; width: 100%; height: 100%; }
.folder__shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Same --focus contract as .plate img, so a cover crop is tuned in
     the archive data and not in CSS. */
  object-position: var(--focus, center);
}

.folder__bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  min-width: 0;
}
.folder__name {
  font-family: var(--font-display);
  font-size: var(--t-base);
  line-height: var(--lh-snug);
  min-width: 0;
}
.folder__count {
  flex: none;
  font-size: var(--t-3xs);
  letter-spacing: var(--tr-wide);
  color: var(--c-ink-3);
  font-variant-numeric: tabular-nums;
}
.on-ink .folder__count { color: var(--c-on-ink-3); }

/* The open/closed affordance. A rule that grows across the label is
   quieter than a chevron and matches the .link-rule idiom used
   elsewhere; transform-only, so it never reflows the row. */
.folder__name { position: relative; }
.folder__name::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  border-bottom: var(--bw-hair) solid currentColor;
  transform: scaleX(0);
  transform-origin: left;
  /* tokens.css already collapses every --dur-* to 1ms under
     prefers-reduced-motion, so this needs no media query of its own. */
  transition: transform var(--dur-fast) ease;
}
.folder:hover .folder__name::after,
.folder:focus-visible .folder__name::after,
.folder[aria-expanded='true'] .folder__name::after { transform: scaleX(1); }

.folder[aria-expanded='true'] .folder__shot {
  outline-color: currentColor;
}

/* The one rule that makes it an accordion. */
.folder__panel {
  grid-column: 1 / -1;
  padding-top: var(--s-2);
}

.plate { position: relative; display: grid; gap: var(--s-3); }

/* The button is a pass-through: it wraps the frame for keyboard use
   and contributes no size, spacing or paint of its own. */
.plate__open {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
}

/* THE FRAME. One square, one border, identical on every card — the
   border lives here rather than on the <img> so all four edges are
   the same box at every breakpoint, whatever the photograph's own
   proportions. `aspect-ratio: 1/1` plus `box-sizing: border-box`
   means the frame is exactly one column wide and exactly as tall,
   so caption length can never alter an image's dimensions. */
.plate figure {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: var(--bw-hair) solid var(--gallery-border-color);
  box-sizing: border-box;
  background: transparent;
}

/* <picture> fills the frame so the image has a definite box to cover. */
.plate picture {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
}

/* The photograph fills the frame edge to edge — `cover` guarantees no
   strip and no empty space, at the cost of trimming whatever does not
   fit the square. Centre is the default; a frame that would lose the
   face or the ends of the hair sets `--focus` in the archive data
   (e.g. `focus: 'center 25%'`) and this one shared rule reads it. No
   per-card CSS. */
.plate img {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  object-fit: cover;
  object-position: var(--focus, center);
  box-sizing: border-box;
}
/* Stacked, not a space-between row: in a narrow column the two halves
   of a row collide and overflow into the neighbour. Sits directly
   under the frame, so title and meta stay tied to their image. */
.plate figcaption { display: grid; gap: 2px; min-width: 0; }
.plate__title { font-family: var(--font-display); font-size: var(--t-base); line-height: var(--lh-snug); min-width: 0; }
.plate__meta  { font-size: var(--t-3xs); letter-spacing: var(--tr-wide); text-transform: uppercase; color: var(--c-ink-3); min-width: 0; }
.on-ink .plate__meta { color: var(--c-on-ink-3); }

/* No forced ratio on the frame. Each photograph keeps its own
   proportions, so nothing is cropped and nothing is letterboxed; the
   cards in a row top-align and their bottoms sit where the picture
   ends. Space is still reserved before load from the width/height
   attributes on every <img>, so there is no layout shift. */

/* ---------- SPLIT FEATURE (overlapping media) -------------- */
.split {
  display: grid; grid-template-columns: 1fr; gap: var(--s-8);
  align-items: center;
}
@media (min-width: 1024px) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(40px, 5vw, 88px); }
  .split--reverse > :first-child { order: 2; }
}
.split__media { position: relative; }
.split__media img { width: 100%; aspect-ratio: var(--ar, var(--ar-landscape)); object-fit: cover; }
.split__stack { display: grid; gap: var(--s-5); }

/* Philosophy: quiet section with an architectural ground. */
.philosophy { position: relative; isolation: isolate; overflow: hidden; }
.philosophy::before {
  content: ''; position: absolute; inset: 0; z-index: var(--z-below);
  background-size: cover; background-position: center;
  opacity: 0.42;
}
.philosophy::after {
  content: ''; position: absolute; inset: 0; z-index: var(--z-below);
  background: linear-gradient(to bottom, var(--c-paper), color-mix(in srgb, var(--c-bone) 82%, transparent));
}

/* Numbered credo rows */
.credo { display: grid; gap: 0; border-top: var(--bw-hair) solid var(--c-line); }
/* Three children — .num, h3, .body — in a two-column grid below 768px.
   `auto 1fr` put the BODY in column one, where `auto` sized that column
   to the paragraph: 394px of it, leaving the heading 35px in column
   two and breaking it one word per line. `auto` means "as wide as my
   content", and the widest content in that column was never the number.

   So the number keeps its own column and both the heading and the body
   share the second one. minmax(0,1fr) rather than 1fr because a grid
   track's default minimum is min-content, which a long unbroken word
   would push past the viewport. */
.credo li {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s-3) var(--s-4);
  padding-block: var(--s-5);
  border-bottom: var(--bw-hair) solid var(--c-line);
}
.credo li .body { grid-column: 2; }
@media (min-width: 768px) {
  .credo li { grid-template-columns: 56px minmax(0,1fr) minmax(0,1.15fr); gap: var(--s-6); align-items: baseline; }
  /* Back to auto-placement: at three columns the body belongs in the
     third, beside the heading rather than beneath it. Without this
     reset the rule above would pin it under the heading and leave
     column three empty. */
  .credo li .body { grid-column: auto; }
}
.credo h3 { font-size: var(--t-md); line-height: var(--lh-snug); }

/* ---------- PATHWAY CARDS (service discovery) -------------- */
.pathways { display: grid; gap: var(--s-5); grid-template-columns: 1fr; }
@media (min-width: 768px)  { .pathways { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .pathways { grid-template-columns: repeat(4, 1fr); gap: var(--bw-hair); background: var(--c-line); border: var(--bw-hair) solid var(--c-line); } }

.pathway {
  display: flex; flex-direction: column; gap: var(--s-4);
  padding: var(--s-6) 0;
  border-top: var(--bw-hair) solid var(--c-line);
  background: var(--c-paper);
  transition: background var(--dur-base) var(--ease-out);
}
@media (min-width: 1024px) { .pathway { padding: var(--s-7) var(--s-6); border-top: none; } .pathway:hover { background: var(--c-bone); } }
.pathway__rail { display: flex; }
.pathway__rail span { height: 4px; flex: 1; }
.pathway h3 { font-size: var(--t-lg); }
.pathway__list { display: grid; gap: var(--s-3); margin-top: auto; }
.pathway__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4);
  font-size: var(--t-sm); color: var(--c-ink-2);
  padding-bottom: var(--s-2); border-bottom: var(--bw-hair) solid var(--c-line);
}
.pathway__row b { font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; color: var(--c-ink); white-space: nowrap; }

/* ---------- STEPS (consultation) --------------------------- */
.steps { display: grid; gap: var(--s-6); grid-template-columns: 1fr; counter-reset: step; }
@media (min-width: 768px)  { .steps { grid-template-columns: repeat(2, 1fr); gap: var(--s-8); } }
@media (min-width: 1024px) { .steps { grid-template-columns: repeat(4, 1fr); } }
.step { display: grid; gap: var(--s-3); align-content: start; padding-top: var(--s-4); border-top: var(--bw-hair) solid var(--c-line-on-ink); }
.step h3 { font-size: var(--t-md); }

/* ---------- SHOP ------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-7); }
.chip {
  min-height: 44px; padding: var(--s-2) var(--s-5);
  font-size: var(--t-2xs); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-wide); text-transform: uppercase;
  border: var(--bw-hair) solid var(--c-line-strong);
  color: var(--c-ink-2);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.chip:hover { border-color: var(--c-ink); color: var(--c-ink); }
.chip[aria-pressed="true"] { background: var(--c-ink); color: var(--c-paper); border-color: var(--c-ink); }

/* ---------- BRAND TILES ------------------------------------
   The picture-tile rendering of the same filter control. Used when
   the filter data carries an `img`; .chip is the fallback when it
   doesn't. Both are [data-filter] buttons, so only the skin differs.

   One column fewer than .product-grid at every breakpoint. The tiles
   are landscape where the products are portrait, and matching the
   product column count made them small enough to lose the shelf. */
.brands { display: grid; gap: var(--s-4); grid-template-columns: repeat(2, 1fr); margin-bottom: var(--s-7); }
@media (min-width: 768px)  { .brands { grid-template-columns: repeat(3, 1fr); gap: var(--s-5); } }
@media (min-width: 1024px) { .brands { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1920px) { .brands { grid-template-columns: repeat(6, 1fr); } }

.brand {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: 0; text-align: left; background: none; border: 0;
  cursor: pointer;
}
.brand__shot {
  display: block; position: relative; overflow: hidden;
  /* Square, where .product__shot is 4:5. The hero is a packshot like the
     cards below it, so the aspect is the only thing separating a brand
     from a product at a glance — and a square gives a tall bottle and a
     wide jar the same room. */
  aspect-ratio: var(--ar-square);
  background: var(--c-paper);
  padding: var(--s-5);
  outline: var(--bw-hair) solid var(--c-line);
  outline-offset: calc(-1 * var(--bw-hair));   /* inside the box, so it can't shift layout on select */
}
.brand__shot picture { display: block; width: 100%; height: 100%; }
/* No blend, matching .product__shot — see the note there. */
.brand__shot img {
  width: 100%; height: 100%; object-fit: contain;
  transition: transform var(--dur-slow) var(--ease-out);
}
/* Unselected tiles sit back so the chosen one reads as chosen; the
   veil is on the shot, not the whole tile, to keep the label legible.
   Kept light — only ever one tile is selected, so the veil is what the
   grid mostly looks like, and anything heavier reads as milky rather
   than as recessive. */
.brand__shot::after {
  content: ""; position: absolute; inset: 0;
  background: var(--c-paper); opacity: .26;
  transition: opacity var(--dur-fast) var(--ease-out);
  pointer-events: none;
}
.brand:hover .brand__shot::after,
.brand:focus-visible .brand__shot::after { opacity: .06; }
.brand:hover .brand__shot img { transform: scale(1.04); }
.brand[aria-pressed="true"] .brand__shot::after { opacity: 0; }
.brand[aria-pressed="true"] .brand__shot { outline: var(--bw-thick) solid var(--c-ink); }

.brand__name {
  font-size: var(--t-2xs); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-wide); text-transform: uppercase;
  color: var(--c-ink-2);
  transition: color var(--dur-fast) var(--ease-out);
}
.brand:hover .brand__name,
.brand[aria-pressed="true"] .brand__name { color: var(--c-ink); }
.brand__count { font-size: var(--t-3xs); letter-spacing: var(--tr-label); color: var(--c-metal-text); }

@media (prefers-reduced-motion: reduce) {
  .brand__shot img { transition: none; }
  .brand:hover .brand__shot img { transform: none; }
}

.product-grid { display: grid; gap: var(--s-5); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 768px)  { .product-grid { grid-template-columns: repeat(3, 1fr); gap: var(--s-6); } }
@media (min-width: 1024px) { .product-grid { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1920px) { .product-grid { grid-template-columns: repeat(6, 1fr); } }

.product {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding-top: var(--s-4);
  border-top: var(--bw-hair) solid var(--c-line);
}
.product__shot {
  aspect-ratio: var(--ar-portrait);
  /* White, not bone, and no multiply — see the note on .product__shot img
     below. The tile has to match the ground the packshots are shot on,
     and the only ground they share is white. */
  background: var(--c-paper);
  /* Block, not grid. As a grid the image was auto-placed into an
     implicit row that sized to its own content, so it never took the
     frame's height and ran past the bottom edge — `overflow: hidden`
     then sheared the base off most of the bottles. A plain block with
     a definite height (aspect-ratio + border-box) gives the wrappers
     below something real to resolve `height: 100%` against. */
  display: block; padding: var(--s-5);
  margin-bottom: var(--s-3);
  overflow: hidden;
}
/* <picture> is a block with auto height; without this the shot box
   grows to the image intrinsic height and the grid goes ragged. */
.product__shot picture, .line-item__shot picture { display: contents; }
/* Both shot frames now have a definite height, so <picture> becomes a
   real block that fills the frame and passes that height down to the
   image. (.line-item__shot picture is overridden the same way further
   down, next to its own rules.) */
.product__shot picture { display: block; width: 100%; height: 100%; }
/* Fill the padded frame and let `contain` do the fitting.
   This was `max-height: 100%; width: auto`, which looks right but is a
   circular percentage: the grid row is sized by its content, so a
   percentage max-height against that row resolves to `none`. The
   `height` attribute on every <img> then won, giving a 211x500 box
   inside a 251x314 frame — and `overflow: hidden` sheared the bottom
   off 56 of the 61 shots (31% of the photograph on average, 41% at
   worst). A definite width AND height make the box the frame, so
   `contain` fits the whole bottle, jar or box inside it. */
/* `mix-blend-mode: multiply` used to sit here. It was the right call for
   61 packshots that all came from one source on one white ground: multiply
   drops white out, so a bottle floated on the bone tile with no seam.

   It does not survive a 205-product catalogue drawn from six brands'
   photography. Multiply darkens whatever it touches, so Oribe's charcoal
   Gold Lust seamless became a black block and OUAI's warm beige became a
   dirty square. Knocking those backgrounds out programmatically was tried
   and abandoned — it destroyed pale products.

   White ground, no blend: every packshot renders exactly as its brand
   shot it. The 132 on white are seamless; the rest show their own
   backdrop, which is honest and is how the brands themselves show them. */
.product__shot img { width: 100%; height: 100%; object-fit: contain; transition: transform var(--dur-slow) var(--ease-out); }
.product:hover .product__shot img { transform: scale(1.04); }
.product__brand { font-size: var(--t-3xs); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--c-metal-text); }
.product__name { font-family: var(--font-display); font-size: var(--t-base); line-height: var(--lh-snug); }
.product__desc { font-size: var(--t-xs); color: var(--c-ink-3); flex-grow: 1; }
.product__foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); margin-top: var(--s-4); }
.product__price { font-size: var(--t-sm); font-variant-numeric: tabular-nums; }
.add-btn {
  min-height: 44px; padding: var(--s-2) var(--s-5);
  font-size: var(--t-2xs); font-weight: var(--fw-medium);
  letter-spacing: var(--tr-wide); text-transform: uppercase;
  border: var(--bw-hair) solid var(--c-ink); color: var(--c-ink);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.add-btn:hover { background: var(--c-ink); color: var(--c-paper); }
.add-btn[data-added="true"] { background: var(--c-metal-text); border-color: var(--c-metal-text); color: var(--c-paper); }
.shop-note { margin-top: var(--s-7); font-size: var(--t-xs); color: var(--c-ink-3); max-width: var(--w-text); }

/* ---------- REVIEWS / AWARDS ------------------------------- */
.awards { display: grid; gap: var(--bw-hair); background: var(--c-line-on-ink); border: var(--bw-hair) solid var(--c-line-on-ink); }
@media (min-width: 768px) { .awards { grid-template-columns: repeat(3, 1fr); } }
.award { background: var(--c-ink-ground); padding: var(--s-6); display: grid; gap: var(--s-2); align-content: start; }
.award h3 { font-size: var(--t-md); line-height: var(--lh-snug); }

.review-slot {
  display: grid; gap: var(--s-4); align-content: center;
  padding: var(--s-7) 0;
}
.review-slot blockquote { font-family: var(--font-display); font-size: var(--t-xl); line-height: var(--lh-snug); }

/* ---------- FULL-BLEED FEATURE ----------------------------- */
.feature { position: relative; }
.feature__media img { width: 100%; aspect-ratio: var(--ar-wide); object-fit: cover; }
@media (max-width: 767px) { .feature__media img { aspect-ratio: var(--ar-landscape); } }
.feature__card {
  background: var(--c-ink-ground); color: var(--c-on-ink);
  padding: var(--s-7); display: grid; gap: var(--s-4);
}
@media (min-width: 1024px) {
  .feature__card {
    position: absolute; right: var(--page-pad); bottom: calc(var(--s-9) * -1);
    width: min(430px, 38vw); padding: var(--s-9);
  }
  .feature { margin-bottom: var(--s-9); }
}

/* ---------- LOCATION / HOURS ------------------------------- */
.hours { display: grid; gap: 0; }
.hours div {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-5);
  padding-block: var(--s-3);
  border-bottom: var(--bw-hair) solid var(--c-line);
  font-size: var(--t-sm);
}
.hours dt { color: var(--c-ink-2); }
.hours dd { font-variant-numeric: tabular-nums; }
.hours div[data-closed="true"] dd { color: var(--c-ink-3); }

.contact-block { display: grid; gap: var(--s-3); }
.contact-block a { display: inline-flex; align-items: center; min-height: 44px; }

/* ---------- FOOTER ----------------------------------------- */
.site-footer { background: var(--c-ink-ground); color: var(--c-on-ink); padding-block: var(--section-y) var(--s-7); }
.footer-grid { display: grid; gap: var(--s-8); grid-template-columns: 1fr; }
@media (min-width: 768px)  { .footer-grid { grid-template-columns: repeat(2, 1fr); gap: var(--s-9); } }
@media (min-width: 1024px) { .footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1.2fr; } }
.footer-col h2 { font-family: var(--font-ui); font-size: var(--t-3xs); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--c-metal-on-ink); margin-bottom: var(--s-4); }
.footer-col ul { display: grid; gap: 2px; }
.footer-col a { display: inline-flex; align-items: center; min-height: 44px; font-size: var(--t-sm); color: var(--c-on-ink-2); transition: color var(--dur-fast) var(--ease-out); }
.footer-col a:hover { color: var(--c-on-ink); }
.footer-mark { font-family: var(--font-display); font-size: var(--t-2xl); line-height: var(--lh-tight); }
.footer-bottom {
  margin-top: var(--s-11); padding-top: var(--s-5);
  border-top: var(--bw-hair) solid var(--c-line-on-ink);
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-7);
  justify-content: space-between;
  font-size: var(--t-3xs); color: var(--c-on-ink-3);
}

/* Staff entrance. It sits in the footer's quietest row on purpose —
   this is for the people who work here, not for visitors — but it is
   still a link, so it gets an underline on hover and a real focus ring
   rather than being styled down into invisibility. */
.footer-staff {
  color: var(--c-on-ink-3);
  text-decoration: none;
  border-bottom: var(--bw-hair) solid transparent;
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.footer-staff:hover,
.footer-staff:focus-visible {
  color: var(--c-on-ink);
  border-bottom-color: currentColor;
}

/* ---------- CART DRAWER (dialog) --------------------------- */
.overlay {
  position: fixed; inset: 0; z-index: var(--z-overlay);
  background: rgba(14, 13, 11, 0.55);
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-out);
}
.overlay[data-open="true"] { opacity: 1; pointer-events: auto; }

.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: var(--z-drawer);
  width: min(440px, 100vw);
  background: var(--c-paper);
  border-left: var(--bw-hair) solid var(--c-line);
  box-shadow: var(--shadow-panel);
  display: flex; flex-direction: column;
  transform: translateX(100%);
  visibility: hidden;
  transition: transform var(--dur-slow) var(--ease-out), visibility 0s var(--dur-slow);
}
.drawer[data-open="true"] {
  transform: translateX(0); visibility: visible;
  transition: transform var(--dur-slow) var(--ease-out), visibility 0s;
}
.drawer__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding: var(--s-5) var(--s-6);
  border-bottom: var(--bw-hair) solid var(--c-line);
}
.drawer__head h2 { font-size: var(--t-lg); }
.drawer__items { flex: 1; overflow-y: auto; padding-inline: var(--s-6); }
.drawer__empty { padding-block: var(--s-12); text-align: center; color: var(--c-ink-3); font-size: var(--t-sm); }
.line-item {
  display: grid; grid-template-columns: 64px 1fr auto; gap: var(--s-4);
  padding-block: var(--s-5);
  border-bottom: var(--bw-hair) solid var(--c-line);
  align-items: start;
}
/* Same defect as .product__shot, same fix: as a grid with a
   content-sized row the 500px-tall shot images forced this 64px square
   open to 516px, so every bag row was roughly eight times too tall.
   A block with a definite height, and an image that fills it. */
.line-item__shot { background: var(--c-bone); aspect-ratio: var(--ar-square); display: block; padding: var(--s-2); overflow: hidden; }
.line-item__shot picture { display: block; width: 100%; height: 100%; }
.line-item__shot img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.line-item__brand { font-size: var(--t-3xs); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--c-metal-text); }
.line-item__name { font-family: var(--font-display); font-size: var(--t-sm); line-height: var(--lh-snug); margin-bottom: var(--s-2); }
.line-item__price { font-size: var(--t-sm); font-variant-numeric: tabular-nums; white-space: nowrap; }
.qty { display: inline-flex; align-items: center; border: var(--bw-hair) solid var(--c-line-strong); }
.qty button { min-width: 36px; min-height: 36px; display: grid; place-items: center; font-size: var(--t-sm); }
.qty button:hover { background: var(--c-bone); }
.qty output { min-width: 34px; text-align: center; font-size: var(--t-sm); font-variant-numeric: tabular-nums; }
.line-item__remove { font-size: var(--t-3xs); letter-spacing: var(--tr-wide); text-transform: uppercase; color: var(--c-ink-3); text-decoration: underline; text-underline-offset: 3px; min-height: 44px; }
.line-item__remove:hover { color: var(--c-ink); }
.drawer__foot { padding: var(--s-5) var(--s-6) var(--s-6); border-top: var(--bw-hair) solid var(--c-line); display: grid; gap: var(--s-4); }
.drawer__total { display: flex; align-items: baseline; justify-content: space-between; font-size: var(--t-md); }
.drawer__total b { font-family: var(--font-display); font-variant-numeric: tabular-nums; }
.drawer__note { font-size: var(--t-xs); color: var(--c-ink-3); }

body[data-locked="true"] { overflow: hidden; }

/* ---------- STATUS / LIVE REGIONS -------------------------- */
.sr-status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* ---------- ULTRAWIDE -------------------------------------- */
@media (min-width: 1920px) {
  :root { --page-pad: clamp(56px, 5vw, 120px); }
  .hero__title { font-size: clamp(6rem, 5.6vw, 9rem); }
  .hero { min-height: min(88svh, 1040px); }
}

/* ============================================================
   STAGE 3 — ARTISTS, SERVICE FINDER, THE COLOR ARCHIVE
   ============================================================ */

/* ---------- ARCHIVE: filters, featured frames, open button --- */
.chip__count {
  font-size: var(--t-3xs); opacity: 0.6; font-variant-numeric: tabular-nums;
  margin-left: var(--s-1);
}
.archive__empty {
  color: var(--c-ink-3); font-size: var(--t-sm);
  padding-block: var(--s-11); text-align: center;
}
/* The whole frame is the control. A button wrapper keeps it
   keyboard-reachable and named, without nesting interactives.
   Its box is reset with the other wrappers above — this rule adds
   only the affordance, so there is one source of truth for sizing. */
.plate__open { cursor: zoom-in; }
/* `.plate--featured` carries no styling of its own. It once spanned all
   columns, then wore a champagne hairline on the <figure>; both are gone
   so that every photograph has one consistent border, on the image
   itself. The class and the `featured` data flag are still emitted, so
   an emphasis can be reintroduced here later — as a border-COLOUR
   change on `.plate--featured img`, never as a second border or a rule
   on a wrapper, which is what produced the detached edges. */

/* ---------- LIGHTBOX ---------------------------------------- */
.lightbox {
  position: fixed; inset: 0; z-index: var(--z-drawer);
  background: var(--c-ink-ground); color: var(--c-on-ink);
  display: grid; grid-template-rows: auto 1fr auto;
  padding: var(--s-4) var(--page-pad) var(--s-6);
  overflow-y: auto;
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s var(--dur-base);
}
.lightbox[data-open="true"] {
  opacity: 1; visibility: visible;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s;
}
.lightbox :focus-visible { outline-color: var(--c-on-ink); }
.lightbox__bar { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); }
.lightbox__bar .num { color: var(--c-metal-on-ink); }
.lightbox__bar .icon-btn { color: var(--c-on-ink); }
.lightbox__body {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--s-3);
  padding-block: var(--s-5);
}
.lightbox__media { display: grid; place-items: center; min-width: 0; width: 100%; }
.lightbox__frame { width: 100%; }
.lightbox__frame img, .compare img {
  width: 100%; height: auto; max-height: 62svh; object-fit: contain;
}
.lightbox__nav {
  display: grid; place-items: center;
  min-width: 48px; min-height: 48px;
  border: var(--bw-hair) solid var(--c-line-on-ink);
  color: var(--c-on-ink); font-size: var(--t-md);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.lightbox__nav:hover { background: var(--c-on-ink); color: var(--c-ink); }
.lightbox__nav[hidden] { display: none; }
.lightbox__meta {
  display: grid; gap: var(--s-4); justify-items: start;
  max-width: var(--w-narrow); margin-inline: auto; width: 100%;
  border-top: var(--bw-hair) solid var(--c-line-on-ink);
  padding-top: var(--s-5);
}
.lightbox__facts { display: grid; gap: var(--s-3); width: 100%; }
.lightbox__facts > div { display: flex; gap: var(--s-4); align-items: baseline; }
.lightbox__facts dt {
  flex: 0 0 8.5rem; font-size: var(--t-3xs); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--c-on-ink-3);
}
.lightbox__facts dd { font-size: var(--t-sm); }
.lb-products { display: grid; gap: var(--s-2); margin-block: var(--s-3); }
.lb-products li { display: flex; gap: var(--s-3); align-items: baseline; font-size: var(--t-sm); }
.lb-products__brand { flex: 0 0 8.5rem; font-size: var(--t-3xs); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--c-metal-on-ink); }
.lb-products__name { flex: 1 1 auto; min-width: 0; }
.lb-products__price { font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (min-width: 1024px) {
  /* Two columns: the frame beside its facts, so the booking action is
     in view without scrolling and the dark field is not just empty. */
  .lightbox {
    padding-inline: var(--s-11);
    grid-template-columns: minmax(0, 1.15fr) minmax(320px, 0.85fr);
    grid-template-rows: auto minmax(0, 1fr);
    column-gap: var(--s-13); align-items: center;
  }
  .lightbox__bar { grid-column: 1 / -1; align-self: start; }
  .lightbox__body { grid-column: 1; gap: var(--s-6); }
  .lightbox__meta {
    grid-column: 2; margin-inline: 0; max-width: none;
    border-top: 0; padding-top: 0;
  }
}
@media (max-width: 767px) {
  .lightbox__body { grid-template-columns: auto minmax(0,1fr) auto; gap: var(--s-2); }
  .lightbox__nav { min-width: 44px; }
  .lightbox__facts dt, .lb-products__brand { flex-basis: 6rem; }
}

/* Genuine before/after, rendered only when a real pair exists. */
.compare { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3); width: 100%; }
.compare figure { margin: 0; display: grid; gap: var(--s-2); }
.compare__label {
  font-size: var(--t-3xs); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--c-on-ink-3); order: 2;
}

/* ---------- SERVICE FINDER ---------------------------------- */
.finder { display: grid; gap: var(--s-8); }
@media (min-width: 1024px) { .finder { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s-11); align-items: start; } }
.finder__form { display: grid; gap: var(--s-6); }
.finder__q { border: 0; display: grid; gap: var(--s-3); }
.finder__q legend {
  display: flex; align-items: baseline; gap: var(--s-3);
  font-family: var(--font-display); font-size: var(--t-md);
  margin-bottom: var(--s-2);
}
.finder__hint { max-width: 46ch; }
.finder__opts { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.finder__opt { position: relative; display: inline-flex; }
.finder__opt input {
  position: absolute; inset: 0; opacity: 0; cursor: pointer; margin: 0;
}
.finder__opt span {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: var(--s-2) var(--s-5);
  font-size: var(--t-sm);
  border: var(--bw-hair) solid var(--c-line-strong);
  color: var(--c-ink-2);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.finder__opt input:hover + span { border-color: var(--c-ink); color: var(--c-ink); }
.finder__opt input:checked + span { background: var(--c-ink); border-color: var(--c-ink); color: var(--c-paper); }
.finder__opt input:focus-visible + span { outline: 2px solid var(--c-focus); outline-offset: 3px; }
.finder__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); }

.finder__results { display: grid; gap: var(--s-5); align-content: start; }
.finder__results[hidden] { display: none; }
.finder__idle .route__notes li { border-left-color: var(--c-line-strong); }
.finder__results h3:focus-visible { outline-offset: 6px; }
@media (min-width: 1024px) {
  .finder__results {
    position: sticky; top: 108px;
    background: var(--c-paper);
    border: var(--bw-hair) solid var(--c-line);
    padding: var(--s-7);
  }
}
.route { display: grid; gap: var(--s-2); }
.route__title { font-family: var(--font-display); font-size: var(--t-lg); }
.route__list { display: grid; gap: var(--s-2); margin-top: var(--s-2); }
.route__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4);
  font-size: var(--t-sm); padding-bottom: var(--s-2);
  border-bottom: var(--bw-hair) solid var(--c-line);
}
.route__price { color: var(--c-ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; }
.route__note { color: var(--c-metal-text); }
.route__notes { display: grid; gap: var(--s-3); }
.route__notes li {
  font-size: var(--t-sm); color: var(--c-ink-2);
  padding-left: var(--s-4); border-left: var(--bw-thick) solid var(--c-metal);
}
.route__consult { font-size: var(--t-sm); font-weight: var(--fw-medium); }

/* ---------- ARTIST PROFILES --------------------------------- */
.artist {
  display: grid; gap: var(--s-6);
  padding-block: var(--s-9);
  border-top: var(--bw-hair) solid var(--c-line);
}
.artist:first-child { border-top: 0; padding-top: 0; }
@media (min-width: 1024px) {
  .artist { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: clamp(40px, 5vw, 88px); align-items: center; }
  /* Alternating sides: the roster reads as a spread, not a list. */
  .artist--flip .artist__media { order: 2; }
}
.artist__media img { width: 100%; aspect-ratio: var(--ar-portrait); object-fit: cover; }
.artist__media--type {
  aspect-ratio: var(--ar-portrait); background: var(--c-smoke);
  display: grid; place-items: center;
}
.artist__initial {
  font-family: var(--font-display); font-size: clamp(4rem, 12vw, 9rem);
  color: var(--c-metal); line-height: 1;
}
.artist__body { display: grid; gap: var(--s-3); align-content: start; }
.artist__title {
  font-size: var(--t-2xs); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--c-metal-text);
}
.artist__chips { display: grid; gap: var(--s-2); margin-top: var(--s-2); }
.artist__chips ul { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.artist__chips li {
  font-size: var(--t-xs); padding: var(--s-1) var(--s-3);
  border: var(--bw-hair) solid var(--c-line); color: var(--c-ink-2);
}
.artist__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); margin-top: var(--s-4); }
.artist-pending { display: grid; gap: var(--s-4); max-width: var(--w-narrow); }

/* ---------- PRODUCT SIZE ------------------------------------ */
.product__size {
  font-size: var(--t-3xs); letter-spacing: var(--tr-wide);
  text-transform: uppercase; color: var(--c-ink-3);
}

.shop-more { display: flex; justify-content: center; margin-top: var(--s-8); }
.shop-more button[hidden] { display: none; }

/* ---------- SERVICE FINDER: SAVE / ACCOUNT ------------------ */
.finder__account {
  margin-top: var(--s-6); padding-top: var(--s-6);
  border-top: var(--bw-hair) solid var(--c-line);
  display: grid; gap: var(--s-3);
}
.finder__account h4 { font-family: var(--font-display); }
.finder__account-hi { font-size: var(--t-sm); }
.finder__account-form { display: grid; gap: var(--s-4); margin-top: var(--s-2); }
.finder__account-form[hidden] { display: none; }
.finder__field { display: grid; gap: var(--s-2); }
.finder__field span {
  font-size: var(--t-3xs); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--c-ink-3);
}
.finder__field input {
  min-height: 48px; padding: var(--s-3) var(--s-4);
  font: inherit; font-size: var(--t-sm); color: var(--c-ink);
  background: var(--c-paper);
  border: var(--bw-hair) solid var(--c-line-strong);
  border-radius: var(--radius-none);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.finder__field input:hover { border-color: var(--c-ink-3); }
.finder__field input:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; border-color: var(--c-ink); }

/* ============================================================
   THE TEAM PAGE
   ------------------------------------------------------------
   A wall of stylists; opening one gives a horizontal slider of
   their work and a short bio.
   ============================================================ */
.tm-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-4);
}
@media (min-width: 600px)  { .tm-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-5); } }
@media (min-width: 1024px) { .tm-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.tm-card__open {
  display: grid; gap: var(--s-2);
  width: 100%; padding: 0; border: 0; background: none; cursor: pointer;
  text-align: left; color: inherit;
}
.tm-card__shot {
  display: block; position: relative; overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--c-bone);
  outline: var(--bw-hair) solid var(--c-line);
  outline-offset: calc(-1 * var(--bw-hair));
}
.tm-card__shot picture { display: block; width: 100%; height: 100%; }
.tm-card__shot img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: var(--focus, center);
  transition: transform var(--dur-slow) var(--ease-out);
}
.tm-card__open:hover .tm-card__shot img,
.tm-card__open:focus-visible .tm-card__shot img { transform: scale(1.03); }

/* No photograph: the initial, set large. Better than a grey box. */
.tm__initial {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-display); font-size: var(--t-4xl);
  color: var(--c-metal-text);
}

.tm-card__name  { font-family: var(--font-display); font-size: var(--t-lg); line-height: var(--lh-snug); }
.tm-card__title { font-size: var(--t-3xs); letter-spacing: var(--tr-wide); text-transform: uppercase; color: var(--c-ink-3); }

/* ---------- the panel ---------- */
.tm-panel {
  position: fixed; z-index: var(--z-drawer);
  inset: auto 0 0 0; max-height: 92vh;
  display: none; grid-template-rows: auto 1fr;
  background: var(--c-paper);
  border-top: var(--bw-hair) solid var(--c-line);
  overflow-y: auto;
  padding-bottom: env(safe-area-inset-bottom);
}
.tm-panel[data-open="true"] { display: grid; }
@media (min-width: 900px) {
  /* Centred sheet on a desktop; bottom sheet on a phone, where a thumb
     reaches the bottom of the screen and not the middle. */
  .tm-panel { inset: 50% auto auto 50%; transform: translate(-50%, -50%);
              width: min(1100px, 92vw); max-height: 88vh; border: var(--bw-hair) solid var(--c-line); }
}

.tm-panel__bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); padding: var(--s-4) var(--s-5);
  border-bottom: var(--bw-hair) solid var(--c-line);
  position: sticky; top: 0; background: var(--c-paper); z-index: 1;
}
.tm-panel__body { padding: var(--s-5); display: grid; gap: var(--s-6); }
@media (min-width: 900px) { .tm-panel__body { grid-template-columns: 1.35fr 1fr; gap: var(--s-7); padding: var(--s-6); } }

/* ---------- the slider ----------
   A scroll container with snap points. The phone flicks it natively;
   the buttons are a convenience on top, not the mechanism. */
.tm-rail {
  display: grid; grid-auto-flow: column; grid-auto-columns: 100%;
  gap: var(--s-3);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
@media (min-width: 900px) { .tm-rail { grid-auto-columns: 78%; } }
.tm-slide { scroll-snap-align: start; margin: 0; min-width: 0; }
.tm-slide picture { display: block; }
.tm-slide img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 5; object-fit: cover;
  background: var(--c-bone);
  /* Capped so the arrows and the counter stay on screen. A 4:5 portrait
     at full column width is taller than the panel, which pushed the
     controls below the fold — the slider looked like it had none. */
  max-height: 58vh;
}
.tm-slide figcaption { margin-top: var(--s-2); }
.tm-slide--empty { display: grid; place-items: center; aspect-ratio: 4/5; background: var(--c-bone); color: var(--c-ink-3); }

.tm-rail__nav { display: flex; align-items: center; gap: var(--s-3); margin-top: var(--s-3); }
.tm-rail__nav .num { font-variant-numeric: tabular-nums; color: var(--c-ink-3); font-size: var(--t-3xs); }
.tm-arrow {
  min-width: 44px; min-height: 44px;
  border: var(--bw-hair) solid var(--c-line-strong); background: none;
  cursor: pointer; color: var(--c-ink);
}
.tm-arrow:hover:not(:disabled) { background: var(--c-ink); color: var(--c-paper); border-color: var(--c-ink); }
.tm-arrow:disabled { opacity: .3; cursor: default; }

.tm-bio { line-height: var(--lh-relaxed); color: var(--c-ink-2); }
.tm__chips { margin-top: var(--s-4); }
.tm__chips ul { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-2); }
.tm__chips li {
  font-size: var(--t-2xs); padding: 4px 10px;
  border: var(--bw-hair) solid var(--c-line); color: var(--c-ink-2);
}
.tm-panel__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4); margin-top: var(--s-6); }
