/* ==========================================================================
   Barbershop — stylesheet

   Re-skinning for the next client: change the palette block below and
   web/config.js. Nothing else should need to move.

   Fonts are a system stack on purpose. Both competitors pull webfonts from a
   CDN and pay a render delay for it; this loads instantly and costs nothing.
   ========================================================================== */

/* ── Palette ──────────────────────────────────────────────────────────────
   Two themes, one set of names.

   LIGHT — white shop, brass fittings. The page is genuinely #fff, not an
   off-white pretending. Depth comes from warm alternating bands, a hairline on
   every card, and a shadow soft enough to read as light rather than as a smudge.

   DARK — midnight navy and brass. Navy for the same reason suits are navy: it
   is the colour of things made well. It carries real chroma, so it never looks
   like a dimmed screen, and it flatters brass in a way brown cannot.

   Both are complete and equal. Nothing below is a tinted version of the other:
   the neutrals carry a warm cast in light and a blue cast in dark, because a
   grey borrowed across a theme flip is the thing that makes a toggle look
   cheap.

   BRASS COMES IN TWO WEIGHTS, and the split is why one stylesheet can serve
   both. On navy a single bright gold does both jobs. On white it cannot —
   #c9a227 is 2.4:1 against white, illegible as text.

     --accent / --accent-hi     text, icons, hairlines. Readable on the ground.
     --accent-fill / -hi        backgrounds only, near-black label on top.

   In dark those four collapse back to the same bright brass. Every rule in this
   file is already written against the right one, so the flip is free.

   HOW THE THEME IS CHOSEN: an inline script in every <head> stamps
   data-theme on <html> before first paint — the visitor's saved choice if they
   have one, otherwise light. `prefers-color-scheme` is deliberately not
   consulted: the shop is a white barbershop, and following the OS would put
   every dark-mode phone on the navy version. Dark is opt-in. See Theme in
   shared.js for how to reverse that if the client ever wants it.

   Contrast is measured, not eyeballed. Smallest margin in each theme:
     light   --text 17.8:1   --text-faint 5.3:1   label on --accent-fill 7.5:1
     dark    --text 15.8:1   --text-faint 4.6:1   label on --accent-fill 8.9:1
   ────────────────────────────────────────────────────────────────────────── */

/* Light is the default, for everyone, on every first visit. */
:root {
  color-scheme: light;

  --bg:          #ffffff;   /* the page */
  --bg-alt:      #f6f3ee;   /* alternating sections, warm */
  --surface:     #ffffff;   /* cards */
  --surface-2:   #faf7f2;   /* raised / hover */
  --line:        #ddd6c9;
  --line-soft:   #ece7dd;

  --text:        #16181d;   /* near-black, never pure #000 */
  --text-dim:    #4c515a;
  --text-faint:  #5f6570;   /* 5.9:1 on white, still 4.8:1 at the foot of the
                               footer gradient, which is the darkest ground any
                               small text on this site ever lands on */

  --accent:      #7d6212;   /* brass you can read */
  --accent-hi:   #6d5610;
  --accent-fill:    #c9a227;   /* brass you can only sit on */
  --accent-fill-hi: #b08f1f;

  --accent-soft: rgba(201, 162, 39, 0.15);
  --accent-line: rgba(125, 98, 18, 0.32);

  --ok:          #0f7a45;
  --ok-soft:     rgba(15, 122, 69, 0.10);
  --ok-line:     rgba(15, 122, 69, 0.30);
  --closed:      #b3392c;
  --closed-soft: rgba(179, 57, 44, 0.09);
  --closed-line: rgba(179, 57, 44, 0.28);

  /* Surfaces that float over the page and need their own ground. */
  --nav-bg:      rgba(255, 255, 255, 0.92);
  --nav-shadow:  0 8px 24px rgba(40, 30, 12, .09);
  --bar-bg:      rgba(255, 255, 255, 0.97);
  --bar-shadow:  0 -8px 26px rgba(40, 30, 12, .10);
  --band-mid:    #f1ece3;   /* midpoint of the alternating band gradient */
  --footer-end:  #efe8dd;
  --ribbon-bg:   #fdf6e0;

  /* The hero photograph sits under a scrim so the text on top can read. The
     scrim is the one thing that genuinely inverts between themes: on white it
     bleaches the photo, on navy it darkens it. Same job, opposite direction. */
  --hero-photo:  .42;
  --hero-scrim:
    linear-gradient(180deg, rgba(255,255,255,.80) 0%, rgba(255,255,255,.90) 55%, var(--bg) 100%),
    radial-gradient(900px 500px at 50% 30%, rgba(255,255,255,.42), transparent 70%);
  /* Two warm light sources rather than one flat wash. In dark the second is a
     cool blue pool, which on white read as a bruise — so light gets tan. */
  --hero-glow:
    radial-gradient(900px 460px at 78% -8%, rgba(201,162,39,.13), transparent 64%),
    radial-gradient(780px 430px at 4% 108%, rgba(176,142,86,.11), transparent 62%),
    linear-gradient(178deg, rgba(120,100,60,.035), transparent 55%);
  --page-glow:
    radial-gradient(880px 420px at 72% -12%, rgba(201,162,39,.12), transparent 64%),
    radial-gradient(760px 400px at 6% 112%, rgba(176,142,86,.10), transparent 62%);
  --stripe-op:   .07;   /* barber-pole motif, kept very subtle */

  --btn-ghost-line: #c4baa8;
  --avatar-ring: rgba(0, 0, 0, .07);
  --badge-line:  var(--line);
  --star:        #9a6d04;
  --heart:       #c0392b;
  --quote-op:    .16;
  --splash-glow:   rgba(201,162,39,.13);
  --splash-stripe: rgba(201,162,39,.10);

  --radius:      14px;
  --radius-sm:   9px;
  --maxw:        1140px;

  --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  /* Warm-tinted rather than neutral grey, so a shadow looks like light falling
     across the page instead of a grey smudge under a box. */
  --shadow:      0 16px 40px rgba(40, 30, 12, 0.11);
  /* Cards sit on white, so the border does the defining and the shadow only
     lifts. Two layers: a tight one for the edge, a wide one for the light. */
  --shadow-card: 0 1px 2px rgba(40, 30, 12, .05), 0 10px 26px rgba(40, 30, 12, .05);
}

/* Dark. Only the values that actually differ are restated — anything absent
   here (radii, the max width, the font stack) is deliberately shared. */
:root[data-theme='dark'] {
  color-scheme: dark;

  --bg:          #1a2332;   /* midnight navy, lifted */
  --bg-alt:      #202b3c;
  --surface:     #253143;
  --surface-2:   #2d3b4f;
  --line:        #3a4a60;
  --line-soft:   #2f3d50;

  --text:        #f2f5f9;   /* crisp off-white, never pure #fff */
  --text-dim:    #b3c0d0;
  --text-faint:  #93a1b5;   /* 6.0:1 on --bg, and still 5.0:1 on --surface,
                               which is the lighter ground and so the real
                               constraint — the old #8493a8 was 4.2:1 there */

  /* Both weights collapse to the bright brass: on navy it is already 7.8:1. */
  --accent:      #c9a227;
  --accent-hi:   #e0bb46;
  --accent-fill:    #c9a227;
  --accent-fill-hi: #e0bb46;

  --accent-soft: rgba(201, 162, 39, 0.13);
  --accent-line: rgba(201, 162, 39, 0.34);

  --ok:          #4fbf87;
  --ok-soft:     rgba(79, 191, 135, 0.14);
  --ok-line:     rgba(79, 191, 135, 0.34);
  --closed:      #e06c5f;
  --closed-soft: rgba(224, 108, 95, 0.14);
  --closed-line: rgba(224, 108, 95, 0.34);

  --nav-bg:      rgba(26, 35, 50, 0.94);
  --nav-shadow:  0 10px 30px rgba(5, 10, 20, .4);
  --bar-bg:      rgba(26, 35, 50, 0.96);
  --bar-shadow:  0 -10px 30px rgba(5, 10, 20, .45);
  --band-mid:    #232f41;
  --footer-end:  #16202e;
  --ribbon-bg:   #2a2410;

  --hero-photo:  .5;
  --hero-scrim:
    linear-gradient(180deg, rgba(19,26,38,.72) 0%, rgba(19,26,38,.86) 55%, var(--bg) 100%),
    radial-gradient(900px 500px at 50% 30%, rgba(19,26,38,.35), transparent 70%);
  --hero-glow:
    radial-gradient(900px 460px at 78% -8%, rgba(201,162,39,.17), transparent 64%),
    radial-gradient(780px 430px at 4% 108%, rgba(58,96,150,.20), transparent 62%),
    linear-gradient(178deg, rgba(210,228,255,.04), transparent 55%);
  --page-glow:
    radial-gradient(880px 420px at 72% -12%, rgba(201,162,39,.16), transparent 64%),
    radial-gradient(760px 400px at 6% 112%, rgba(58,96,150,.19), transparent 62%);
  --stripe-op:   .05;

  --btn-ghost-line: var(--line);
  --avatar-ring: rgba(255, 255, 255, .09);
  /* The Google badge is a white pill in both themes. On navy it pops on its
     own; on white it needs an edge, so only light gives it a border. */
  --badge-line:  transparent;
  --star:        #f0a500;
  --heart:       #e8767c;
  --quote-op:    .09;
  --splash-glow:   rgba(201,162,39,.16);
  --splash-stripe: rgba(201,162,39,.055);

  --shadow:      0 18px 44px rgba(5, 10, 20, 0.55);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, .22), 0 10px 26px rgba(5, 10, 20, .34);
}

