/* Edit Studio — base styles */
:root {
  --bg: #efeae0;
  --ink: #141210;
  --ink-soft: #4a4540;
  --ink-faint: rgba(20,18,16,0.42);
  --rule: rgba(20,18,16,0.14);
  --paper: #f7f3eb;
  --accent: oklch(0.42 0.12 25);
  --accent-2: oklch(0.78 0.14 70);
  --accent-3: oklch(0.82 0.08 20);
  --display: "Fraunces", "Times New Roman", serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --body: "Inter Tight", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --easing-cinematic: cubic-bezier(0.65, 0, 0.35, 1);
  --easing-spring: cubic-bezier(0.34, 1.2, 0.64, 1);
  /* Colour iOS Safari extends into its status/toolbar strips. Seeded to the home
     panel (the default landing) so first paint is already right; app.jsx rewrites
     it per panel. A deep link to another service flashes this for one frame. */
  --chrome-tint: #f5d0cf;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* --chrome-tint is rewritten per panel in app.jsx. It needs a real initial value
   rather than falling back to --bg: measured on an iPhone 17 Pro Max, iOS Safari
   lays the page out in the 796pt safe area (not the full 956pt screen) and fills
   the leftover 62pt status strip and ~98pt toolbar strip by extending the page's
   background colour. It samples that colour at first paint, before the per-panel
   JS has run, so a fallback to --bg is what painted those strips flat beige. */
html, body { margin: 0; padding: 0; background: var(--chrome-tint); color: var(--ink); font-family: var(--body); }
/* The document is the scroller. It used to be overflow:hidden at a fixed
   100dvh, with all movement faked by transforms — which is why iOS never
   collapsed its toolbar (no root scroll to react to) and why content could
   never reach the status/toolbar strips. Nothing here may reintroduce a fixed
   height or overflow:hidden on html/body without bringing both back. */
body { min-height: 100svh; }

#root { width: 100%; }

/* ── App shell ─────────────────────────────────────────────── */
.app {
  position: relative;
  background: var(--chrome-tint, var(--bg));
  color: var(--ink);
  /* Only the horizontal axis is clipped — clipping vertically would turn this
     back into a scroll container and undo the whole point. */
  overflow-x: clip;
  isolation: isolate;
}

/* Announcement strip */
:root { --announce-h: 0px; }
.app[data-announce="true"] { --announce-h: 36px; }
.app[data-announce="true"] .chrome-top { top: var(--announce-h); }
.announce {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: var(--announce-h);
  display: flex; align-items: stretch;
  z-index: 20;
  overflow: hidden;
  animation: announce-in 0.45s var(--easing-spring, ease) both;
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}

/* Parchment — warm tone derived from page bg, palette-aware */
.announce[data-style="parchment"] {
  background: color-mix(in oklch, var(--bg), var(--ink) 9%);
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
.announce[data-style="parchment"] .announce-body:hover { background: color-mix(in oklch, var(--bg), var(--ink) 15%); }
.announce[data-style="parchment"] .announce-dot { background: var(--accent); }
.announce[data-style="parchment"] .announce-close { color: var(--ink-faint); border-left: 1px solid var(--rule); }
.announce[data-style="parchment"] .announce-close:hover { color: var(--ink); background: color-mix(in oklch, var(--bg), var(--ink) 14%); }

/* Lime — fresh chartreuse, dark green ink */
.announce[data-style="lime"] {
  background: oklch(0.91 0.15 122);
  color: oklch(0.22 0.05 135);
  border-bottom: 1px solid oklch(0.74 0.17 122);
}
.announce[data-style="lime"] .announce-body:hover { background: oklch(0.87 0.17 122); }
.announce[data-style="lime"] .announce-dot { background: oklch(0.32 0.08 138); }
.announce[data-style="lime"] .announce-close {
  color: oklch(0.30 0.06 135);
  border-left: 1px solid oklch(0.74 0.17 122);
}
.announce[data-style="lime"] .announce-close:hover { color: oklch(0.18 0.04 135); background: oklch(0.84 0.18 122); }

/* Ink — original bold treatment */
.announce[data-style="ink"] {
  background: var(--ink);
  color: var(--bg);
  border-bottom: 1px solid rgba(0,0,0,0.18);
}
.announce[data-style="ink"] .announce-body:hover { background: rgba(255,255,255,0.06); }
.announce[data-style="ink"] .announce-dot { background: var(--accent-2, currentColor); }
.announce[data-style="ink"] .announce-close {
  color: inherit;
  opacity: 0.6;
  border-left: 1px solid rgba(255,255,255,0.12);
}
.announce[data-style="ink"] .announce-close:hover { opacity: 1; background: rgba(255,255,255,0.08); }
@keyframes announce-in {
  from { transform: translateY(-100%); }
  to   { transform: translateY(0); }
}
.announce-body {
  flex: 1;
  display: flex; align-items: center; gap: 12px;
  padding: 0 22px;
  background: transparent;
  border: none;
  color: inherit;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  text-align: left;
  transition: background 0.25s ease;
  min-width: 0;
}
.announce-body:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: -3px;
}
.announce-dot {
  flex: 0 0 auto;
  width: 7px; height: 7px;
  border-radius: 50%;
  animation: announce-pulse 2.4s ease-in-out infinite;
}
@keyframes announce-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.55; transform: scale(0.82); }
}
.announce-text {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0.82;
}
.announce-arr {
  flex: 0 0 auto;
  font-family: var(--display);
  font-style: italic;
  font-size: 13px;
  letter-spacing: 0;
  text-transform: none;
  opacity: 0.7;
  transition: transform 0.3s var(--easing-spring, ease), opacity 0.2s ease;
}
.announce-body:hover .announce-arr {
  transform: translateY(3px);
  opacity: 1;
}
.announce-close {
  flex: 0 0 auto;
  width: 36px;
  background: transparent;
  border: none;
  color: inherit;
  font-family: var(--display);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
.announce-close:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: -3px;
}
@media (max-width: 540px) {
  .app[data-announce="true"] { --announce-h: 40px; }
  .announce-body { padding: 0 14px; font-size: 10px; letter-spacing: 0.1em; }
  .announce-arr { display: none; }
}

