/* Amble Barbers — website styles.
   Everything brand-level comes from the design-system tokens in tokens/.
   This file only lays out the page and adds the dark theme mapping. */

@import "tokens/fonts.css";
@import "tokens/colors.css";
@import "tokens/typography.css";
@import "tokens/spacing.css";
@import "tokens/effects.css";

/* ---------- Dark theme: remap the semantic aliases, keep the raw materials ---------- */
[data-theme="dark"] {
  /* Softened 2026-09-10 per D+M: the old near-black + bright bone read as
     stark black-and-white on a phone. Warm charcoal ground, bone-2 text,
     bone-2 frames — still dark, less contrast. */
  --bg: #1C1914;
  --bg-alt: #23201A;
  --surface: #29251E;
  --surface-invert: var(--bone-2);

  --text: var(--bone-2);
  --text-muted: var(--concrete);
  --text-faint: #938E82; /* 5.4:1 on charcoal, 4.7:1 on raised (HIG audit 2026-09-14) */
  --text-invert: var(--ink);

  --border: var(--bone-2);
  --border-hairline: #3A3730;
  --divider: var(--concrete-dark);

  --frost-fill: rgba(20, 18, 13, 0.6);
  --shadow-panel: 0 18px 48px -24px rgba(0, 0, 0, 0.6);
  --shadow-lift: 0 8px 24px -16px rgba(0, 0, 0, 0.5);
}

/* Light theme softening (2026-09-10): frames, rules and the inverted band
   use softened ink instead of pure ink, so the page reads cream-and-charcoal
   rather than white-and-black. Text stays ink for legibility.
   Scoped to light mode explicitly: a bare :root here has the same specificity
   as [data-theme="dark"] above and, coming later, silently won — which turned
   the dark-mode opening band and coming-soon banner charcoal-on-charcoal. */
:root:not([data-theme="dark"]) {
  --border: var(--ink-80);
  --surface-invert: #26231C;
}

/* ---------- Base ---------- */
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-text);
  font-size: var(--text-base);
  line-height: var(--text-line);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
img { max-width: 100%; display: block; }
a { color: inherit; }

/* Keyboard focus, visible in both themes (the browser default was the only
   ring before; HIG audit 2026-09-14). */
:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }

/* Skip link: first element on every page, visible only when focused. */
.skip { position: absolute; left: var(--gutter); top: -100px; z-index: 30; padding: 10px 14px; background: var(--text); color: var(--bg); font-size: var(--text-sm); text-decoration: none; }
.skip:focus { top: var(--space-3); }

.container { max-width: var(--container); margin: 0 auto; padding: 0 var(--gutter); }
.narrow { max-width: var(--container-narrow); }

.label {
  font-family: var(--font-text);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  font-weight: var(--label-weight);
  text-transform: uppercase;
}

/* ---------- The Frame device ---------- */
.frame {
  position: relative;
  border: 2px solid var(--border);
  border-radius: var(--radius-none);
}
.frame::before {
  content: "";
  position: absolute;
  inset: var(--frame-inset);
  border: 1px solid var(--border);
  opacity: 0.55;
  pointer-events: none;
}
.frame > * { position: relative; z-index: 1; }

/* ---------- Mark (logo) ---------- */
.mark {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 2px solid var(--border);
  position: relative;
  flex: none;
}
.mark::before {
  content: "";
  position: absolute;
  inset: 4px;
  border: 1px solid var(--border);
  opacity: 0.55;
}
.mark span {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--weight-medium);
  font-size: 25px;
  line-height: 1;
}

/* ---------- Wordmark ----------
   The stacked lockup (Sep 11 2026, David's call, applied across every Amble
   app): "amble" over BARBERS with the dot between. "amble" keeps the size the
   inline mark had, so the header still reads as the same wordmark; BARBERS is
   0.5em of it, big enough to read at header sizes (the print spec's 0.24em is
   for signage). Scale the whole thing with font-size; never one part alone. */
.wordmark {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  letter-spacing: var(--wordmark-tracking);
  line-height: 0.92;
  text-decoration: none;
}
/* WONK is Fraunces' signature-alternates axis (the curled b). The design system
   spends it here and nowhere else — not on the mark's "a", not on headings, not
   on body copy. One letterform is a signature; a page of them is a costume. */