/* The theme flip is deliberately instant.
 *
 * A `transition: background-color` on <body> was the obvious first idea and it
 * is a trap. In any environment that is not compositing frames — embedded
 * webviews, and the same class of browser that already broke this project's
 * scroll and IntersectionObserver code — a started transition never advances,
 * and the page is left stuck on the *old* theme's background with the new
 * theme's cards on top of it. Verified: with the transition declared the body
 * reads rgb(26,35,50) after switching to light; remove it and the same element
 * resolves to #ffffff immediately.
 *
 * Losing a 250ms cross-fade costs nothing. A white page with navy furniture is
 * a broken site.
 *
 * The same reasoning applies to transitions that already existed for hover —
 * `.nav` animates its background, `.btn` its border. A theme flip retriggers
 * every one of them, so the header cross-fades over 250ms while the buttons
 * take 160ms and the cards change instantly. Even where it does not freeze,
 * that staggered ripple is what makes a theme toggle feel cheap.
 *
 * So the switch turns every transition off for one beat. Theme.apply() adds
 * this class, commits the new attribute, and drops it again on a timer. If that
 * timer somehow never runs, transitions simply stay off — the colours are still
 * correct, which is the failure this whole comment exists to guarantee. */
.theme-switching, .theme-switching *,
.theme-switching *::before, .theme-switching *::after {
  transition: none !important;
}

/* ── Base ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* The nav is sticky, so an anchor jump would land with the heading hidden
     underneath it. This offsets every scroll target by the nav height —
     cleaner and jank-free compared with doing it in JavaScript. */
  scroll-padding-top: 84px;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3, h4 { margin: 0; line-height: 1.12; font-weight: 800; letter-spacing: -0.02em; }
p { margin: 0; }

:focus-visible {
  outline: 2px solid var(--accent-hi);
  outline-offset: 3px;
  border-radius: 4px;
}

.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 22px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--accent-fill); color: #101720; padding: 10px 16px;
  border-radius: var(--radius-sm); font-weight: 700; transition: top .15s;
}
.skip-link:focus { top: 12px; }

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 13px 24px; border-radius: 100px; border: 1px solid transparent;
  font: inherit; font-weight: 700; font-size: 15px; text-decoration: none;
  cursor: pointer; transition: transform .12s ease, background .16s, border-color .16s, color .16s;
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }

/* The doubled class is deliberate, and it has been earned twice.
 *
 * A button is almost always inside some region that also says "links in here
 * are brass" — `.nav-links a`, `.footer a`, `.footer-direct a`. Those rules sit
 * later in the file, so with a single class they win, and the button's label
 * silently repaints to a link colour on top of a brass fill. That shipped once
 * in the nav (grey on brass, unreadable) and again in the footer.
 *
 * `.btn.btn-primary` is (0,2,0) and outranks any `.region a` rule, so a new
 * section style can never take a button's label with it.
 *
 * Near-black on brass is 7.5:1. Note it is the *fill* brass — `--accent` is
 * deliberately too dark to sit a black label on. */
.btn.btn-primary { background: var(--accent-fill); color: #0f1620; }
/* Hover darkens the brass rather than brightening it — on a white page a
   lighter hover reads as the button switching off. */
.btn.btn-primary:hover { background: var(--accent-fill-hi); color: #0f1620; }
.btn.btn-ghost { background: transparent; color: var(--text); border-color: var(--btn-ghost-line); }
.btn.btn-ghost:hover { border-color: var(--accent-line); color: var(--accent-hi); }
.btn-sm { padding: 9px 18px; font-size: 14px; }
.btn-lg { padding: 16px 30px; font-size: 16px; }
.btn-block { width: 100%; }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn:disabled:active { transform: none; }

/* ── Top bar ──────────────────────────────────────────────────────────────
   Thin strip above the header for social links and the phone number — the
   pattern both competitors use, and it gets two pieces of contact information
   above the fold without spending any of the header's attention on them.
   ────────────────────────────────────────────────────────────────────────── */
/* Kept, but not currently used on any public page — the strip above the nav was
   removed at the client's request and everything on it (social, phone) moved
   into the nav itself. Re-adding it is a markup change only. Same for
   `.demo-ribbon` further down. */
.topbar-strip {
  background: var(--bg-alt);
  border-bottom: 1px solid var(--line-soft);
  font-size: 13px;
}
.topbar-strip .container {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; min-height: 40px;
}
.topbar-note { color: var(--text-faint); }
.social-row { display: flex; align-items: center; gap: 6px; }
.social-row a {
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 50%;
  color: var(--text-dim); text-decoration: none;
  transition: color .18s, background .18s;
}
.social-row a:hover { color: var(--accent); background: var(--accent-soft); }

/* ── Theme toggle ─────────────────────────────────────────────────────────
   Sun and moon are stacked in the same box and cross-faded, so the button
   never changes size mid-swap and there is no reflow of the row it sits in.
   The icon shown is the theme you will GET, not the one you are in — that is
   the convention people already read correctly without a tooltip.
   ────────────────────────────────────────────────────────────────────────── */
.theme-toggle {
  position: relative; flex: none;
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: none; border: 1px solid transparent; color: var(--text-dim);
  cursor: pointer; padding: 0;
  transition: color .18s, background .18s, border-color .18s;
}
.theme-toggle:hover { color: var(--accent); background: var(--accent-soft); border-color: var(--accent-line); }
.theme-toggle svg {
  grid-area: 1 / 1; width: 17px; height: 17px; fill: currentColor;
  transition: opacity .22s ease, transform .32s cubic-bezier(.2,.8,.2,1);
}
.theme-toggle .i-sun  { opacity: 0; transform: rotate(-90deg) scale(.6); }
.theme-toggle .i-moon { opacity: 1; transform: none; }
/* In dark, the button offers to take you back to light. */
:root[data-theme='dark'] .theme-toggle .i-sun  { opacity: 1; transform: none; }
:root[data-theme='dark'] .theme-toggle .i-moon { opacity: 0; transform: rotate(90deg) scale(.6); }

/* One mount, two presentations. On a wide screen it is the icon alone; in the
   phone panel the label appears beside it, because this is the one control on
   the site whose effect a glyph does not explain. Same button either way, so
   there is no second copy to keep in sync. */
.nav-theme-label { display: none; }
.social-row svg { width: 16px; height: 16px; fill: currentColor; display: block; }

/* ── Header ───────────────────────────────────────────────────────────────
   Logo hard left, everything else hard right — the arrangement Omar's uses and
   the one a shop sign actually has. The centred logo it replaced looked good
   empty but squeezed the right-hand group until the phone number wrapped onto
   two lines.
   ────────────────────────────────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 100;
  background: var(--nav-bg);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
  transition: box-shadow .25s, background .25s;
}
.nav.is-stuck { box-shadow: var(--nav-shadow); }

/* The header runs wider than the page's 1140px body.
 *
 * A centred logo needs room for the WIDER of the two side groups on both
 * sides, not the average — the right group (social, theme, phone, button) is
 * 430px against the pages' 280px, so at 1140 the logo overlapped the social
 * icons by 32px even though it was mathematically dead centre. 1300 gives the
 * narrow side its surplus and still leaves ~48px of clear air on the tight
 * side. A header wider than the body it sits above is a deliberate look, not
 * an accident. */
.nav .container {
  position: relative;
  max-width: 1300px;
  display: flex; align-items: center;
  padding-top: 18px; padding-bottom: 18px;
}

/* Pages left, logo centred, everything else right.
 *
 * The logo is taken out of flow and centred on the container, rather than
 * being a middle column. A `1fr auto 1fr` grid centres the logo in the *grid*,
 * which is only the same thing when the two side groups are equal width — and
 * here the right group (social, theme, phone, button) is nearly twice the left.
 * That is what pulled the logo visibly off-centre last time.
 *
 * The side groups are one flex row with `margin-left: auto` on the first
 * utility item, so the page links sit hard left, the utilities hard right, and
 * the space they leave in the middle is where the logo lands. See the
 * breakpoint note below for why that space is always big enough. */
.brand {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  /* Generous on the sides, gentle top and bottom — the gap either side of a
     shop sign is what makes it read as a sign rather than as another item in
     the row. */
  padding: 6px clamp(30px, 4.5vw, 66px);
  display: grid; grid-template-columns: auto auto; align-items: center;
  column-gap: 13px; text-decoration: none;
  /* No `transition: transform` here. It was left over from a hover lift that no
     longer exists, and now that transform carries the centring it is actively
     harmful: crossing the breakpoint animates translate(-50%,-50%) → none, and
     where the clock is stopped it parks on the start value and drags the logo
     112px off the left edge of the screen. Measured. */
}
.brand-mark { grid-row: 1 / 3; grid-column: 1; }
.brand-name { grid-column: 2; align-self: end; }
.brand-tagline { grid-column: 2; align-self: start; }

.brand-mark {
  width: 56px; height: 56px; border-radius: 14px; flex: none;
  background: linear-gradient(150deg, var(--accent-fill) 0%, #a17f18 100%);
  display: grid; place-items: center; color: #101720; font-size: 26px; font-weight: 900;
  box-shadow: 0 8px 22px rgba(201,162,39,.22);
  transition: width .28s, height .28s, font-size .28s;
}
.brand-name {
  font-weight: 800; font-size: 19px; letter-spacing: .01em;
  transition: font-size .28s, opacity .2s;
}
.brand-tagline {
  font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--accent); font-weight: 700;
}

/* Shrink the header once the page scrolls, so the logo is generous on arrival
   and out of the way afterwards. */
.nav.is-stuck .container { padding-top: 8px; padding-bottom: 8px; }
.nav.is-stuck .brand-mark { width: 38px; height: 38px; font-size: 18px; }
.nav.is-stuck .brand-name { font-size: 16px; }
.nav.is-stuck .brand-tagline { display: none; }

/* One list, two groups. The four page links run from the left edge; the
   utilities are pushed to the right edge by `margin-left: auto` on the first
   of them, and the space that opens between the two is the logo's. Social
   leads the utilities, immediately after the last page link. */
.nav-links {
  flex: 1; display: flex; align-items: center;
  gap: 28px; list-style: none; margin: 0; padding: 0;
}
.nav-links > li { display: flex; align-items: center; }

/* The theme switch sits with the nav links, not with the utilities — it is a
   page control, and beside Location it is found without hunting between the
   phone number and the icon row. The social row still opens the right-hand
   group, so `margin-left: auto` moves with it. */
.nav-links .nav-theme + .nav-social { margin-left: auto; }
.nav-links .nav-social .social-row { gap: 4px; }
.nav-links .nav-social .social-row a { width: 36px; height: 36px; }
.nav-links .nav-social .social-row svg { width: 19px; height: 19px; }
.nav-links .nav-theme { margin-left: -12px; }

/* `:not(.btn)` matters. This rule sits after .btn-primary in the file, so
   without it the Book Now button in the nav inherited --text-dim and rendered
   muted grey on brass — unreadable, and the first thing you notice. */
.nav-links a:not(.btn) {
  text-decoration: none; color: var(--text-dim); font-size: 14.5px; font-weight: 600;
  transition: color .15s;
}
.nav-links a:not(.btn):hover { color: var(--text); }

.nav-book { flex: none; margin-left: 24px; }

/* The phone now lives inside `.nav-links`, so `.nav-links a:not(.btn)` matches
   it and outranks a bare `.nav-phone` — which is exactly how it ended up dim
   grey and half a shade from invisible. The extra class wins it back. The
   number is the one thing in the header someone might be squinting at while
   holding a phone in the other hand, so it gets full --text, not --text-dim. */
.nav-links a.nav-phone, .nav-phone {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  color: var(--text); text-decoration: none; font-size: 14.5px; font-weight: 700;
}
.nav-links a.nav-phone:hover, .nav-phone:hover { color: var(--accent-hi); }

/* Scroll-spy: the section you are looking at is marked in the nav. Cheap to
   do and it is most of what makes a one-pager feel navigable rather than
   like one long scroll. */
.nav-links a[aria-current='true'] { color: var(--accent); }

.nav-toggle {
  display: none; background: none; border: 1px solid var(--line); color: var(--text);
  border-radius: 10px; width: 44px; height: 44px; cursor: pointer;
  place-items: center; padding: 0; flex: none;
}
.nav-toggle-bars { display: block; width: 18px; }
.nav-toggle-bars i {
  display: block; height: 2px; background: currentColor; border-radius: 2px;
  transition: transform .28s cubic-bezier(.2,.8,.2,1), opacity .2s;
}
.nav-toggle-bars i + i { margin-top: 4px; }
/* Bars morph into a cross rather than swapping to a "✕" glyph — smoother, and
   it does not shift the button width mid-animation. */
.nav-toggle[aria-expanded='true'] .nav-toggle-bars i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded='true'] .nav-toggle-bars i:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded='true'] .nav-toggle-bars i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* The full row needs real room; below this the pages collapse behind the
   toggle, but Book Now stays out in the header where it can be tapped without
   opening anything first. */