/* Top chrome. Sits at the top of the document and scrolls away with the hero.
   The safe-area inset is 0 in normal iOS Safari (measured), but non-zero when
   the site is launched standalone from the home screen — there is a
   manifest.json, so that is a real case — and there the page really does start
   under the status bar. env() with a 0px fallback covers both. */
.chrome-top {
  position: absolute; top: 0; left: 0; right: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 20px;
  padding-top: calc(18px + env(safe-area-inset-top, 0px));
  z-index: 50;
  pointer-events: none;
  color: var(--ink);
}
.chrome-top .lockup {
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 22px;
  letter-spacing: -0.01em;
  line-height: 1;
  display: flex;
  align-items: center;
  pointer-events: auto;
}
.chrome-top .lockup-logo {
  height: 44px;
  width: auto;
  display: block;
  /* mix-blend-mode: difference on the parent inverts white/black, so we
     pick the asset that matches the active background. */
}
@media (min-width: 760px) {
  .chrome-top .lockup-logo { height: 56px; }
}
.chrome-top .lockup em { font-style: italic; }
.chrome-top .meta {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: flex; gap: 12px;
  pointer-events: auto;
}
.chrome-top .meta span { opacity: 0.8; }
.chrome-top .chrome-ig {
  display: inline-flex; align-items: baseline; gap: 4px;
  margin-left: 10px;
  padding-left: 12px;
  border-left: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  color: inherit;
  text-decoration: none;
  opacity: 0.7;
  transition: opacity 0.25s ease, gap 0.25s ease;
}
.chrome-top .chrome-ig:hover { opacity: 1; gap: 6px; }
.chrome-top .chrome-ig-label { letter-spacing: 0.12em; }
.chrome-top .chrome-ig-arr {
  font-family: var(--display);
  font-style: italic;
  font-size: 12px;
  line-height: 1;
}

/* Sticky top pill nav */
.chrome-nav {
  position: absolute; top: 86px; left: 0; right: 0;
  z-index: 49;
  display: flex; justify-content: center;
  pointer-events: none;
  transition: opacity 0.4s ease;
}
.app[data-announce="true"] .chrome-nav { top: calc(86px + var(--announce-h)); }
@media (min-width: 760px) {
  .chrome-nav { top: 96px; }
  .app[data-announce="true"] .chrome-nav { top: calc(96px + var(--announce-h)); }
}
.chrome-nav-track {
  display: flex; gap: 6px; align-items: center;
  max-width: 100%;
  overflow-x: auto;
  padding: 2px 16px;
  pointer-events: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.chrome-nav-track::-webkit-scrollbar { display: none; }
.navpill {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 500;
  padding: 7px 13px; border-radius: 12px;
  /* Minimal "muted pill" (flexnative custom-trigger style): inactive tabs are
     borderless text; only the active — or hovered — tab gets a soft translucent
     ink wash. color-mix keeps the wash readable on either light or noir palette. */
  border: none;
  background: transparent;
  box-shadow: none;
  color: var(--ink); opacity: 0.55;
  cursor: pointer; white-space: nowrap;
  transition: opacity 0.25s ease, background 0.25s ease, color 0.25s ease;
  -webkit-tap-highlight-color: transparent;
}
.navpill:hover {
  opacity: 0.85;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
}
.navpill.active {
  opacity: 1;
  background: color-mix(in srgb, var(--ink) 12%, transparent);
  color: var(--ink);
}
/* Narrow screens: shrink pills so all services fit without clipping/scroll */
@media (max-width: 430px) {
  .chrome-nav-track { gap: 5px; padding: 2px 10px; }
  .navpill { font-size: 10px; padding: 6px 9px; letter-spacing: 0.04em; }
}
/* The nav used to be hidden by JS state once you left the hero
   (.app:not([data-vidx="0"])). It now simply scrolls away with the hero, so
   there is no state to track and no rule needed. */

/* ── Panels ──────────────────────────────────────────────────
   Stacked sections in normal flow. Formerly a .strip translated by transform.
   svh, not dvh: dvh is the *dynamic* viewport, which grows the moment iOS
   collapses its toolbar (measured 796 -> 836 on an iPhone 17 Pro Max), so a
   dvh-sized hero visibly lurches mid-scroll. svh is the small viewport and
   stays put. min-height, not height, so a panel whose content outgrows the
   screen simply gets taller instead of overflowing — this is what removes the
   whole class of "content creeps up into the nav" bugs. */
.panel {
  position: relative;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
}

/* Hero panel.
   min-height rather than height: the hero is bottom-anchored, so when content
   grew taller than the screen it used to push upward into the nav pills (the
   eyebrow/nav collision). Now the hero just gets taller and the page scrolls.
   padding-top reserves the chrome band so content cannot start underneath it;
   --chrome-clear is measured from .chrome-nav's top plus the pill height. It is
   !important because .hero carries an inline `padding` shorthand from the
   design tool, which would otherwise reset padding-top to 0. */
:root { --chrome-clear: 131px; --hero-pad-bottom: 110px; --hero-bleed: 0px; }
@media (min-width: 760px) { :root { --chrome-clear: 146px; } }
.hero {
  position: relative; width: 100%;
  min-height: 100vh;
  /* --hero-bleed (set in app.jsx) extends the hero past the layout viewport so
     its artwork reaches the bottom of the physical screen; without it the next
     section shows as a band under the hero at rest. The same value is added to
     padding-bottom, so the bottom-anchored content lands in exactly the same
     place as before — only the background grows. */
  min-height: calc(100svh + var(--hero-bleed));
  display: flex; flex-direction: column;
  justify-content: flex-end;
  padding: 0 24px 96px;
  padding-top: calc(var(--chrome-clear) + var(--announce-h)) !important;
  padding-bottom: calc(var(--hero-pad-bottom) + var(--hero-bleed)) !important;
}
/* Mobile: sit the (bottom-anchored) hero content lower by trimming the bottom
   padding (110px → 50px, ~60px lower) and nudge it 5px left (80px → 75px).
   Overrides the inline padding on .hero. */
@media (max-width: 759px) {
  :root { --hero-pad-bottom: 50px; }
  .hero {
    padding-left: 75px !important;
  }
  /* Centre the full-width pills on screen despite the asymmetric hero padding
     (left 75 / right 56): pull their left edge in to match the 56px right inset,
     leaving the left-aligned text where it is. */
  .hero .book,
  .hero .next-avail {
    margin-left: -19px !important;
    margin-right: 0 !important;
  }
}
.hero .number {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 10px;
}
.hero[data-service="home"] .number {
  text-shadow: 0 0 4px var(--bg), 0 0 16px var(--bg), 0 0 40px var(--bg), 0 0 80px var(--bg), 0 0 140px var(--bg), 0 0 200px var(--bg), 0 0 260px var(--bg), 0 0 320px var(--bg);
}
.hero h1 {
  font-family: var(--display);
  font-weight: 300;
  /* Width-scaled, but also bounded by viewport HEIGHT so short/wide
     laptop screens don't push the (bottom-anchored) headline up under
     the nav pills. The vh term approximates the space left after the
     nav and the sub/CTA block below the headline. */
  font-size: clamp(54px, min(14vw, 55vh - 265px), 168px);
  line-height: 0.88;
  letter-spacing: -0.035em;
  margin: 0;
  text-wrap: balance;
}
/* Barber stacks THREE lines — needs a much stricter height bound. */
.hero[data-service="barber"] h1 {
  font-size: clamp(44px, min(14vw, 37vh - 200px), 168px);
}
.hero h1 .it { font-style: italic; font-weight: 300; }
.hero .sub {
  margin-top: 22px;
  max-width: 32ch;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-soft);
}
.hero .swipe-hint {
  margin-top: 28px;
  display: flex; gap: 18px; align-items: center;
  font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-soft);
}
.hero .swipe-hint .glyph {
  display: inline-block; width: 18px; height: 1px; background: currentColor; opacity: 0.5;
}
/* Barber hero runs headline-free, so its sub is the top of the bottom-anchored
   cluster and sits right under the animation's neck. Trim the swipe-hint's top
   margin (overrides the inline 28px) so the sub slides down ~a line and clears
   the photo. Scoped to barber; other heroes keep their spacing. */