.wordmark .amble { font-style: italic; font-variation-settings: var(--wordmark-wonk); }
/* The lockup dot — v2 (Master Design Reference). A structural divider between
   the two words, not decoration: never remove it, never swap it for a rule,
   never scale it on its own. Chartreuse is this surface's one spark. */
.wordmark .dot {
  width: 0.15em; height: 0.15em; border-radius: var(--radius-pill);
  background: var(--chartreuse); flex: none;
  margin: 0.18em 0;
}
.wordmark .barbers {
  font-family: var(--font-text);
  font-weight: var(--weight-semibold);
  font-size: 0.5em;
  letter-spacing: 0.3em;
  /* Browsers add tracking after the last letter too; pad the left by the same
     amount so the ink, not the box, sits centered under "amble". */
  padding-left: 0.3em;
  text-transform: uppercase;
  line-height: 1;
}

/* ---------- Header ---------- */
header.site {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--frost-fill);
  backdrop-filter: blur(var(--frost-blur));
  -webkit-backdrop-filter: blur(var(--frost-blur));
  border-bottom: 1px solid var(--border-hairline);
}
header.site .bar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--gutter);
  max-width: var(--container);
  margin: 0 auto;
}
header.site .wordmark { font-size: 30px; }
header.site nav { margin-left: auto; display: flex; align-items: center; gap: var(--space-5); }
header.site nav a {
  padding: 14px 0; /* 44px target with 16px text (HIG minimum control size) */
  text-decoration: none;
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease);
}
header.site nav a:hover { color: var(--text); }

.theme-toggle {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  width: 44px;
  height: 44px; /* HIG minimum control size; was 34 */
  display: grid;
  place-items: center;
  cursor: pointer;
  font-size: 17px;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.theme-toggle:hover { background: var(--text); color: var(--bg); }

/* ---------- Hero ----------
   The h1 is a sentence now, not the wordmark — the wordmark's job is the header,
   and the hero's job is one plain claim about the work. Sized to sit a couple of
   steps under the old wordmark scale so a full sentence still reads as a hero
   without running to five lines on a laptop.

   The hero owns the first screen: it fills the viewport and ends on a hard rule,
   so the page below is a genuine second thing you scroll to rather than
   something already peeking over the fold. That separation is the whole point —
   don't reintroduce content into the bottom of this section.

   svh, not vh: on mobile Safari, vh means the *tallest* the viewport ever gets,
   so a 100vh hero hides its own bottom edge behind the browser chrome on load. */
.hero {
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: var(--space-7) 0 var(--space-9);
  border-bottom: 2px solid var(--border);
}
/* The container is a flex item here, so it would otherwise shrink to fit its
   text and get centered by its own `margin: 0 auto` — pushing the hero's left
   edge inward and out of line with every section below it. */
.hero > .container { width: 100%; }
.hero .eyebrow { color: var(--text-muted); margin-bottom: var(--space-6); display: flex; align-items: center; gap: var(--space-3); }
/* Accent discipline: chartreuse is ~one note per surface, and since v2 that note
   is the lockup dot in the header. The eyebrow marker steps down to concrete so
   the two are not competing on the same screen. */
.hero .eyebrow::before { content: ""; width: 10px; height: 10px; background: var(--concrete); flex: none; }
.hero h1 {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  line-height: var(--display-line);
  letter-spacing: var(--display-tracking);
  font-size: clamp(46px, 8vw, 104px);
  max-width: 11em;
}
.hero .sub { color: var(--text-muted); max-width: 34em; margin-top: var(--space-6); font-size: var(--text-lg); }
.hero .cta-row { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-7); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 14px 28px;
  font-family: var(--font-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  border: 2px solid var(--border);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
  cursor: pointer;
}
.btn.solid { background: var(--text); color: var(--bg); }
.btn.solid:hover { background: transparent; color: var(--text); }
.btn.ghost { background: transparent; color: var(--text); }
.btn.ghost:hover { background: var(--text); color: var(--bg); }

/* ---------- Sections ---------- */
section.block { padding: var(--section) 0; }
section.block.alt { background: var(--bg-alt); transition: background var(--dur) var(--ease); }
.section-head { display: flex; align-items: baseline; gap: var(--space-5); margin-bottom: var(--space-7); }
.section-head .label { color: var(--text-muted); flex: none; }
.section-head::after { content: ""; height: 1px; background: var(--divider); flex: 1; align-self: center; opacity: 0.5; }
h2 {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: clamp(32px, 5vw, var(--display-lg));
  line-height: var(--display-line);
  letter-spacing: var(--display-tracking);
  margin-bottom: var(--space-5);
}
h2 .it { font-style: italic; }
.lede { font-size: var(--text-lg); max-width: 36em; }
.lede + .lede { margin-top: var(--space-4); }
.muted { color: var(--text-muted); }

/* ---------- Facts ----------
   One framed block cut into three, rather than three separate framed tiles.
   The old tiles each carried a display numeral and a paragraph, which turned
   three plain facts into three small essays. These are facts: a label and a
   line. Hairlines between, one frame around — the room's structure, not cards. */
.facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border: 2px solid var(--border);
  margin-top: var(--space-7);
}
.facts .fact { padding: var(--space-6); }
.facts .fact + .fact { border-left: 1px solid var(--border-hairline); }
.facts h3 {
  font-family: var(--font-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--space-4);
}
.facts p { font-size: var(--text-base); max-width: 24em; }