/* The centred logo needs a real gap between the two side groups to sit in.
   Below this there is not one, so the layout goes back to logo-left with the
   pages behind the toggle — measured minimum for the three-part row is ~1283px,
   so the switch happens with room to spare rather than at the exact moment the
   logo would start touching a link. */
@media (max-width: 1280px) {
  .nav .container { gap: 12px; padding-top: 11px; padding-bottom: 11px; }
  /* Back into the flow, hard left. */
  .brand {
    position: static; transform: none; padding: 0;
    margin-right: auto;
  }
  .nav-toggle { display: grid; }
  .brand-mark { width: 44px; height: 44px; font-size: 20px; }
  .brand-name { font-size: 16.5px; }
  .brand-tagline { font-size: 9.5px; letter-spacing: .18em; }

  /* A dropdown panel, not a full-screen sheet.
   *
   * The sheet was `position: fixed; inset: 0`, and it was broken on every
   * phone: `.nav` carries `backdrop-filter`, and a filter or backdrop-filter
   * makes an element the containing block for its fixed-position descendants.
   * So `inset: 0` resolved against the 126px-tall header instead of the
   * viewport, and the "full-screen" menu rendered as a stub with the page
   * showing through underneath it.
   *
   * Anchoring the panel to the header with `position: absolute` sidesteps that
   * completely — and with only four links it is the better shape anyway. */
  /* The panel opens instantly, on `display` alone. No transition, no animation.
   *
   * Both were tried and both fail the same way. The sheet this replaced hid
   * itself with `opacity: 0; visibility: hidden` and transitioned them; where
   * the browser is not compositing, that transition never advances and tapping
   * the toggle appears to do nothing — measured, the panel still read
   * `visibility: hidden` after a click. Swapping to a keyframe animation was no
   * better: with the clock stopped it simply parks on the `from` frame, which
   * measured opacity 0 and a 10px offset that pushed the panel up under the
   * header.
   *
   * Anything whose *start* state is invisible can strand the menu shut. A menu
   * that cannot be opened is a broken site; a menu that appears without sliding
   * is a menu. Same trade already made for the theme flip. */
  .nav-links {
    display: none;
    position: absolute; top: 100%; left: 0; right: 0; z-index: 90;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: 6px 22px 18px;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow);
    max-height: calc(100dvh - 100%); overflow-y: auto;
  }
  .nav-links.open { display: flex; }

  .nav-links > li { border-bottom: 1px solid var(--line-soft); }
  .nav-links > li:last-child { border-bottom: 0; }
  /* The desktop rules that push the utilities to the right edge have to be
     unwound at matching specificity, or `margin-left: auto` shunts the social
     row to the far side of a full-width panel. */
  .nav-links .nav-theme + .nav-social { margin-left: 0; }
  .nav-links .nav-theme { margin-left: 0; }
  .nav-links a:not(.btn) {
    display: flex; align-items: center; width: 100%; min-height: 54px;
    font-size: 17.5px; font-weight: 700; color: var(--text);
  }
  .nav-links a[aria-current='true'] { color: var(--accent); }

  /* Social becomes a real row of tap targets rather than 30px decorations. */
  .nav-links .nav-social { padding: 12px 0; }
  .nav-links .nav-social .social-row { gap: 8px; }
  .nav-links .nav-social .social-row a { width: 46px; height: 46px; }
  .nav-links .nav-social .social-row svg { width: 20px; height: 20px; }

  /* The theme switch is the one control whose effect a glyph does not explain,
     and a panel has room for words. */
  .nav-links .nav-theme {
    justify-content: space-between; gap: 16px; min-height: 56px; margin-left: 0;
  }
  .nav-theme-label { display: inline; font-size: 16px; font-weight: 700; color: var(--text); }
  .nav-links .nav-theme .theme-toggle { width: 46px; height: 46px; border-color: var(--line); }
  .nav-links .nav-theme .theme-toggle svg { width: 20px; height: 20px; }

  .nav-links .nav-phone-item { padding: 6px 0; }
  .nav-links a.nav-phone { min-height: 48px; font-size: 16px; }

  html.menu-open, html.menu-open body { overflow: hidden; }
}

/* Very narrow: the tagline under the mark is the first thing to go, then the
   shop name, so the logo never crowds Book Now. */
@media (max-width: 430px) {
  .brand-tagline { display: none; }
  .brand-name { font-size: 15.5px; }
  .nav-book { padding-left: 14px; padding-right: 14px; }
}
@media (max-width: 350px) {
  .brand-name { display: none; }
}

/* ── Status pill (open now / next available) ──────────────────────────── */
.status {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 8px 16px 8px 13px; border-radius: 100px;
  font-size: 13.5px; font-weight: 700; letter-spacing: .01em;
  border: 1px solid var(--line);
  background: var(--surface);
}
.status.is-open   { background: var(--ok-soft);     border-color: var(--ok-line);     color: var(--ok); }
.status.is-closed { background: var(--closed-soft); border-color: var(--closed-line); color: var(--closed); }
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
.status.is-open .status-dot { animation: pulse 2.4s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .status.is-open .status-dot { animation: none; }
  * { transition-duration: .01ms !important; }
}

/* ── Hero ─────────────────────────────────────────────────────────────── */
/* A real photo behind the hero, dimmed hard enough that white text sits at
   AA over any part of it. Both competitors do this and it is most of what
   separates "a website" from "a shop with a website". */