.hero[data-service="barber"] .swipe-hint { margin-top: 6px !important; }
.hero .hero-book-link {
  margin-left: auto;
  color: var(--ink);
  text-decoration: none;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 30%, transparent);
  padding-bottom: 3px;
  transition: border-color 0.25s ease, gap 0.25s ease;
}
.hero .hero-book-link:hover { border-bottom-color: var(--ink); }

/* Hero contact (home only) */
.hero-contact {
  margin: 22px 0 0 10px;
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 12px 14px;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-soft);
}
.hero-contact-label {
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--ink-faint);
}
.hero-contact-link {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 30%, transparent);
  padding-bottom: 3px;
  font-feature-settings: "tnum" 1;
  transition: border-color 0.25s ease, gap 0.25s ease;
}
.hero-contact-link:hover { border-bottom-color: var(--ink); }
.hero-contact-link.sms { letter-spacing: 0.16em; }
.hero-contact-sep {
  color: var(--ink-faint); opacity: 0.6;
}

/* Live "open now" status — sits above phone/text links on the home hero. */
.open-status {
  flex-basis: 100%;
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 4px;
}
.open-status .open-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.open-status.open {
  color: oklch(0.58 0.13 150); /* muted editorial green */
}
.open-status.open .open-dot {
  position: relative;
  animation: openPulse 2.4s ease-in-out infinite;
}
.open-status.open .open-dot::after {
  content: '';
  position: absolute; inset: -4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.25;
  animation: openHalo 2.4s ease-out infinite;
}
.open-status.closed {
  color: var(--ink-faint);
}
.open-status.closed .open-dot {
  background: transparent;
  border: 1px solid currentColor;
}
.open-status .open-label { letter-spacing: 0.2em; }
.open-status .open-sep { opacity: 0.5; }
.open-status .open-meta { color: var(--ink-soft); letter-spacing: 0.12em; }
.open-status.closed .open-meta { color: var(--ink-faint); }

@keyframes openPulse {
  0%, 100% { opacity: 0.85; }
  50% { opacity: 1; }
}
@keyframes openHalo {
  0% { transform: scale(0.6); opacity: 0.35; }
  100% { transform: scale(1.6); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .open-status.open .open-dot,
  .open-status.open .open-dot::after {
    animation: none;
  }
}
@media (max-width: 540px) {
  .hero-contact { gap: 6px 12px; font-size: 10px; }
  .hero-contact-sep { display: none; }
}

/* ── Next available barber CTA ───────────────────────────────────── */
.next-avail {
  display: inline-flex; align-items: center; gap: 10px;
  background: transparent;
  border: 1px solid color-mix(in oklch, var(--ink) 20%, transparent);
  border-radius: 999px;
  padding: 9px 18px 9px 12px;
  cursor: pointer;
  margin-top: 12px; margin-left: 10px;
  transition: border-color 0.2s ease, background 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
.next-avail:hover {
  border-color: color-mix(in oklch, var(--ink) 38%, transparent);
  background: color-mix(in oklch, var(--ink) 5%, transparent);
}
.avail-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: oklch(0.58 0.13 150);
  flex-shrink: 0; position: relative;
  animation: openPulse 2.4s ease-in-out infinite;
}
.avail-dot::after {
  content: ''; position: absolute; inset: -4px;
  border-radius: 50%;
  background: oklch(0.58 0.13 150);
  opacity: 0.25;
  animation: openHalo 2.4s ease-out infinite;
}
.next-avail-eyebrow {
  font-family: var(--mono); font-size: 9px;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-soft);
}
.next-avail-time {
  font-family: var(--mono);
  font-size: 12px; letter-spacing: 0.06em; line-height: 1;
  color: var(--ink);
}
.next-avail-arr {
  font-family: var(--display); font-style: italic;
  font-size: 16px; color: var(--ink-soft);
}
@media (prefers-reduced-motion: reduce) {
  .avail-dot, .avail-dot::after { animation: none; }
}