/* ---------- Services menu ----------
   Duration sits next to price on purpose: it does the premium justification
   with no adjectives. Both are generated from the booking API — see index.html. */
.menu { border: 2px solid var(--border); padding: var(--space-7); position: relative; background: var(--surface); transition: background var(--dur) var(--ease); list-style: none; margin-top: var(--space-6); }
.menu::before { content: ""; position: absolute; inset: var(--frame-inset); border: 1px solid var(--border); opacity: 0.55; pointer-events: none; }
.menu > * { position: relative; }
/* Grid, not flex-wrap. The row is three explicit lines — name/dots/price, then
   the description, then the booking link — and grid states that outright. Under
   flex-wrap the description's max-width clamped its hypothetical size, so it
   kept fitting on line one and never wrapped; areas can't be argued with. */
.menu .item {
  display: grid;
  grid-template-columns: auto minmax(40px, 1fr) auto;
  grid-template-areas:
    "name dots meta"
    "desc desc desc"
    "link link link";
  align-items: baseline;
  column-gap: var(--space-4);
  padding: var(--space-6) 0;
}
.menu .item + .item { border-top: 1px solid var(--border-hairline); }
.menu .item h3 { grid-area: name; font-family: var(--font-display); font-weight: var(--weight-medium); font-size: var(--display-sm); }
.menu .item .dots { grid-area: dots; border-bottom: 1px dotted var(--divider); transform: translateY(-6px); }
.menu .item .meta { grid-area: meta; display: flex; align-items: baseline; gap: var(--space-4); }
.menu .item .dur { color: var(--text-muted); font-size: var(--text-sm); letter-spacing: 0.04em; font-variant-numeric: tabular-nums; }
.menu .item .price { font-family: var(--font-display); font-style: italic; font-size: var(--display-sm); }
.menu .item p { grid-area: desc; margin-top: var(--space-2); color: var(--text-muted); font-size: var(--text-sm); max-width: 44em; }
.menu .item .book-link {
  grid-area: link;
  justify-self: start;
  margin-top: var(--space-3);
  padding: 10px 0; /* 44px hit area on a text link */
  margin-bottom: -10px;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  text-decoration: none;
  color: var(--text);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  transition: gap var(--dur-fast) var(--ease);
}
/* The rule sits on the label rather than the <a> so the arrow isn't underlined
   and the underline stops where the words do. */
.menu .item .book-link .book-label { border-bottom: 2px solid var(--accent); padding-bottom: 2px; }
.menu .item .book-link:hover { gap: var(--space-3); }
.menu-note { margin-top: var(--space-6); color: var(--text-muted); font-size: var(--text-sm); display: flex; align-items: baseline; gap: var(--space-3); max-width: 46em; }
.menu-note::before { content: ""; width: 8px; height: 8px; background: var(--accent); flex: none; transform: translateY(-1px); }

/* ---------- Interior page head ----------
   About and Services open with this instead of a hero: same display type, no
   CTA row, and a hard rule at the bottom so every page has the same header/body
   separation the landing page has. */