.hero-bg {
  position: absolute; inset: 0; z-index: 0;
  background-size: cover; background-position: center;
  /* Scaled slightly so the blur never shows a soft edge at the frame. */
  filter: blur(2px) saturate(1.05); transform: scale(1.06);
  opacity: var(--hero-photo);
}

/* ── Hero video ───────────────────────────────────────────────────────────
   Sits inside `.hero-bg`, so it inherits the same blur, scale and scrim the
   photo gets and the two are interchangeable.

   `--hero-photo` is overridden up for video. A still can afford to be a faint
   texture; a clip at the same opacity is just a grey shimmer and nobody can
   tell what it is — which defeats the point of filming it.

   The scrim is shaped rather than flat. A wash heavy enough to guarantee the
   headline everywhere also drains the footage everywhere, which is the trade
   the first cut made and it cost too much: at p = .60 under a .38 wash the
   clip read as pale blue-grey haze. Contrast is only needed where the words
   are, so almost all of it is now a soft ellipse behind the text block and the
   full-bleed layer is light enough to leave the frame recognisable.

   Measured, not estimated: sampled against the darkest pixel under each line
   across twelve frames of the shipped clip, in both themes. Worst of the
   twelve —

     h1     4.5:1   (73.6px, so large text; its bar is 3:1)
     sub    6.6:1   (17.5px, bar 4.5:1)
     meta   4.8:1   (14px,   bar 4.5:1)

   Away from the text the ellipse falls off to ~.14 total alpha, which is where
   the footage actually shows and where nothing has to be legible. Re-measure
   if the clip is ever swapped: a much darker cut eats the h1 margin first.
   The check is in git history — sample the video into a canvas, composite
   video·p over --bg then the scrim over that, and compare against the computed
   colour of each line.
   ────────────────────────────────────────────────────────────────────────── */
.hero-video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
  /* Faded in on `playing`, so a decoding first frame never shows as black. */
  opacity: 0; transition: opacity .6s ease;
}
.hero-video.is-ready { opacity: 1; }

/* Scoped to a hero that actually got a video, so the photo hero is untouched. */
.hero-bg:has(.hero-video) {
  --hero-photo: .92;
  filter: saturate(1.04);
}
.hero-bg:has(.hero-video)::after {
  background:
    radial-gradient(940px 700px at 50% 52%, rgba(255,255,255,.54), transparent 76%),
    linear-gradient(180deg, rgba(255,255,255,.09) 0%, rgba(255,255,255,.14) 55%, var(--bg) 100%);
}
:root[data-theme='dark'] .hero-bg:has(.hero-video)::after {
  background:
    radial-gradient(940px 700px at 50% 52%, rgba(19,26,38,.58), transparent 76%),
    linear-gradient(180deg, rgba(19,26,38,.22) 0%, rgba(19,26,38,.34) 55%, var(--bg) 100%);
}

/* Dimmed greys are a device for a calm flat ground; over moving footage they
   stop being "secondary" and start being "hard to read" — measured, the sub
   dropped to 2.9:1 against the darkest frame. Over video the whole text column
   goes to full --text and the hierarchy is carried by size and weight instead,
   which is what actually separates these three lines anyway. */
.hero:has(.hero-video) .hero-sub,
.hero:has(.hero-video) .hero-meta { color: var(--text); }
/* The meta line sits at the bottom of the column where the ellipse has already
   fallen off, so it gets no opacity haircut on top of that — measured, .82 put
   it at 3.7:1. The ellipse is pulled down far enough to reach it. */
.hero:has(.hero-video) .hero-meta .dot { opacity: .45; }
/* The barber-pole stripes are removed so the hero background remains crisp and clean. */
.hero::after,
.hero:has(.hero-video)::after,
.hero:has(.hero-video)::before {
  display: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .hero-video { display: none; }
}
.hero-bg::after {
  content: ''; position: absolute; inset: 0;
  background: var(--hero-scrim);
}

.hero { position: relative; padding: 74px 0 82px; overflow: hidden; }
/* Two warm light sources rather than one flat wash — a brass glow top-right
   and a deeper amber pooling bottom-left. */
.hero::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: var(--hero-glow);
}
.hero .container { position: relative; z-index: 1; }

/* Centred single column. The opening-hours card that used to sit alongside is
   gone — hours live in the footer, and the hero's only job is to say what this
   is and give one obvious thing to tap. Fewer decisions above the fold. */
.hero-inner { max-width: 46rem; margin: 0 auto; text-align: center; position: relative; z-index: 1; }

/* Google rating badge. AJ's leads with this and it is the single most
   persuasive element on their page — social proof before any claim we make
   about ourselves. */
.google-badge {
  display: inline-flex; align-items: center; gap: 10px;
  background: #fff; color: #1f2328;
  border: 1px solid var(--badge-line); border-radius: 100px; padding: 6px 16px 6px 7px;
  font-size: 13.5px; font-weight: 600; text-decoration: none;
  box-shadow: var(--shadow-card);
  transition: transform .18s;
}
.google-badge:hover { transform: translateY(-2px); }
.google-badge .g-score {
  background: #1f2328; color: #fff; border-radius: 100px;
  padding: 3px 10px; font-weight: 800; font-variant-numeric: tabular-nums;
}
/* Not --star: the badge is a white pill in both themes, so its stars take
   the light theme's dark gold either way. Bright gold here is 2.1:1. */
.google-badge .g-stars { color: #9a6d04; letter-spacing: 1px; }
.google-badge .g-count { color: #5f6672; }

.hero h1 {
  font-size: clamp(2.5rem, 7vw, 4.6rem);
  white-space: pre-line;
  margin: 22px 0 20px;
}
.hero h1 em { font-style: normal; color: var(--accent); }

.hero-sub {
  color: var(--text-dim); font-size: 17.5px;
  max-width: 34rem; margin: 0 auto 32px;
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-bottom: 28px; }

.hero-meta {
  display: flex; flex-wrap: wrap; gap: 6px 12px; justify-content: center;
  color: var(--text-faint); font-size: 14px;
}
.hero-meta .dot { opacity: .5; }

.hero-scroll {
  display: grid; place-items: center;
  width: 42px; height: 42px; margin: 54px auto 0;
  border: 1px solid var(--line); border-radius: 50%;
  color: var(--text-faint); text-decoration: none; font-size: 15px;
  animation: hero-bob 2.6s ease-in-out infinite;
  transition: border-color .2s, color .2s;
}
.hero-scroll:hover { border-color: var(--accent-line); color: var(--accent); }
@keyframes hero-bob { 0%,100% { transform: translateY(0) } 50% { transform: translateY(6px) } }

/* Hours card */
.hours-card {
  background: linear-gradient(170deg, var(--surface) 0%, var(--bg-alt) 100%);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 24px 26px; box-shadow: var(--shadow);
}
.hours-card h3 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--accent); margin-bottom: 16px; font-weight: 700;
}
.hours-row {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 9px 0; border-bottom: 1px solid var(--line-soft); font-size: 14.5px;
}
.hours-row:last-of-type { border-bottom: 0; }
.hours-row.today { color: var(--accent-hi); font-weight: 700; }
.hours-row .day { color: var(--text-dim); }
.hours-row.today .day { color: var(--accent-hi); }
.hours-row .time { font-variant-numeric: tabular-nums; }
.hours-note {
  margin-top: 15px; padding-top: 15px; border-top: 1px solid var(--line-soft);
  font-size: 13.5px; color: var(--text-faint);
}

@media (max-width: 900px) {
  .hero { padding: 40px 0 46px; }
  .hero-scroll { display: none; }
}

/* ── Sections ─────────────────────────────────────────────────────────── */
.section { padding: 78px 0; border-top: 1px solid var(--line-soft); }
/* Alternating bands give the long page rhythm; the gradient keeps the warmth
   from going flat over a full screen height. */
.section.alt {
  background: linear-gradient(180deg, var(--bg-alt), var(--band-mid) 60%, var(--bg-alt));
}

.section-head { margin-bottom: 38px; max-width: 46rem; }
.eyebrow {
  display: block; font-size: 12px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 12px;
}
.section-head h2 { font-size: clamp(1.85rem, 3.6vw, 2.5rem); margin-bottom: 12px; }
.section-head p { color: var(--text-dim); font-size: 16.5px; }

/* ── Services ─────────────────────────────────────────────────────────── */
.svc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 14px; }

.svc {
  display: flex; align-items: flex-start; gap: 16px;
  background: linear-gradient(160deg, var(--surface), var(--surface-2));
  box-shadow: var(--shadow-card);
  border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px 22px;
  text-decoration: none; transition: border-color .16s, background .16s, transform .16s;
}
.svc:hover { border-color: var(--accent-line); background: var(--surface-2); transform: translateY(-2px); }

.svc { align-items: center; }
.svc-body { flex: 1; min-width: 0; }
.svc-name { font-weight: 700; font-size: 16.5px; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.svc-desc { color: var(--text-faint); font-size: 14px; margin-top: 5px; }

/* Prices and durations live in Square and appear at booking. The arrow is the
   only affordance the card needs — it says "this leads somewhere" without
   pretending to be a price list. */
.svc-go {
  flex: none; color: var(--text-faint); font-size: 18px;
  transition: transform .2s, color .2s;
}
.svc:hover .svc-go { color: var(--accent); transform: translateX(4px); }

.tag-popular {
  font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent); background: var(--accent-soft);
  border: 1px solid var(--accent-line); padding: 2px 8px; border-radius: 100px;
}