/* Animation canvas (full bleed under hero text) */
.anim-canvas {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 0;
}
/* Fade the very top of the artwork into the flat colour iOS Safari paints in
   its status strip, so the two meet without a seam.
   Only the canvas background can reach that strip — no element can, verified:
   at scroll 0 a `position: fixed; top: 0` probe landed at 61pt, and an html
   background of #00ff00 rendered the strip as pure lime with no content in it.
   So the strip is necessarily one flat colour, and the mismatch shows wherever
   the artwork varies across its top edge (home's drifting aura, sunless's
   radial). Fading the top ~150px to that same colour hides the join.
   Sits above the SVG but below the hero text, which is z-index 1. */
.anim-canvas::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: var(--hero-fade, 150px);
  background: linear-gradient(180deg,
    var(--hero-tint, var(--bg)) 0%,
    color-mix(in srgb, var(--hero-tint, var(--bg)) 55%, transparent) 45%,
    color-mix(in srgb, var(--hero-tint, var(--bg)) 0%, transparent) 100%);
  pointer-events: none;
}
/* The SVG fills the whole canvas, bleed included — several animations paint
   their own background into it (WaxAnim's "deep wash bottom" rect, for one), so
   an SVG that stopped at 100svh left a hard seam where its painting ended. The
   artwork is kept on screen by the HV/placeH split in animations.jsx, not by
   shrinking the viewport. */
.hero > * { position: relative; z-index: 1; }

/* ── Content panels (swipe down) ────────────────────────── */
/* Content section. No longer its own scroll container — it flows in the
   document, which is what lets one continuous scroll carry you from the hero
   through the menu and into booking. The old overflow-y/overscroll/height:100%
   made this a nested scroller that swallowed the page scroll. */
.cpanel {
  width: 100%;
  padding: 56px 24px 96px;
  /* Clear the home indicator / collapsed toolbar at the very bottom of the
     document (0px in Safari, non-zero standalone). */
  padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
  background: var(--bg);
}
.cpanel::-webkit-scrollbar { display: none; }
.cpanel .eyebrow {
  font-family: var(--mono);
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 18px;
  display: flex; justify-content: space-between;
  /* Two long labels used to meet in the middle at 375px and read as one word
     — "PREP + AFTERCAREREAD BEFORE YOUR APPOINTMENT". The gap makes that
     impossible, and the right label wraps rather than pushing into the left. */
  gap: 16px;
  line-height: 1.5;
}
/* The section name never breaks; the descriptor gives way and wraps. */
.cpanel .eyebrow > span:first-child { flex-shrink: 0; }
.cpanel .eyebrow > span:last-child  { text-align: right; }
.cpanel h2 {
  font-family: var(--display); font-weight: 300; font-style: italic;
  font-size: clamp(36px, 8vw, 80px);
  line-height: 0.92; letter-spacing: -0.02em;
  margin: 0 0 28px;
}
.cpanel .body { font-size: 15px; line-height: 1.55; color: var(--ink-soft); max-width: 56ch; }
.cpanel .rule { height: 1px; background: var(--rule); margin: 32px 0; }

/* Limited-time bundles.
   Sits above the booking embed on every panel the bundle touches. Deliberately
   quieter than the service menu below it — it is an offer, not the main event,
   and the ordered steps are the part that has to be legible. */
.bundle { margin: 4px 0 8px; }
.bundle-name {
  font-family: var(--display); font-size: 26px; font-weight: 400;
  letter-spacing: -0.01em; margin: 2px 0 0;
}
.bundle-blurb {
  font-size: 14px; line-height: 1.55; color: var(--ink-soft);
  max-width: 56ch; margin: 10px 0 0; white-space: pre-line;
}
/* Collapsed step list. Borrows the FAQ accordion's summary behaviour — the
   rotating plus, the hidden native marker — so it reads as the same control
   the client meets twice more further down the page. */
.bundle-more { margin-top: 18px; }
.bundle-more > summary {
  list-style: none;
  display: flex; align-items: baseline; gap: 10px;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  padding: 12px 0;
  /* Top border only. A bottom border left a bare 32px band between it and the
     section rule that follows, which read as an empty row rather than a
     closed accordion. When open, the step list's own borders close it. */
  border-top: 1px solid var(--rule);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink);
}
.bundle-more > summary::-webkit-details-marker { display: none; }
.bundle-more > summary .plus {
  font-family: var(--mono); font-size: 14px; opacity: 0.5;
  display: inline-block; transition: transform 0.3s var(--easing-spring);
}
.bundle-more[open] > summary .plus { transform: rotate(45deg); }

.bundle-steps { list-style: none; margin: 4px 0 0; padding: 0; }
.bundle-step {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 16px 0; border-top: 1px solid var(--rule);
}
.bundle-spacing { margin-top: 14px; }
.bundle-step:last-child { border-bottom: 1px solid var(--rule); }
.bundle-more .bundle-step:first-child { border-top: none; }
.bundle-num {
  flex-shrink: 0; width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--rule);
  font-family: var(--mono); font-size: 11px;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-faint); margin-top: 2px;
}
.bundle-step-body { flex: 1; min-width: 0; }
.bundle-step-head {
  display: flex; gap: 16px; align-items: baseline; justify-content: space-between;
}
.bundle-step-name {
  font-family: var(--display); font-size: 19px; letter-spacing: -0.01em;
}
.bundle-step-price {
  font-family: var(--mono); font-size: 13px; letter-spacing: 0.04em;
  flex-shrink: 0; white-space: nowrap;
}
.bundle-was { color: var(--ink-faint); margin-left: 8px; opacity: 0.7; }
.bundle-addons {
  list-style: none; margin: 6px 0 0; padding: 0;
  font-size: 13px; color: var(--ink-soft); line-height: 1.5;
}
.bundle-step-note {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-faint); margin-top: 6px;
}
.bundle-book {
  appearance: none; background: none; border: 1px solid var(--rule);
  border-radius: 999px; padding: 8px 16px; margin-top: 12px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* 44pt minimum — these sit close together on a phone. */
  min-height: 44px;
}
.bundle-book:hover { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.bundle-total {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; margin-top: 14px; color: var(--ink);
}

/* Bundle pricing chip inside the booking embed */
.bk-bundle-chip {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 14px; margin: 0 0 18px;
  border: 1px solid var(--rule); border-radius: 10px;
}
.bk-bundle-dot {
  width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
  background: var(--ink);
}
.bk-bundle-label {
  flex: 1; min-width: 0;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink);
}
.bk-bundle-clear {
  appearance: none; background: none; border: none; padding: 4px 0;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-faint);
  text-decoration: underline; text-underline-offset: 3px;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}