.page-head { padding: var(--space-9) 0 var(--space-8); border-bottom: 2px solid var(--border); }
.page-head .eyebrow { color: var(--text-muted); margin-bottom: var(--space-5); display: flex; align-items: center; gap: var(--space-3); }
.page-head .eyebrow::before { content: ""; width: 10px; height: 10px; background: var(--concrete); flex: none; }
.page-head h1 {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: clamp(40px, 6.5vw, 84px);
  line-height: var(--display-line);
  letter-spacing: var(--display-tracking);
  max-width: 12em;
}
.page-head .sub { color: var(--text-muted); max-width: 34em; margin-top: var(--space-5); font-size: var(--text-lg); }

/* ---------- Prose ----------
   The About page is paragraphs, not components. Wider type and a real measure;
   nothing else on the site runs this long. */
.prose { max-width: 34em; }
.prose p { font-size: var(--text-lg); }
.prose p + p { margin-top: var(--space-5); }

/* ---------- Photo slots ----------
   Aspect-locked frames that hold their layout before the photography exists,
   so dropping a real <img> in later changes nothing about the page.
   Shot list + required aspect ratios: docs/OPERATIONS.md. */
.shot { position: relative; border: 2px solid var(--border); overflow: hidden; }
.shot::after { content: ""; position: absolute; inset: var(--frame-inset); border: 1px solid var(--border); opacity: 0.55; pointer-events: none; z-index: 2; }
.shot.portrait { aspect-ratio: 4 / 5; }
.shot.square { aspect-ratio: 1 / 1; }
.shot img { width: 100%; height: 100%; object-fit: cover; }
.shot-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  background:
    repeating-linear-gradient(
      -45deg,
      transparent 0 11px,
      var(--border-hairline) 11px 12px
    );
  opacity: 0.75;
}
.shot-empty .mark { width: 38px; height: 38px; background: var(--bg); }
.shot-empty .mark span { font-size: 21px; }
.shot-caption { color: var(--text-muted); background: var(--bg); padding: var(--space-2) var(--space-3); }

/* ---------- Who's cutting ---------- */
.people { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6); margin-top: var(--space-8); max-width: 640px; }
.person figcaption { margin-top: var(--space-4); }
.person h3 { font-family: var(--font-display); font-weight: var(--weight-medium); font-size: var(--display-sm); margin-bottom: var(--space-2); }
.person p { color: var(--text-muted); font-size: var(--text-sm); }
.work-head { font-family: var(--font-display); font-weight: var(--weight-medium); font-size: clamp(24px, 3vw, var(--display-md)); margin-top: var(--space-9); margin-bottom: var(--space-5); }
.work-head .it { font-style: italic; }
.work-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }

/* ---------- Sticky book bar ----------
   Appears only once the hero CTA is out of view, so the two never compete. */
.book-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
  padding: var(--space-4) var(--gutter);
  background: var(--frost-fill);
  backdrop-filter: blur(var(--frost-blur));
  -webkit-backdrop-filter: blur(var(--frost-blur));
  border-top: 2px solid var(--border);
  /* Clear the iPhone home indicator (needs viewport-fit=cover in the meta). */
  padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  transform: translateY(100%);
  transition: transform var(--dur) var(--ease);
}
.book-bar.show { transform: translateY(0); }
.book-bar-text { font-size: var(--text-sm); color: var(--text-muted); }
.btn.compact { padding: 9px 18px; font-size: var(--text-xs); border-width: 2px; }
header.site .book-cta { margin-left: var(--space-2); }