.svc-foot {
  margin-top: 24px; padding: 16px 20px; border-radius: var(--radius);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  color: var(--text-dim); font-size: 14.5px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
}

/* ── Barbers ──────────────────────────────────────────────────────────── */
.filter-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 26px;
}
.filter-label { font-size: 13.5px; color: var(--text-faint); margin-right: 4px; }
.chip {
  background: var(--surface); border: 1px solid var(--line); color: var(--text-dim);
  padding: 7px 15px; border-radius: 100px; font: inherit; font-size: 13.5px; font-weight: 600;
  cursor: pointer; transition: all .15s;
}
.chip:hover { border-color: var(--accent-line); color: var(--text); }
.chip[aria-pressed='true'] {
  background: var(--accent-fill); border-color: var(--accent-fill); color: #101720;
}

.barber-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 18px; }

.barber {
  background: linear-gradient(165deg, var(--surface), var(--surface-2));
  box-shadow: var(--shadow-card);
  border: 1px solid var(--line);
  border-radius: var(--radius); padding: 24px; display: flex; flex-direction: column;
  transition: border-color .16s, transform .16s;
}
.barber:hover { border-color: var(--accent-line); transform: translateY(-2px); }
.barber[hidden] { display: none; }

.barber-top { display: flex; align-items: center; gap: 15px; margin-bottom: 15px; }
.avatar {
  width: 60px; height: 60px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  font-size: 21px; font-weight: 800; color: #101720;
  border: 2px solid var(--avatar-ring);
}
.barber-name { font-size: 17.5px; font-weight: 800; }
.barber-title { font-size: 13.5px; color: var(--accent); font-weight: 600; margin-top: 2px; }
.barber-bio { color: var(--text-faint); font-size: 14.5px; flex: 1; }

.badges { display: flex; flex-wrap: wrap; gap: 7px; margin: 15px 0; }
.badge {
  font-size: 12px; font-weight: 600; padding: 4px 11px; border-radius: 100px;
  background: var(--bg); border: 1px solid var(--line); color: var(--text-dim);
}
.badge.lang { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-hi); }

.barber-next {
  font-size: 13.5px; color: var(--text-dim); margin-bottom: 14px;
  padding-top: 14px; border-top: 1px solid var(--line-soft);
}
.barber-next b { color: var(--ok); font-weight: 700; }

.empty-state {
  grid-column: 1 / -1; text-align: center; padding: 42px 20px;
  color: var(--text-faint); border: 1px dashed var(--line); border-radius: var(--radius);
}

/* Escape hatch for the customer who does not have a regular yet. Without it,
   picking a barber reads as compulsory. */
.team-any {
  text-align: center; margin-top: 26px;
  color: var(--text-faint); font-size: 15px;
}
.team-any a { color: var(--accent-hi); text-decoration: none; font-weight: 600; }
.team-any a:hover { text-decoration: underline; }

/* ── Inner-page hero ──────────────────────────────────────────────────────
   Shorter than the homepage hero and centred. It has one job — say what the
   page is — so it gets about half the height and none of the status furniture.
   ────────────────────────────────────────────────────────────────────────── */
.page-hero { position: relative; overflow: hidden; padding: 84px 0 72px; text-align: center; }
.page-hero::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: var(--page-glow);
}
.page-hero::after {
  content: ''; position: absolute; inset: 0; z-index: 0; opacity: var(--stripe-op);
  background: repeating-linear-gradient(115deg, var(--accent-fill) 0 2px, transparent 2px 22px);
}
.page-hero .container { position: relative; z-index: 1; }
.page-hero h1 {
  font-size: clamp(2.1rem, 5.2vw, 3.2rem); line-height: 1.07; letter-spacing: -.02em;
}
.page-hero > .container > p {
  color: var(--text-dim); font-size: 17px; margin: 16px auto 0; max-width: 40rem;
}
.page-hero-actions {
  display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 30px;
}

/* ── Team cards (services page) ───────────────────────────────────────────
   Omar's barber cards are a photo, a name and a button. These carry the title,
   a line of story and the real next opening, so choosing a barber is an
   informed decision rather than a coin flip on a face.
   ────────────────────────────────────────────────────────────────────────── */
.team-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)); gap: 20px; }

.team-card {
  background: linear-gradient(165deg, var(--surface), var(--surface-2));
  box-shadow: var(--shadow-card);
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; display: flex; flex-direction: column;
  transition: border-color .16s, transform .16s;
}
.team-card:hover { border-color: var(--accent-line); transform: translateY(-3px); }

/* A fixed portrait ratio so a row of cards lines up no matter what the shop
   uploads — phone snapshots are never all the same shape. */
.team-photo {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover; display: block;
  background-size: cover; background-position: center;
  border-bottom: 1px solid var(--line-soft);
}
.team-photo-placeholder {
  display: grid; place-items: center;
  font-size: 46px; font-weight: 800; color: #101720; letter-spacing: .02em;
}

.team-body { padding: 20px 20px 22px; display: flex; flex-direction: column; flex: 1; }
.team-name { font-size: 18px; font-weight: 800; }
.team-title { font-size: 13px; font-weight: 600; color: var(--accent); margin-top: 3px; }
.team-bio { color: var(--text-faint); font-size: 14.5px; margin-top: 12px; flex: 1; }
.team-next {
  font-size: 13px; color: var(--text-dim); margin: 14px 0;
  padding-top: 14px; border-top: 1px solid var(--line-soft);
}
.team-next b { color: var(--ok); font-weight: 700; }

/* ── Service menu (services page) ─────────────────────────────────────────
   Grouped the way a barber talks about the work — cuts, beard, the two
   together, threading — and every row shows the duration next to the price.
   Neither competitor publishes durations, and "45 min" is what tells someone
   whether a skin fade fits in a lunch break.
   ────────────────────────────────────────────────────────────────────────── */
.menu-group { margin-bottom: 42px; }
.menu-group:last-of-type { margin-bottom: 0; }

.menu-group-head {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  padding-bottom: 12px; border-bottom: 1px solid var(--line);
}
.menu-group-head h3 { font-size: 20px; font-weight: 800; letter-spacing: -.01em; }
.menu-group-head p { color: var(--text-faint); font-size: 14px; }

.menu-list { list-style: none; margin: 0; padding: 0; }
.menu-item {
  display: flex; align-items: center; gap: 20px;
  padding: 16px 14px; border-radius: 12px; text-decoration: none;
  border-bottom: 1px solid var(--line-soft);
  transition: background .16s;
}
.menu-list li:last-child .menu-item { border-bottom: 0; }
.menu-item:hover { background: var(--surface); }

.menu-item-main { flex: 1; min-width: 0; }
.menu-item-name {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  font-size: 16.5px; font-weight: 700; color: var(--text);
}
.menu-item-desc { display: block; color: var(--text-faint); font-size: 14px; margin-top: 4px; }

.menu-item-meta { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
.menu-item-dur { font-size: 12.5px; color: var(--text-faint); white-space: nowrap; }
.menu-item-price {
  font-size: 19px; font-weight: 800; color: var(--accent-hi);
  font-variant-numeric: tabular-nums;
}

.menu-foot { margin-top: 32px; text-align: center; color: var(--text-faint); font-size: 14.5px; }
.work-more { text-align: center; margin-top: 28px; }

/* On a phone the cards turn sideways — a portrait photo per barber at full
   width would be half a screen each, and six of them is a lot of scrolling to
   reach the prices. Landscape keeps the story visible, which is the whole
   reason the section exists. */
@media (max-width: 560px) {
  .page-hero { padding: 52px 0 46px; }
  .page-hero-actions .btn { width: 100%; }

  .team-grid { grid-template-columns: 1fr; gap: 12px; }
  .team-card { flex-direction: row; align-items: stretch; }
  .team-photo {
    width: 116px; flex: none; aspect-ratio: auto; align-self: stretch;
    border-bottom: 0; border-right: 1px solid var(--line-soft);
  }
  .team-photo-placeholder { font-size: 30px; }
  .team-body { padding: 15px 16px 16px; }
  .team-bio { margin-top: 8px; font-size: 14px; }
  .team-next { margin: 11px 0; padding-top: 11px; }

  .menu-item { gap: 14px; padding: 15px 10px; }
  .menu-item-price { font-size: 17.5px; }
}

/* ── Legal pages ──────────────────────────────────────────────────────────
   Long-form prose, so the column is narrow enough to read comfortably and the
   headings carry real space above them. Nobody reads these pages for pleasure;
   the least we can do is not make them hard work.
   ────────────────────────────────────────────────────────────────────────── */
.legal { border-top: 0; }
.legal .container { max-width: 44rem; }
.legal h1 { font-size: clamp(1.9rem, 4.4vw, 2.6rem); letter-spacing: -.02em; }
.legal h2 {
  font-size: 19px; font-weight: 800; margin: 38px 0 10px;
  padding-top: 18px; border-top: 1px solid var(--line-soft);
}
.legal p { color: var(--text-dim); font-size: 16px; line-height: 1.72; margin-bottom: 12px; }
.legal ul { color: var(--text-dim); font-size: 16px; line-height: 1.72; padding-left: 20px; }
.legal li { margin-bottom: 8px; }
.legal li b, .legal p b { color: var(--text); font-weight: 700; }
.legal a { color: var(--accent-hi); }
.legal-updated { font-size: 13.5px; color: var(--text-faint); margin-top: 10px; }

/* ── Location ─────────────────────────────────────────────────────────── */
.loc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: stretch; }
.loc-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 28px;
}
.loc-card h3 { font-size: 19px; margin-bottom: 14px; }
.loc-line { display: flex; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
.loc-line:last-child { border-bottom: 0; }
.loc-line .k { color: var(--text-faint); font-size: 13.5px; min-width: 74px; flex: none; }
.loc-line .v { font-size: 15px; }

/* Hours as three stacked rows, not one run-on line. */
.loc-hours-row {
  display: flex; gap: 12px; justify-content: space-between;
  font-variant-numeric: tabular-nums;
}
.loc-hours-row + .loc-hours-row { margin-top: 5px; }
.loc-hours-row .d { color: var(--text-dim); min-width: 62px; }
.loc-hours-row .t { white-space: nowrap; }
.loc-hours-row.today .d, .loc-hours-row.today .t { color: var(--accent-hi); font-weight: 600; }
.loc-line .v:has(.loc-hours-row) { flex: 1; }
.loc-line a { color: var(--accent-hi); text-decoration: none; }
.loc-line a:hover { text-decoration: underline; }

.map-embed {
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; min-height: 320px; background: var(--surface);
  display: grid; place-items: center; color: var(--text-faint); text-align: center; padding: 24px;
}
.map-embed iframe { width: 100%; height: 100%; min-height: 320px; border: 0; display: block; }

@media (max-width: 820px) { .loc-grid { grid-template-columns: 1fr; } }

/* ── About stats ──────────────────────────────────────────────────────── */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; margin-top: 28px; }
.stat {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px; text-align: center;
}
.stat-v { font-size: 25px; font-weight: 800; color: var(--accent); }
.stat-k { font-size: 12.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .09em; margin-top: 5px; }