/* Pricing list */
.menu { display: flex; flex-direction: column; gap: 1px; background: var(--rule); margin: 8px 0; }
.menu-row {
  display: grid; grid-template-columns: 1fr auto;
  gap: 16px; padding: 18px 0;
  background: var(--bg);
  align-items: baseline;
}
.menu-row .name { font-family: var(--display); font-size: 22px; font-weight: 400; letter-spacing: -0.01em; }
.menu-row .name em { font-style: italic; }
.menu-row .desc { font-size: 12px; color: var(--ink-faint); margin-top: 4px; max-width: 36ch; line-height: 1.45; }
.menu-row .price { font-family: var(--mono); font-size: 13px; letter-spacing: 0.04em; }

/* Menu subsection label (used inside Waxing) */
.menu-group {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 22px 0 4px;
  padding-top: 12px;
  border-top: 1px solid var(--rule);
}
.menu-group:first-of-type { border-top: 0; padding-top: 0; margin-top: 8px; }
.menu-group-note {
  font-size: 9.5px;
  letter-spacing: 0.1em;
  opacity: 0.6;
  text-transform: none;
  font-style: italic;
}

/* Gallery */
.gallery {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.tile {
  aspect-ratio: 3/4;
  border-radius: 2px;
  overflow: hidden;
  position: relative;
  background: var(--paper);
}
.tile.tall { grid-row: span 2; aspect-ratio: 3/5; }
.tile.wide { grid-column: span 2; aspect-ratio: 16/10; }
.tile.square { aspect-ratio: 1 / 1; }
.tile .ph {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(
    135deg,
    rgba(20,18,16,0.045) 0 8px,
    rgba(20,18,16,0.085) 8px 16px
  );
  display: flex; align-items: flex-end; justify-content: flex-start;
  padding: 10px;
  color: var(--ink-faint);
  font-family: var(--mono); font-size: 9px;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.tile img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.8s var(--easing-spring, ease);
}
.tile:hover img { transform: scale(1.03); }

/* Stylist cards */
.stylists { display: flex; flex-direction: column; gap: 24px; }
.stylist {
  display: grid; grid-template-columns: 92px 1fr; gap: 18px;
  align-items: start;
}
.stylist .avatar {
  width: 92px; height: 116px; border-radius: 2px;
  background: repeating-linear-gradient(
    135deg, rgba(20,18,16,0.05) 0 6px, rgba(20,18,16,0.09) 6px 12px
  );
  background-size: cover;
  background-position: center;
  position: relative;
  overflow: hidden;
}
/* Hide the "LF" initials overlay once a real photo is set inline */
.stylist .avatar[style*="background-image"]::after { display: none; }
.stylist .avatar::after {
  content: attr(data-initials);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--display); font-style: italic; font-size: 28px;
  color: var(--ink-faint);
}
.stylist h3 { font-family: var(--display); font-weight: 400; font-size: 24px; margin: 0 0 4px; letter-spacing: -0.01em; }
.stylist h3 em { font-style: italic; }
.stylist h3 .ig {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 25%, transparent);
  padding-bottom: 1px;
  transition: border-color 0.25s ease, color 0.25s ease;
}
.stylist h3 .ig:hover { border-bottom-color: var(--ink); }
.stylist h3 .ig:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 2px;
}
.stylist .role { font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 8px; }
.stylist p { font-size: 13px; line-height: 1.5; color: var(--ink-soft); margin: 0; }

/* CTA / book */
.book {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 18px 22px;
  background: var(--ink); color: var(--bg);
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.14em; text-transform: uppercase;
  border: none; cursor: default;
  border-radius: 1px;
  position: relative; isolation: isolate;
  /* the "lit" full metallic ring, reused by hover (desktop) and :active (tap) */
  --hbg-lit: conic-gradient(from 0deg,
    #e6e6e6, #ffffff, #d6d6d6, #ffffff, #e6e6e6, #ffffff, #d6d6d6, #ffffff, #e6e6e6);
  transition: gap 0.4s var(--easing-spring), background 0.3s ease, box-shadow 0.35s ease;
}
.book:hover { gap: 18px; background: var(--accent, var(--ink)); }
.book .arr { font-family: var(--display); font-style: italic; font-size: 16px; }

/* Hover-border-gradient (21st.dev, adapted to pure CSS) — a warm light sweeps
   around the pill's edge. A conic gradient rotated via @property --hbg-angle,
   masked to a 1.5px ring. Animation is gated to hover-capable pointers so
   touch devices get a clean static pill with no continuous repaint. */
@property --hbg-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}
.book::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 2px;
  background: conic-gradient(from var(--hbg-angle),
    transparent 0turn,
    transparent 0.58turn,
    rgba(255, 255, 255, 0.45) 0.7turn,
    #ffffff 0.8turn,
    rgba(255, 255, 255, 0.45) 0.9turn,
    transparent 0.99turn);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  opacity: 0.8;
  animation: hbg-rotate 5s linear infinite;
  transition: opacity 0.35s ease, background 0.3s ease;
  pointer-events: none;
}
/* Engaged state — the whole edge lights up into a bright metallic ring
   (static, ignores --hbg-angle so it holds still). :active covers touch taps
   and clears on release, so it can't stick the way :hover would on touch. */