/* ---------- The room ---------- */
.room-grid { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: var(--space-8); align-items: start; }
.materials { display: grid; grid-template-columns: 1fr 1fr; gap: 0; border: 2px solid var(--border); }
.materials .cell { padding: var(--space-5); border: 1px solid var(--border-hairline); min-height: 108px; display: flex; flex-direction: column; justify-content: flex-end; gap: var(--space-2); }
.materials .swatch { width: 28px; height: 28px; border: 1px solid var(--border); margin-bottom: auto; }
.materials .cell h4 { font-family: var(--font-text); font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.materials .cell p { font-size: var(--text-xs); color: var(--text-muted); }
.detail-list { list-style: none; margin-top: var(--space-6); }
.detail-list li { padding: var(--space-4) 0; border-top: 1px solid var(--border-hairline); display: flex; gap: var(--space-4); }
.detail-list li:last-child { border-bottom: 1px solid var(--border-hairline); }
.detail-list .k { flex: none; width: 9.5em; }
.detail-list .k .label { color: var(--text-muted); }
.detail-list .v { color: var(--text); }

/* ---------- Visit ---------- */
.visit-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-8); margin-top: var(--space-7); }
.visit-card .park { color: var(--text); border-left: 2px solid var(--accent); padding-left: var(--space-4); margin-top: var(--space-4); font-size: var(--text-sm); }
.visit-card { border: 2px solid var(--border); padding: var(--space-7); position: relative; }
.visit-card::before { content: ""; position: absolute; inset: var(--frame-inset); border: 1px solid var(--border); opacity: 0.55; pointer-events: none; }
.visit-card > * { position: relative; }
.visit-card h3 { font-family: var(--font-display); font-weight: var(--weight-medium); font-size: var(--display-sm); margin-bottom: var(--space-4); }
.visit-card p { color: var(--text-muted); }
.visit-card p + p { margin-top: var(--space-3); }
.visit-card .big { color: var(--text); font-size: var(--text-lg); }
.hours { list-style: none; margin-top: var(--space-4); }
.hours li { display: flex; justify-content: space-between; padding: var(--space-2) 0; border-bottom: 1px solid var(--border-hairline); font-size: var(--text-sm); }
.hours .day { color: var(--text-muted); }

/* ---------- Footer ---------- */
footer.site { border-top: 2px solid var(--border); padding: var(--space-7) 0; }
/* The sticky book bar hides itself once the footer is on screen (site.js), so
   the footer needs no clearance for it at any width. */