/* ── CTA band ─────────────────────────────────────────────────────────────
   The homepage band was removed at the client's request; `.cta-actions` is
   still used by the 404 page, so the block stays and stays theme-aware. */
.cta {
  background: var(--page-glow);
  border-top: 1px solid var(--accent-line); border-bottom: 1px solid var(--accent-line);
  padding: 58px 0; text-align: center;
}
.cta h2 { font-size: clamp(1.7rem, 3.4vw, 2.3rem); margin-bottom: 12px; }
.cta p { color: var(--text-dim); margin-bottom: 26px; }
.cta-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

/* ── Footer ───────────────────────────────────────────────────────────── */
/* Hours + address appear on every page. AJ's site omits both entirely, and
   "what time do they close" is one of the most common local searches. */
.footer {
  background: linear-gradient(180deg, var(--bg-alt), var(--footer-end));
  border-top: 1px solid var(--line);
  padding: 58px 0 26px;
}
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1.1fr 1.1fr; gap: 34px; }

/* Brand block */
.footer-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; text-decoration: none; }
.footer-brand .brand-mark { width: 48px; height: 48px; font-size: 22px; border-radius: 12px; }
.footer-brand-name { font-weight: 800; font-size: 18px; color: var(--text); }
.footer-brand-tag {
  font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--accent); font-weight: 700;
}
.footer .social-row { margin-top: 14px; }
.footer .social-row a { border: 1px solid var(--line); }

/* Hours, grouped into ranges rather than seven near-identical rows. */
.footer-hours-list { list-style: none; margin: 0; padding: 0; }
.footer-hours-list li {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 6px 0; font-variant-numeric: tabular-nums;
}
.footer-hours-list .d { color: var(--text-dim); }
.footer-hours-list .t { color: var(--text); font-weight: 600; white-space: nowrap; }
.footer-hours-list li.today .d,
.footer-hours-list li.today .t { color: var(--accent-hi); }

.footer-note {
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line-soft);
  font-size: 13px; color: var(--text-faint);
}

/* Direct line block */
.footer-direct a { color: var(--accent-hi); text-decoration: none; font-weight: 600; }
.footer-direct a:hover { text-decoration: underline; }

.footer-legal {
  display: flex; gap: 18px; flex-wrap: wrap;
}
.made-with {
  display: inline-flex; align-items: center; gap: 6px;
}
.made-with .heart {
  color: var(--heart); display: inline-block;
  animation: heartbeat 2.4s ease-in-out infinite;
}
@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  8%  { transform: scale(1.25); }
  16% { transform: scale(1); }
  24% { transform: scale(1.18); }
  32% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) { .made-with .heart { animation: none; } }
.footer h4 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--accent); margin-bottom: 14px;
}
.footer p, .footer li { color: var(--text-dim); font-size: 14.5px; }
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { padding: 4px 0; }
/* `:not(.btn)` for the same reason the nav needs it: this rule sits after
   .btn-primary in the file, so without it the footer's Book button inherited
   --text-dim and rendered grey on brass — 3.3:1, and the one button down there
   that matters. */
.footer a:not(.btn) { color: var(--text-dim); text-decoration: none; }
.footer a:not(.btn):hover { color: var(--accent-hi); }
.footer .brand { margin-bottom: 14px; }
.footer-hours { display: flex; justify-content: space-between; gap: 14px; font-variant-numeric: tabular-nums; }
.footer-bottom {
  margin-top: 36px; padding-top: 20px; border-top: 1px solid var(--line-soft);
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  color: var(--text-faint); font-size: 13px;
}
@media (max-width: 980px) { .footer-grid { grid-template-columns: 1fr 1fr; gap: 30px; } }
@media (max-width: 620px) {
  .footer-grid { grid-template-columns: 1fr; gap: 30px; }
  .footer .social-row a { width: 44px; height: 44px; }

  /* On a phone the footer is a single column, so a left-aligned logo floating
     above centred-feeling content looks accidental. Centre the brand block and
     the credit; the three information columns stay left-aligned because lists
     of hours and addresses are read, not admired. */
  .footer-brand { align-items: center; text-align: center; width: 100%; }
  .footer .social-row { justify-content: center; }

  .footer-bottom {
    flex-direction: column; align-items: center; gap: 12px; text-align: center;
  }
  .footer-legal { justify-content: center; }
  .made-with { justify-content: center; }
}

/* ==========================================================================
   Intro splash
   Sits on top of a fully rendered page, so content is never blocked. See
   splash.js for the rules it has to obey.
   ========================================================================== */
.splash {
  position: fixed; inset: 0; z-index: 9999;
  background: var(--bg);
  display: grid; place-items: center;
  overflow: hidden; cursor: pointer;
  animation: splash-in .45s ease both;
}
.splash::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(620px 420px at 50% 42%, var(--splash-glow), transparent 68%);
}
/* Barber-pole stripes, drifting. The one flourish the whole thing is built on. */
.splash::after {
  content: ''; position: absolute; inset: -60% -20%;
  background: repeating-linear-gradient(115deg,
    var(--splash-stripe) 0 3px, transparent 3px 26px);
  animation: splash-drift 9s linear infinite;
}

.splash-inner { position: relative; text-align: center; padding: 20px; }

.splash-mark {
  width: 104px; height: 104px; margin: 0 auto 22px;
  border-radius: 26px;
  background: linear-gradient(150deg, var(--accent-fill) 0%, #a17f18 100%);
  display: grid; place-items: center;
  font-size: 42px; font-weight: 900; letter-spacing: -0.03em; color: #101720;
  box-shadow: 0 22px 60px rgba(201,162,39,.30);
  animation: splash-mark 1.1s cubic-bezier(.2,.8,.2,1) both;
}

.splash-name {
  font-size: clamp(1.5rem, 4.6vw, 2.2rem); font-weight: 800;
  letter-spacing: -0.02em; color: var(--text);
  animation: splash-rise .8s cubic-bezier(.2,.8,.2,1) .22s both;
}
.splash-tag {
  margin-top: 8px; font-size: 13px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--accent);
  animation: splash-rise .8s cubic-bezier(.2,.8,.2,1) .34s both;
}
.splash-rule { margin: 24px auto 0; width: 132px; height: 2px; background: var(--line); overflow: hidden; }
.splash-rule i { display: block; height: 100%; width: 100%; background: var(--accent-fill);
  transform-origin: left; animation: splash-wipe 1.5s cubic-bezier(.4,0,.2,1) .2s both; }

.splash-skip {
  position: absolute; right: 20px; bottom: 20px;
  background: none; border: 1px solid var(--line); color: var(--text-faint);
  border-radius: 100px; padding: 7px 16px; font: inherit; font-size: 12.5px; cursor: pointer;
}
.splash-skip:hover { color: var(--text); border-color: var(--accent-line); }

.splash-out { animation: splash-fade .62s ease forwards; pointer-events: none; }

/* Stop the page scrolling behind the overlay while it is up. */
html.splash-open, html.splash-open body { overflow: hidden; }

@keyframes splash-in   { from { opacity: 0 } to { opacity: 1 } }
@keyframes splash-fade { to { opacity: 0; transform: scale(1.04) } }
@keyframes splash-mark {
  from { opacity: 0; transform: translateY(16px) scale(.82) rotate(-8deg) }
  to   { opacity: 1; transform: none }
}
@keyframes splash-rise { from { opacity: 0; transform: translateY(14px) } to { opacity: 1; transform: none } }
@keyframes splash-wipe { from { transform: scaleX(0) } to { transform: scaleX(1) } }
@keyframes splash-drift { to { transform: translateX(-26px) } }