.book:active::before { opacity: 1; background: var(--hbg-lit); }
@media (hover: hover) and (pointer: fine) {
  .book:hover::before { opacity: 1; background: var(--hbg-lit); }
  .book:hover { box-shadow: 0 0 26px -8px rgba(255, 255, 255, 0.4); }
}
@keyframes hbg-rotate { to { --hbg-angle: 1turn; } }
/* Reduced motion: no rotation — show a still, symmetric metallic edge. */
@media (prefers-reduced-motion: reduce) {
  .book::before { animation: none; background: var(--hbg-lit); opacity: 0.6; }
}

/* ── Custom booking embed ────────────────────────────────── */

/* Native Apple Pay button — Safari draws Apple's official branded button
   (logo included). The element must be empty; the UA renders the content.
   Only ever shown in Safari (the SDK gates it), so no fallback needed. */
.bk-apple-pay-btn {
  display: block;
  width: 100%;
  height: 50px;
  margin-top: 10px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  -webkit-appearance: -apple-pay-button;
  -apple-pay-button-type: book;
  -apple-pay-button-style: black;
}
.bk-apple-pay-btn:disabled { opacity: 0.5; cursor: default; }

.booking-embed {
  margin: 8px 0 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.booking-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}
.booking-eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
}
.booking-progress {
  flex: 1;
  max-width: 160px;
  height: 2px;
  background: var(--rule);
  border-radius: 2px;
  overflow: hidden;
}
.booking-progress-fill {
  height: 100%;
  background: var(--ink);
  border-radius: 2px;
  transition: width 0.45s cubic-bezier(0.65, 0, 0.35, 1);
}
.booking-body {
  /* Inputs inside the booking flow */
}
.bk-input::placeholder {
  color: var(--ink-faint);
}
.bk-input:focus {
  outline: none;
  border-bottom-color: var(--ink) !important;
}


/* FAQ */
.faq { display: flex; flex-direction: column; gap: 0; }
.faq details {
  border-top: 1px solid var(--rule);
  padding: 18px 0;
}
.faq details:last-child { border-bottom: 1px solid var(--rule); }
.faq summary {
  list-style: none;
  display: flex; justify-content: space-between; align-items: baseline;
  cursor: default;
  font-family: var(--display); font-size: 20px; font-weight: 400; letter-spacing: -0.005em;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary .plus { font-family: var(--mono); font-size: 14px; opacity: 0.5; }
.faq details[open] summary .plus { transform: rotate(45deg); }
.faq summary .plus { transition: transform 0.3s var(--easing-spring); display: inline-block; }
.faq .answer { padding-top: 12px; font-size: 14px; line-height: 1.55; color: var(--ink-soft); max-width: 56ch; }
/* Most answers are a bare string; the cancellation policy needs paragraphs
   around its list, so give them spacing without a stray trailing margin. */
.faq .answer p { margin: 0 0 12px; }
.faq .answer p:last-child { margin-bottom: 0; }
.faq .answer .prep-list + p { margin-top: 12px; }
.faq .answer .prep-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex; flex-direction: column;
  gap: 10px;
}
.faq .answer .prep-list li {
  position: relative;
  padding-left: 22px;
  font-size: 13.5px;
  line-height: 1.55;
}
.faq .answer .prep-list li::before {
  content: '';
  position: absolute;
  left: 0; top: 0.7em;
  width: 12px; height: 1px;
  background: currentColor;
  opacity: 0.45;
}

/* Before/After subheads inside one answer — used where a single service has
   both, so the accordion can be titled by service ("Lash Extensions") rather
   than by phase. Borrows the .eyebrow treatment so it reads as a label and
   can't be mistaken for a list item. First one loses its top margin; the
   padding on .answer already provides that space. */
.faq .answer .prep-head {
  font-family: var(--mono);
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint);
  margin: 20px 0 10px;
}
.faq .answer .prep-head:first-child { margin-top: 0; }

/* Hours */
.hours {
  display: grid; grid-template-columns: 1fr auto;
  font-family: var(--mono); font-size: 12px;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.hours .row { display: contents; }
.hours .row > * { padding: 12px 0; border-top: 1px solid var(--rule); }
.hours .row:last-child > * { border-bottom: 1px solid var(--rule); }
.address {
  margin-top: 28px;
  font-family: var(--display); font-style: italic; font-size: 22px; line-height: 1.3;
  display: flex; flex-direction: column;
  gap: 6px;
}
.address-street { color: var(--ink); }
.address-city {
  font-family: var(--mono);
  font-style: normal;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 4px;
}
.address-links {
  display: flex; flex-wrap: wrap;
  gap: 12px 22px;
  margin-top: 14px;
  font-family: var(--mono);
  font-style: normal;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.address-link {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 30%, transparent);
  padding-bottom: 3px;
  transition: border-color 0.25s ease;
}
.address-link:hover { border-bottom-color: var(--ink); }
.address-link span { display: inline-block; transition: transform 0.3s var(--easing-spring); }
.address-link:hover span { transform: translateX(4px); }

/* Map */
.map {
  margin-top: 28px;
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 11;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 2px;
  overflow: hidden;
}
.map iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
  /* Desaturate so the Google chrome doesn't fight the editorial palette */
  filter: grayscale(0.85) contrast(0.92) brightness(1.02);
  transition: filter 0.4s ease;
}
.map:hover iframe { filter: grayscale(0) contrast(1) brightness(1); }
@media (min-width: 760px) {
  .map { aspect-ratio: 16 / 9; }
}

/* Goods (end-of-vertical card) */
.goods-card {
  margin-top: 8px;
  border: 1px solid var(--rule);
  padding: 24px;
  display: flex; flex-direction: column; gap: 14px;
}
.goods-card h4 { font-family: var(--display); font-style: italic; font-weight: 400; font-size: 26px; margin: 0; }
.goods-card .row { display: flex; justify-content: space-between; font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-soft); }