footer.site .row { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
footer.site .wordmark { font-size: 22px; }
/* The brand line sits beside the lockup, behind a hairline, vertically centered
   on it: a masthead and its motto. Under-the-lockup and centered-band versions
   were both tried and rejected 2026-09-13 (the stacked lockup is a closed badge;
   nothing should hang off it). */
footer.site .tagline { margin: 0; align-self: stretch; display: flex; align-items: center; padding-left: var(--space-5); border-left: 1px solid var(--divider); font-family: var(--font-display); font-style: italic; font-weight: var(--weight-medium); font-size: 20px; line-height: 1; color: var(--text-muted); font-variation-settings: "WONK" 0; }
/* Muted, not faint: the faint concrete sat at ~2.7:1 on bone, under the
   small-text contrast guideline. Stepped up 2026-09-13 (David's call). */
footer.site .fine { margin-left: auto; color: var(--text-muted); font-size: var(--text-xs); letter-spacing: 0.04em; }

/* ---------- Motion: scroll reveals ----------
   The same dialect as the booking app's "softly moving panels": a quiet
   fade-and-rise on the design system's --ease, staggered through groups.
   Everything here is gated on html.anim, which only the script adds (and only
   when IntersectionObserver exists and reduced-motion is off) — so with no JS
   the page is simply visible, nothing hidden. */
@keyframes rise-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

html.anim .reveal { opacity: 0; }
html.anim .reveal.in { animation: rise-in var(--dur-slow) var(--ease) both; }

html.anim .reveal-group > * { opacity: 0; }
html.anim .reveal-group.in > * { animation: rise-in var(--dur-slow) var(--ease) both; }
html.anim .reveal-group.in > :nth-child(1)  { animation-delay: 60ms; }
html.anim .reveal-group.in > :nth-child(2)  { animation-delay: 130ms; }
html.anim .reveal-group.in > :nth-child(3)  { animation-delay: 200ms; }
html.anim .reveal-group.in > :nth-child(4)  { animation-delay: 270ms; }
html.anim .reveal-group.in > :nth-child(5)  { animation-delay: 340ms; }
html.anim .reveal-group.in > :nth-child(6)  { animation-delay: 410ms; }
html.anim .reveal-group.in > :nth-child(n + 7) { animation-delay: 480ms; }

/* Quiet hover warmth on the framed cards — never movement, never scale.
   Matches the booking app's .lift rule: the border firms, a diffuse shadow
   appears, like light shifting behind frosted glass. */
.visit-card, .menu {
  transition: box-shadow var(--dur) var(--ease);
}
.visit-card:hover { box-shadow: var(--shadow-lift); }

@media (prefers-reduced-motion: reduce) {
  html.anim .reveal,
  html.anim .reveal-group > * { opacity: 1; animation: none; }
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  :root { --section: 64px; }
  /* The facts stack, so the divider has to turn with them. */
  .facts { grid-template-columns: 1fr; }
  .facts .fact + .fact { border-left: none; border-top: 1px solid var(--border-hairline); }
  .room-grid, .visit-grid { grid-template-columns: 1fr; }
  /* The full-height hero is a desktop gesture; on a phone it's just an empty
     screen between the visitor and the page. */
  .hero { min-height: 0; display: block; }
  /* The nav links used to be hidden here — they were same-page anchors and the
     page scrolled to them anyway. They're real pages now, so hiding them would
     leave a phone with no way to reach About or Services at all. They shrink
     instead. */
  header.site nav { gap: var(--space-4); }
  header.site nav a.nav-link { font-size: var(--text-sm); }
  .menu { padding: var(--space-5); }
  .hero { padding-top: var(--space-8); }
  .detail-list .k { width: 8em; }
  .work-grid { grid-template-columns: repeat(2, 1fr); }
  .people { max-width: none; }
  /* The sticky bar hides itself once the footer is on screen (site.js), so
     the footer no longer needs a bar's worth of clearance. This is just
     breathing room; the 144px it used to carry read as a dead zone. */
  footer.site { padding-bottom: var(--space-8); }
}

@media (max-width: 480px) {
  /* Narrow phones: the dotted leader has no room, so the name gets the row
     and the duration/price sit at its right. "Haircut & Beard Trim" was
     breaking into three lines beside "60 / min" at 320px. */
  .menu .item {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "name meta"
      "desc desc"
      "link link";
  }
  .menu .item .dots { display: none; }
  .menu .item .meta { white-space: nowrap; }
  .menu .item .dur { white-space: nowrap; }
  /* The middle of the opening band is the one part a phone can drop: three
     lines of tracked caps at the top of the screen was the loudest thing on
     the page. Two lines now. */
  .opening-band .band-mid { display: none; }
}

@media (max-width: 620px) {
  /* Phones: the lockup steps down a notch (30 → 26px; David, 2026-09-14). */
  header.site .wordmark { font-size: 26px; }
  /* The bar's job on a phone is the button, not the sentence. */
  .book-bar-text { display: none; }
  .book-bar { justify-content: stretch; padding: var(--space-3) var(--gutter) calc(var(--space-3) + env(safe-area-inset-bottom, 0px)); }
  .book-bar .btn { flex: 1; justify-content: center; }
  header.site .book-cta { display: none; }
  .menu .item h3 { font-size: var(--text-lg); }
  .menu .item .price { font-size: var(--text-lg); }
}

/* Respect a reduced-motion preference: the bar appears, it just doesn't slide. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .book-bar { transition: none; }
}

/* ---------- Coming-soon page ----------
   coming-soon.html is the placeholder that stands at amblebarbers.com until the
   shop opens. One screen: the hero claim, the three facts, a footer. It reuses
   the hero type and the facts block so the day the real site replaces it,
   nothing about the brand shifts — only the amount of page. Served by its own
   nginx container (deploy/nginx-coming-soon.conf) that never exposes the other
   pages, so this is the only thing a stranger at the apex domain can reach. */
.soon {
  min-height: calc(100svh - 62px); /* header bar height; keeps the footer at the fold, not above it */
  display: flex;
  align-items: center;
  padding: var(--space-8) 0 var(--space-9);
}
.soon > .container { width: 100%; }
.soon .eyebrow { color: var(--text-muted); margin-bottom: var(--space-6); display: flex; align-items: center; gap: var(--space-3); }
.soon .eyebrow::before { content: ""; width: 10px; height: 10px; background: var(--concrete); flex: none; }
.soon h1 {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  line-height: var(--display-line);
  letter-spacing: var(--display-tracking);
  font-size: clamp(46px, 8vw, 104px);
  max-width: 11em;
}
.soon .sub { color: var(--text-muted); max-width: 34em; margin-top: var(--space-6); font-size: var(--text-lg); }
.soon-facts { margin-top: var(--space-8); }
.soon-facts .fact p + p { margin-top: var(--space-2); }
.soon-facts .fact p.muted { font-size: var(--text-sm); }
.soon-note { margin-top: var(--space-7); color: var(--text-faint); display: flex; align-items: center; gap: var(--space-3); }
.soon-note::before { content: ""; width: 56px; height: 1px; background: var(--divider); }
/* No sticky book bar here, so the footer doesn't need the mobile clearance. */
.soon-page footer.site { padding-bottom: var(--space-7); }

@media (max-width: 900px) {
  .soon { min-height: 0; display: block; padding-top: var(--space-8); }
  .soon-facts { margin-top: var(--space-7); }
}
/* The banner: a full-width inverted band under the header. Ink on bone in
   light mode, bone on ink in dark, via the semantic invert tokens. It carries
   the "when," so the hero below it doesn't repeat the date. */
.soon-banner {
  background: var(--surface-invert);
  color: var(--text-invert);
  /* The banner IS the first screen: it holds most of the viewport, and the
     hero below is what you scroll to. Header bar is ~62px. */
  min-height: calc(78svh - 62px);
  display: flex;
  align-items: center;
  padding: var(--space-8) 0;
  border-bottom: 2px solid var(--border);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.soon-banner > .container { width: 100%; }
.soon-banner-title {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  line-height: 0.95;
  letter-spacing: -0.01em;
  font-size: clamp(64px, 14.5vw, 210px);
}
.soon-banner-sub { margin-top: var(--space-5); opacity: 0.7; }
/* The banner owns the page now; the claim below it steps down so it reads as
   the second thing, not a rival headline. */
.soon-page .soon { min-height: 0; padding: var(--space-8) 0 var(--space-9); }
.soon-page .soon h1 { font-size: clamp(34px, 4.6vw, 64px); }
.soon-page .soon .sub { margin-top: var(--space-5); }

@media (max-width: 900px) {
  .soon-banner { min-height: 0; padding: var(--space-8) 0; }
  .soon-banner-title { font-size: clamp(56px, 17vw, 96px); }
}

/* ---------- Legal pages (privacy.html, terms.html, sms.html) ---------- */
.legal { min-height: auto; padding-top: var(--space-10); padding-bottom: var(--space-10); }
/* The back-link row is plain wrapping text here, not the coming-soon page's
   flex row: as flex, its three links became items that could not wrap, and
   "Terms" hung past the right edge of every phone (the page scrolled
   sideways). Found 2026-09-13 on a phone. */
.legal .soon-note { display: block; line-height: 2.2; }
.legal .soon-note::before { display: none; }
.legal .prose { margin-top: var(--space-6); }
.legal .prose p { font-size: var(--text-base); color: var(--text-muted); }
.legal .prose h2 { margin-top: var(--space-7); margin-bottom: var(--space-2); font-size: var(--text-sm); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); font-family: var(--font-body); font-weight: 500; }
.legal .prose strong { color: var(--text); }
.legal .prose a, footer.site .fine a { color: inherit; text-decoration: underline; text-underline-offset: 0.15em; }
footer.site .fine a { display: inline-block; padding: 14px 4px; margin: -8px 0; } /* 44px target on 12px text (HIG); negative margin keeps the row height */

/* ---------- Pre-opening band (index/about/book, until opening day) ---------- */
.opening-band {
  background: var(--surface-invert);
  color: var(--text-invert);
  border-bottom: 1px solid var(--border);
  padding: var(--space-3) 0;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.opening-band .label { margin: 0; text-align: center; color: inherit; opacity: 0.92; }
.opening-band strong { font-weight: 600; color: inherit; }

/* ---------- /sms: the opt-in checkbox replica + screenshot ---------- */
.optin-demo { margin: var(--space-5) 0; padding: var(--space-5); border: 1px solid var(--border); background: var(--surface); border-radius: 2px; }
.optin-demo label { display: flex; gap: var(--space-3); align-items: flex-start; font-size: var(--text-sm); color: var(--text-muted); line-height: 1.5; }
.optin-demo input { margin-top: 0.3em; accent-color: var(--accent); }
.optin-demo .fine { margin-top: var(--space-3); }
.optin-shot { margin: var(--space-7) 0 0; }
.optin-shot img { display: block; width: 100%; max-width: 420px; border: 1px solid var(--border); background: var(--surface); }
.optin-shot figcaption { margin-top: var(--space-2); }