/* splash.js already bails out on prefers-reduced-motion; this is the belt to
   its braces in case the markup ever ships server-rendered. */
@media (prefers-reduced-motion: reduce) {
  .splash { display: none; }
  html.splash-open, html.splash-open body { overflow: auto; }
}

/* ── Section reveal ───────────────────────────────────────────────────────
   Sections fade up as they come into view. Applied by IntersectionObserver in
   app.js, which adds `.is-in`. Content is visible by default and only hidden
   once JS confirms it can un-hide it — so with JS broken or blocked the page
   still reads normally rather than being blank.
   ────────────────────────────────────────────────────────────────────────── */
/* The hiding class is applied to each element by JS, not inherited from an
   ancestor. An ancestor-based rule (`.js-reveal .reveal`) is one stylesheet
   quirk away from leaving the whole page invisible; this way the only element
   that can ever be hidden is one JS has already committed to revealing. */
.reveal.will-reveal {
  opacity: 0; transform: translateY(22px);
  transition: opacity .7s cubic-bezier(.2,.8,.2,1), transform .7s cubic-bezier(.2,.8,.2,1);
}
.reveal.will-reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal.will-reveal { opacity: 1; transform: none; transition: none; }
  .hero-scroll { animation: none; }
}

/* ── Sticky book bar (phones) ─────────────────────────────────────────────
   Nearly all of a barbershop's traffic is mobile. This keeps the one action
   that matters in thumb reach however far down the page someone is, and it
   only appears once they have scrolled past the hero's own buttons.
   ────────────────────────────────────────────────────────────────────────── */
.book-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
  display: none; gap: 10px; align-items: center;
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  background: var(--bar-bg); backdrop-filter: blur(14px);
  box-shadow: var(--bar-shadow);
  border-top: 1px solid var(--line);
  transform: translateY(110%); transition: transform .32s cubic-bezier(.2,.8,.2,1);
}
.book-bar.is-up { transform: none; }
.book-bar .btn-primary { flex: 1; min-height: 50px; }
.book-bar .btn-ghost { flex: 0 0 auto; min-height: 50px; }

@media (max-width: 780px) {
  .book-bar { display: flex; }
  /* Room so the footer is never trapped behind the bar. */
  .footer { padding-bottom: 96px; }
}

/* ── Demo ribbon ──────────────────────────────────────────────────────── */
.demo-ribbon {
  background: var(--ribbon-bg); border-bottom: 1px solid var(--accent-line);
  color: var(--accent-hi); font-size: 13px; text-align: center; padding: 8px 16px;
}
.demo-ribbon b { color: var(--text); }

/* ==========================================================================
   Gallery
   ========================================================================== */

/* Masonry via CSS columns. Barbershop photos arrive in whatever aspect ratio
   the barber's phone produced, and columns absorb that without cropping
   anyone's work — which a fixed grid would. */
.gallery-grid { columns: 3 260px; column-gap: 14px; }
.gallery-item {
  break-inside: avoid; margin: 0 0 14px; position: relative; display: block;
  border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line);
  background: var(--surface); cursor: zoom-in; width: 100%; padding: 0;
}
.gallery-item img {
  width: 100%; height: auto; display: block;
  transition: transform .4s cubic-bezier(.2,.8,.2,1);
  background: var(--surface-2);
}
.gallery-item:hover img { transform: scale(1.035); }
.gallery-item:hover { border-color: var(--accent-line); }

.gallery-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 26px 14px 12px; text-align: left;
  background: linear-gradient(to top, rgba(0,0,0,.82), transparent);
  color: #fff; font-size: 13.5px; font-weight: 600;
  opacity: 0; transition: opacity .22s;
}
.gallery-item:hover .gallery-cap,
.gallery-item:focus-visible .gallery-cap { opacity: 1; }

.gallery-empty {
  border: 1px dashed var(--line); border-radius: var(--radius);
  padding: 54px 24px; text-align: center; color: var(--text-faint);
}

/* ── Homepage carousel ────────────────────────────────────────────────────
   A slow continuous drift rather than a click-through slideshow. The images
   are duplicated once and the track translates exactly -50%, so the loop is
   seamless with no jump at the wrap point.

   It pauses on hover and on keyboard focus — a strip that keeps sliding while
   you are trying to look at one photo is an irritation, not a feature.
   ────────────────────────────────────────────────────────────────────────── */
.carousel {
  position: relative; overflow: hidden;
  /* Feathered edges, so photos enter and leave rather than being chopped. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

/* Spacing is `margin-right` on each item, deliberately NOT `gap`.
   With gap, the track measures 2·S + g·(2n−1), so −50% lands g/2 short of the
   duplicate's start and the loop stutters ~8px every cycle. With a trailing
   margin on every item the track is exactly 2·(S + g·n), and −50% is exact. */
.carousel-track {
  display: flex; width: max-content;
  animation: carousel-drift 64s linear infinite;
  will-change: transform;
}
.carousel:hover .carousel-track,
.carousel:focus-within .carousel-track { animation-play-state: paused; }

@keyframes carousel-drift {
  from { transform: translate3d(0, 0, 0); }
  /* -50% because the track holds the set twice. */
  to   { transform: translate3d(-50%, 0, 0); }
}

.carousel-item {
  flex: 0 0 auto;
  margin-right: 16px;
  /* Sized off the viewport, not a fixed max, so the strip fills a wide screen
     instead of sitting as a small band in the middle of it. */
  width: clamp(200px, 21vw, 420px);
  aspect-ratio: 4 / 5;
  border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line); background: var(--surface);
  padding: 0; cursor: zoom-in; position: relative;
  transition: transform .45s cubic-bezier(.2,.8,.2,1), border-color .3s;
}
.carousel-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.carousel-item:hover, .carousel-item:focus-visible {
  transform: translateY(-6px) scale(1.02); border-color: var(--accent-line);
}
.carousel-item::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(10,16,26,.55), transparent 45%);
  opacity: .75; transition: opacity .3s;
}
.carousel-item:hover::after { opacity: .3; }

.carousel-cap {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  padding: 22px 14px 12px; text-align: left;
  color: #fff; font-size: 13px; font-weight: 600;
  transform: translateY(6px); opacity: 0; transition: all .3s;
}
.carousel-item:hover .carousel-cap { transform: none; opacity: 1; }

/* Anyone who has asked for less movement gets a still grid instead. This kind
   of continuous drift is a genuine nausea trigger for some people. */
@media (prefers-reduced-motion: reduce) {
  .carousel-track {
    animation: none;
    flex-wrap: wrap; width: 100%; justify-content: center; gap: 14px;
  }
  .carousel { -webkit-mask-image: none; mask-image: none; }
  .carousel-item { width: clamp(150px, 30%, 240px); margin-right: 0; }
  .carousel-item:hover { transform: none; }
  /* The duplicates exist only to make the drift loop; with no drift they are
     just the same photos twice. */
  .carousel-item[aria-hidden] { display: none; }
}

@media (max-width: 620px) {
  .carousel-track { animation-duration: 40s; }
  /* Nearly full width on a phone — a photo of a haircut at 46vw is too small
     to judge, which defeats the point of showing it. */
  .carousel-item { width: 78vw; margin-right: 12px; aspect-ratio: 4 / 5; }
}

/* ==========================================================================
   Reviews
   ========================================================================== */
.reviews-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 14px;
}

.review {
  background: linear-gradient(165deg, var(--surface), var(--surface-2));
  box-shadow: var(--shadow-card);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 22px 24px; display: flex; flex-direction: column; gap: 12px;
  position: relative; overflow: hidden;
}
.review::before {
  content: '"'; position: absolute; top: -22px; right: 12px;
  font-size: 110px; line-height: 1; color: var(--accent-fill); opacity: var(--quote-op);
  font-family: Georgia, serif;
}
.review-stars { color: var(--star); letter-spacing: 2px; font-size: 14px; }
.review-text { color: var(--text-dim); font-size: 15px; line-height: 1.65; flex: 1; }
.review-foot { display: flex; align-items: center; gap: 11px; }
.review-av {
  width: 36px; height: 36px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-weight: 800; font-size: 13px; color: #101720;
}
.review-name { font-weight: 700; font-size: 14.5px; }
.review-when { font-size: 12.5px; color: var(--text-faint); }

.reviews-cta { text-align: center; margin-top: 30px; }
.reviews-note {
  text-align: center; margin-top: 14px;
  font-size: 12.5px; color: var(--text-faint);
}

@media (max-width: 620px) {
  .reviews-grid { grid-template-columns: 1fr; }
}

/* Lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 500; display: grid; place-items: center;
  /* Deliberately dark even on a white site: a photo viewer's job is to get
     everything except the photo out of the way. */
  background: rgba(18,16,12,.93); padding: 30px 16px;
  animation: splash-in .18s ease both;
}
.lightbox img {
  max-width: min(1100px, 94vw); max-height: 84vh; width: auto; height: auto;
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.lightbox-cap { color: var(--text-dim); font-size: 14.5px; margin-top: 14px; text-align: center; max-width: 40rem; }
.lightbox-close, .lightbox-nav {
  position: absolute; background: var(--surface); border: 1px solid var(--line);
  color: var(--text); border-radius: 50%; width: 46px; height: 46px;
  font-size: 20px; cursor: pointer; display: grid; place-items: center;
}
.lightbox-close { top: 18px; right: 18px; }
.lightbox-nav.prev { left: 18px; top: 50%; transform: translateY(-50%); }
.lightbox-nav.next { right: 18px; top: 50%; transform: translateY(-50%); }
.lightbox-close:hover, .lightbox-nav:hover { border-color: var(--accent); color: var(--accent); }
.lightbox-count { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
  color: var(--text-faint); font-size: 13px; font-variant-numeric: tabular-nums; }

@media (max-width: 620px) {
  .gallery-grid { columns: 2 140px; column-gap: 10px; }
  .gallery-item { margin-bottom: 10px; }
  .lightbox-nav { width: 42px; height: 42px; }
  .lightbox-nav.prev { left: 8px; }
  .lightbox-nav.next { right: 8px; }
}

/* ==========================================================================
   Booking — embedded Square widget
   The shop's calendar lives in Square, but the customer stays on this domain.
   ========================================================================== */

.booking-frame-wrap {
  position: relative;
  max-width: 900px; margin: 0 auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--surface);
  box-shadow: var(--shadow);
  min-height: 620px;
}

.booking-frame {
  width: 100%; min-height: 760px; border: 0; display: block;
  /* Square's widget renders on a white ground, same as the page now does —
     the fade is only so it does not pop in half-laid-out. */
  opacity: 0; transition: opacity .45s ease;
  background: #fff;
}
.booking-frame.is-ready { opacity: 1; }

.booking-skeleton {
  position: absolute; inset: 0; display: grid; place-items: center;
  gap: 14px; color: var(--text-faint); font-size: 14.5px;
  background: var(--surface); z-index: 1;
}
.booking-spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--accent);
  animation: booking-spin .9s linear infinite;
}
@keyframes booking-spin { to { transform: rotate(360deg); } }

.booking-fallback {
  padding: 60px 24px; text-align: center;
}

.booking-help {
  text-align: center; margin-top: 22px;
  color: var(--text-faint); font-size: 14.5px;
}

@media (prefers-reduced-motion: reduce) {
  .booking-spinner { animation-duration: 2.4s; }
  .booking-frame { transition: none; opacity: 1; }
}

@media (max-width: 620px) {
  .booking-frame-wrap { min-height: 560px; border-radius: var(--radius-sm); }
  .booking-frame { min-height: 700px; }
}

/* ==========================================================================
   Booking flow — built-in engine
   Used when SHOP.booking.provider === 'builtin'. Live code, not dead: the
   next shop may not own Square.
   ========================================================================== */
.book-wrap { max-width: 760px; margin: 0 auto; padding: 44px 22px 80px; }

/* State classes are namespaced `is-*` on purpose. An earlier version used a
   bare `.done` here, which silently collided with the confirmation screen's
   `.done` rule below and gave the completed step 26px of padding, knocking it
   out of line with the others. */
.steps { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 34px; }
.step-pip { flex: 1; min-width: 0; }
.step-pip .bar { height: 4px; border-radius: 4px; background: var(--line); transition: background .25s; }
.step-pip .lbl {
  font-size: 12px; color: var(--text-faint); margin-top: 9px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.step-pip.is-done .bar, .step-pip.is-active .bar { background: var(--accent); }
.step-pip.is-active .lbl { color: var(--accent); }
.step-pip.is-done .lbl { color: var(--text-dim); }

.step { display: none; }
.step.active { display: block; animation: fade .22s ease; }
@keyframes fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.step h2 { font-size: 1.7rem; margin-bottom: 7px; }
.step-hint { color: var(--text-dim); margin-bottom: 24px; font-size: 15.5px; }

.pick-list { display: grid; gap: 10px; }
.pick {
  display: flex; align-items: center; gap: 15px; width: 100%; text-align: left;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 17px 20px; color: var(--text); font: inherit; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.pick:hover { border-color: var(--accent-line); background: var(--surface-2); }
.pick[aria-pressed='true'] { border-color: var(--accent); background: var(--accent-soft); }
.pick-main { flex: 1; min-width: 0; }
.pick-title { font-weight: 700; font-size: 16px; }
.pick-sub { color: var(--text-faint); font-size: 13.5px; margin-top: 3px; }
.pick-right { text-align: right; flex: none; }
.pick-price { font-weight: 800; color: var(--accent); font-size: 18px; font-variant-numeric: tabular-nums; }
.pick-dur { font-size: 12.5px; color: var(--text-faint); margin-top: 2px; }

/* Date strip */
.date-strip {
  display: flex; gap: 9px; overflow-x: auto; padding: 4px 4px 14px;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
}
.date-btn {
  flex: none; width: 76px; scroll-snap-align: start;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px 6px; text-align: center; cursor: pointer; color: var(--text); font: inherit;
  transition: all .15s;
}
.date-btn:hover:not(:disabled) { border-color: var(--accent-line); }
.date-btn[aria-pressed='true'] { background: var(--accent-fill); border-color: var(--accent-fill); color: #101720; }
.date-btn:disabled { opacity: .3; cursor: not-allowed; }
.date-dow { font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em; opacity: .75; }
.date-day { font-size: 21px; font-weight: 800; line-height: 1.25; font-variant-numeric: tabular-nums; }
.date-mon { font-size: 11.5px; opacity: .75; }

/* Time slots */
.slot-note {
  font-size: 13.5px; color: var(--text-faint); margin: 18px 0 12px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.slot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 9px; }
.slot {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px 8px; font: inherit; font-size: 14.5px; font-weight: 600; color: var(--text);
  cursor: pointer; transition: all .14s; font-variant-numeric: tabular-nums;
}
.slot:hover { border-color: var(--accent-line); color: var(--accent-hi); }
.slot[aria-pressed='true'] { background: var(--accent-fill); border-color: var(--accent-fill); color: #101720; }

.slot-group-label {
  grid-column: 1 / -1; font-size: 11.5px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--text-faint); margin-top: 14px; font-weight: 700;
}
.slot-group-label:first-child { margin-top: 0; }

/* Form */
.field { margin-bottom: 17px; }
.field label { display: block; font-size: 14px; font-weight: 600; margin-bottom: 7px; }
.field .req { color: var(--accent); }
.field input, .field textarea {
  width: 100%; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 13px 15px; color: var(--text);
  font: inherit; font-size: 16px; /* 16px stops iOS zooming on focus */
}
.field input:focus, .field textarea:focus { outline: none; border-color: var(--accent); }
.field .help { font-size: 12.5px; color: var(--text-faint); margin-top: 6px; }
.field.err input { border-color: var(--closed); }
.field .err-msg { font-size: 13px; color: var(--closed); margin-top: 6px; }

.check { display: flex; gap: 11px; align-items: flex-start; margin: 20px 0; }
.check input { width: 18px; height: 18px; margin-top: 2px; flex: none; accent-color: var(--accent); }
.check label { font-size: 13.5px; color: var(--text-dim); line-height: 1.5; }

/* Summary */
.summary {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px 22px; margin-bottom: 24px;
}
.summary-row { display: flex; justify-content: space-between; gap: 16px; padding: 8px 0; font-size: 15px; }
.summary-row .k { color: var(--text-faint); }
.summary-row .v { font-weight: 600; text-align: right; }
.summary-total {
  border-top: 1px solid var(--line); margin-top: 8px; padding-top: 14px;
  font-size: 18px; font-weight: 800;
}
.summary-total .v { color: var(--accent); }

.step-actions { display: flex; gap: 11px; margin-top: 26px; }
.step-actions .btn-ghost { flex: none; }
.step-actions .btn-primary { flex: 1; }

/* Confirmation screen */
.confirm-screen { text-align: center; padding: 26px 0; }
.confirm-mark {
  width: 68px; height: 68px; border-radius: 50%; margin: 0 auto 22px;
  background: var(--ok-soft); border: 2px solid var(--ok); color: var(--ok);
  display: grid; place-items: center; font-size: 32px;
}
.confirm-screen h2 { font-size: 1.9rem; margin-bottom: 10px; }
.confirm-screen p { color: var(--text-dim); margin-bottom: 24px; }
.confirm-screen .summary { text-align: left; }

@media (max-width: 620px) {
  .book-wrap { padding: 26px 18px 60px; }
  .step-pip .lbl { display: none; }
  .step-actions { flex-direction: column-reverse; }
  .step-actions .btn { width: 100%; }
}

/* ── Touch targets ────────────────────────────────────────────────────────
   Apple's guidance is a 44x44px minimum, and a barbershop's traffic is almost
   entirely phones. Several controls sit at 37-42px at their desktop sizes, so
   they get floored here rather than shrunk to fit.
   ────────────────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .btn { min-height: 48px; }
  .btn-sm { min-height: 44px; }
  .chip {
    min-height: 44px;
    display: inline-flex; align-items: center;
    padding-top: 0; padding-bottom: 0;
  }
  .nav-toggle { width: 44px; height: 44px; }
  .slot { min-height: 46px; }
  .date-btn { min-height: 76px; }
  .nav-links.open a { min-height: 44px; display: flex; align-items: center; }
}

/* Two owners, two numbers — stacked, each labelled with whose it is, so a
   customer is never choosing blind between a pair of bare digits. */
#locPhones { display: flex; flex-direction: column; gap: 4px; }
.loc-phone { display: flex; align-items: baseline; gap: 8px; }
.loc-phone-who {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-dim);
}