/* Edge service indicators (peek of next service color) */
.edge {
  position: absolute; top: 0; bottom: 0; width: 4px;
  pointer-events: none; z-index: 5;
  opacity: 0; transition: opacity 0.4s ease;
}
.edge.left { left: 0; }
.edge.right { right: 0; }
.dragging-h .edge { opacity: 0.85; }


@media (min-width: 760px) {
  .hero { padding: 0 56px 110px; }
  .cpanel { padding: calc(120px + var(--announce-h)) 56px 110px; max-width: 880px; margin: 0 auto; }
  .gallery { grid-template-columns: repeat(3, 1fr); }
  .stylist { grid-template-columns: 140px 1fr; }
  .stylist .avatar { width: 140px; height: 176px; }
}

/* ── Home hero — “The Aura Edit” ─────────────────────────────
   Milky drifting colour fields + a fanned stack of service photo
   cards. Motion is transform-only (GPU-cheap) and disabled under
   prefers-reduced-motion. */
.home-aura { overflow: hidden; background: var(--paper); }
.aura-blob {
  position: absolute; border-radius: 50%;
  will-change: transform;
}
/* Four pigments — pink, golden, purple, green — saturated enough to
   actually read against the paper, soft-edged so they stay dreamy. */
.aura-a {
  width: 95vmax; height: 95vmax; left: -30vmax; top: -35vmax;
  background: radial-gradient(circle at 50% 50%, rgba(243,158,182,0.75) 0%, rgba(243,158,182,0) 62%);
  animation: aura-drift-a 30s ease-in-out infinite alternate;
}
.aura-b {
  width: 85vmax; height: 85vmax; right: -32vmax; top: -12vmax;
  background: radial-gradient(circle at 50% 50%, rgba(235,182,96,0.7) 0%, rgba(235,182,96,0) 60%);
  animation: aura-drift-b 38s ease-in-out infinite alternate;
}
.aura-c {
  width: 75vmax; height: 75vmax; left: 4vmax; bottom: -34vmax;
  background: radial-gradient(circle at 50% 50%, rgba(187,155,222,0.7) 0%, rgba(187,155,222,0) 60%);
  animation: aura-drift-c 34s ease-in-out infinite alternate;
}
.aura-d {
  width: 70vmax; height: 70vmax; right: -18vmax; bottom: -30vmax;
  background: radial-gradient(circle at 50% 50%, rgba(157,201,160,0.65) 0%, rgba(157,201,160,0) 60%);
  animation: aura-drift-d 42s ease-in-out infinite alternate;
}
@keyframes aura-drift-a { from { transform: translate(0,0) scale(1); }    to { transform: translate(18vmax,12vmax) scale(1.18); } }
@keyframes aura-drift-b { from { transform: translate(0,0) scale(1.08); } to { transform: translate(-16vmax,16vmax) scale(0.9); } }
@keyframes aura-drift-c { from { transform: translate(0,0) scale(0.95); } to { transform: translate(14vmax,-14vmax) scale(1.15); } }
@keyframes aura-drift-d { from { transform: translate(0,0) scale(1.05); } to { transform: translate(-14vmax,-16vmax) scale(1.2); } }
@media (prefers-reduced-motion: reduce) { .aura-blob { animation: none; } }

/* Home headline shares the stage with the imagery */
.hero[data-service="home"] h1 {
  font-size: clamp(46px, min(9vw, 42vh - 220px), 128px);
}

/* Collage — staggered horizontal line, right side (desktop). A single row
   reads as a filmstrip across the empty right band and, being short, no
   longer drifts with viewport height the way the old tall 2×2 stack did. */
.aura-collage {
  position: absolute; right: 4vw; top: 44%;
  transform: translateY(-50%);
  display: flex; align-items: center;
  gap: clamp(12px, 1.3vw, 24px);
  width: auto; max-width: none; aspect-ratio: auto;
  z-index: 1;
}
.aura-card {
  position: relative; flex: 0 0 clamp(120px, 13vw, 200px);
  width: auto; aspect-ratio: 3 / 4;
  padding: 10px 10px 32px; overflow: hidden;
  /* Transparent fill + the sheen overlay reads as a frosted-glass frame
     (matches the mobile strip); a hint of paper keeps it consistent over
     the more varied desktop aura behind it. */
  background: rgba(255, 253, 248, 0.28);
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 16px;
  box-shadow: 0 24px 60px -18px rgba(20,18,16,0.32), 0 6px 18px rgba(20,18,16,0.1),
              inset 0 1px 0 rgba(255,255,255,0.5);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.45s cubic-bezier(0.22,1,0.36,1), box-shadow 0.45s ease,
              filter 0.4s ease, opacity 0.4s ease;
}
/* Glass sheen — a soft diagonal gloss across the tile, brightest at the
   top-left corner. Sits above the photo but below the label. */
.aura-card::after {
  content: ''; position: absolute; inset: 0; border-radius: 16px;
  pointer-events: none; z-index: 2;
  background: linear-gradient(135deg,
    rgba(255,255,255,0.4) 0%, rgba(255,255,255,0) 24%,
    rgba(255,255,255,0) 76%, rgba(255,255,255,0.1) 100%);
}
/* <picture> wraps the img for art-directed mobile crops. `display: contents`
   keeps it from creating a box, so the img's height:100% still resolves
   against the card rather than an auto-height inline wrapper. */
.aura-card picture { display: contents; }
.aura-card img {
  width: 100%; height: 100%; object-fit: cover;
  border-radius: 9px; display: block;
}
/* Liquid-glass label chip — floats over the photo so the backdrop blur
   has real content to frost. Smoked tint keeps light text legible over
   any image. */
.aura-card-label {
  position: absolute; left: 16px; bottom: 16px; z-index: 3;
  display: flex; gap: 7px; align-items: baseline;
  padding: 5px 11px; border-radius: 999px;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; color: rgba(255,255,255,0.96); white-space: nowrap;
  background: rgba(28,24,20,0.34);
  -webkit-backdrop-filter: blur(10px) saturate(1.5);
  backdrop-filter: blur(10px) saturate(1.5);
  border: 1px solid rgba(255,255,255,0.28);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 4px 14px rgba(20,18,16,0.22);
}
.aura-card-num { opacity: 0.7; }
.aura-card-arr { opacity: 0; width: 0; margin-left: -7px; transform: translateX(-4px); transition: opacity 0.3s, transform 0.3s, width 0.3s, margin 0.3s; }
.aura-card:hover .aura-card-arr { opacity: 1; width: auto; margin-left: 0; transform: none; }
/* Staggered zigzag: alternate cards ride high and low along the line, each
   tipped a few degrees for the hand-placed polaroid feel. */
.aura-card-barber { transform: translateY(24px)  rotate(-5deg);  z-index: 4; }
.aura-card-tan    { transform: translateY(-26px) rotate(3.5deg); z-index: 3; }
.aura-card-wax    { transform: translateY(20px)  rotate(4deg);   z-index: 2; }
.aura-card-lashes { transform: translateY(-22px) rotate(-3.5deg); z-index: 1; }
.aura-card:hover,
.aura-card:focus-visible {
  transform: translateY(-16px) rotate(0deg) scale(1.04);
  z-index: 9;
  box-shadow: 0 34px 80px -20px rgba(20,18,16,0.34), 0 10px 24px rgba(20,18,16,0.10);
}
/* Hover reveal — the pointed-at (or keyboard-focused) card stays crisp while
   the rest blur and fade back, pulling focus to the one in play. Gated to
   hover-capable pointers: on touch, a tap emulates :hover and focuses the
   card, and neither clears on swipe — which left the other cards stuck
   blurred. Coarse-pointer (touch) devices skip the effect entirely. */
@media (hover: hover) and (pointer: fine) {
  .aura-collage:hover .aura-card:not(:hover),
  .aura-collage:focus-within .aura-card:not(:focus-visible) {
    filter: blur(3px) saturate(0.9);
    opacity: 0.5;
  }
}

/* Mobile — full-bleed 2×2 grid between headline and CTA.
   Replaces the old horizontal snap strip, which had three problems: it ended
   56px short of the screen edge (hero's right padding) so the third card was
   guillotined by a hard vertical line; `overflow-x: auto` forces `overflow-y`
   to `auto` too, so the strip clipped its own children — shearing the card
   shadows flat and cutting the corners off the tilted cards; and its swipe
   competed with the panel swipe in the same band of screen. A grid shows all
   four services at once with no hidden gesture and nothing to clip. */
@media (max-width: 759px) {
  .aura-collage {
    position: static; transform: none;
    width: auto; max-width: none; aspect-ratio: auto;
    display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
    /* Row height is driven by viewport WIDTH (the tiles are 1fr of a full-bleed
       grid) but hard-capped. Uncapped, a 440pt phone produced 158px-tall tiles
       and a 329px grid, which pushed the bottom-anchored hero up until the
       eyebrow overlapped the nav pills by 15px. Sizing the row rather than
       putting max-height on the card keeps each tile filling its cell — a
       capped card would sit 180px wide in a 198px column with the slack all on
       one side. 34vw reproduces the previous height at 390pt exactly. */
    grid-auto-rows: min(34vw, 144px);
    overflow: visible;
    /* Cancel the hero's asymmetric indent (left 75 / right 56) so the grid
       runs edge to edge, then inset both sides evenly. The old strip only got
       294px of a 375px screen; this gets the full width. */
    margin: 22px -56px 0 -75px;
    padding: 0 16px;
  }
  .aura-card {
    /* Height comes from the row, width from the column — no aspect-ratio, so
       the tile always fills its cell whatever the cap does. */
    position: relative; flex: none; width: auto; height: 100%;
    aspect-ratio: auto;
    padding: 6px; border-radius: 14px;
    box-shadow: 0 14px 30px -12px rgba(20,18,16,0.24), 0 3px 10px rgba(20,18,16,0.07);
  }
  /* No tilt in a grid — the stagger is a desktop-only conceit, and rotation
     against a hard column edge just reads as misalignment. */
  .aura-card-barber, .aura-card-tan, .aura-card-wax, .aura-card-lashes { transform: none; }
  .aura-card img { border-radius: 10px; }
  /* Per-photo crop anchors. These are tall portraits squeezed into a landscape
     tile, so `cover` keeps only a narrow horizontal band and the default 50%
     rarely lands on the subject: the sunless shot showed a bare midriff and
     the lash shot favoured the lips over the lashes, so both pull upward.
     Waxing goes the other way — its top third is empty wall, so raising the
     band added dead space and pushed the face down behind the label; dropping
     it instead fills the tile with the brow being worked on. */
  /* Barber uses its own pre-cropped file (see imgMobile in app.jsx) which is
     already exactly 5:4, so this anchor is inert at normal tile size and only
     applies on the short-phone 2:1 tiles below — where centring would clip the
     crown off the top of the head. */
  .aura-card-barber img { object-position: 50% 28%; }
  .aura-card-tan img    { object-position: 50% 10%; }
  .aura-card-wax img    { object-position: 50% 68%; }
  .aura-card-lashes img { object-position: 50% 12%; }
  /* Bigger than the old 8px: these tiles are the primary service nav. */
  .aura-card-label { left: 10px; bottom: 10px; padding: 4px 10px; font-size: 10px; letter-spacing: 0.12em; }
  .aura-card-arr { display: none; }
  /* Touch feedback, since there's no hover to lean on. */
  .aura-card:active { transform: scale(0.97); }
}
/* Short phones: flatten the tiles rather than dropping the grid entirely, so
   the home page keeps its imagery instead of going bare. The hero is
   bottom-anchored, so anything the grid takes pushes the eyebrow up into the
   nav — measured at 375×667 there is ~187px of room, which two 2:1 rows plus
   the gap and top margin just fit. (The old strip was 213px here and already
   collided with the nav by ~16px.) */
@media (max-width: 759px) and (max-height: 700px) {
  .aura-collage { gap: 8px; margin-top: 10px; grid-auto-rows: min(21vw, 88px); }
  .aura-card-label { left: 8px; bottom: 8px; padding: 3px 8px; font-size: 9px; }
}
