/* ════════════════════════════════════════════════════════════════════
   PRIMITIVES — copied verbatim into every build.
   Layout-agnostic mechanics + motion + a11y + bug-fixes.
   Bespoke component CSS + the per-business :root token block layer
   ON TOP of this. Brand colours / fonts / components are NOT here.
   ═══════════════════════════════════════════════════════════════════ */

/* ──────────────────────────────────────────────────────────────────
   EASING — override in :root with your build's preferred curve
   ────────────────────────────────────────────────────────────────── */
:root {
  --ease: cubic-bezier(.22,1,.36,1);
  /* Form / button hook vars — bespoke :root overrides these */
  --focus-ring: rgba(0,0,0,.25);
  --input-border: #ccc;
  --input-border-focus: #666;
  --input-bg: #fff;
  --input-color: #111;
  --input-radius: 3px;
  --error-color: #c0392b;
  --error-bg: #fdf6f3;
  --btn-bg: #111;
  --btn-color: #fff;
  --btn-radius: 3px;
  --btn-border: #111;
}

/* ── Reset / base ──────────────────────────────────────────────────── */
*,*::before,*::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  overflow-x: hidden;
  scroll-padding-top: 80px; /* override per build if nav height differs */
}
html, body { overflow-x: hidden; } /* belt-and-suspenders — no horizontal scroll ever */
body {
  margin: 0;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
ul { margin: 0; padding: 0; list-style: none; }
h1,h2,h3,h4 { margin: 0; line-height: 1.05; }
button { font-family: inherit; cursor: pointer; }

/* ── Accessibility ─────────────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--focus-ring, rgba(0,0,0,.4));
  outline-offset: 3px;
}

/* Skip-link — rename selector to .u-skip in new builds */
.u-skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--btn-bg, #111); color: var(--btn-color, #fff);
  padding: 12px 18px; text-decoration: none; font-size: .85rem;
  letter-spacing: .06em;
}
.u-skip:focus { left: 12px; top: 12px; }

/* ── Reveal / scroll-motion primitives ────────────────────────────── */
/* Add data-reveal to any element you want to fade-up on scroll.
   JS adds .is-revealed via IntersectionObserver. */
[data-reveal] {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
  will-change: opacity, transform;
}
[data-reveal].is-revealed { opacity: 1; transform: translateY(0); }

/* Add data-reveal-stagger to a PARENT to stagger its direct children. */
[data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .9s var(--ease), transform .9s var(--ease);
}
[data-reveal-stagger].is-revealed > * { opacity: 1; transform: translateY(0); }
[data-reveal-stagger].is-revealed > *:nth-child(1) { transition-delay: .05s; }
[data-reveal-stagger].is-revealed > *:nth-child(2) { transition-delay: .12s; }
[data-reveal-stagger].is-revealed > *:nth-child(3) { transition-delay: .19s; }
[data-reveal-stagger].is-revealed > *:nth-child(4) { transition-delay: .26s; }
[data-reveal-stagger].is-revealed > *:nth-child(5) { transition-delay: .33s; }
[data-reveal-stagger].is-revealed > *:nth-child(6) { transition-delay: .40s; }
[data-reveal-stagger].is-revealed > *:nth-child(7) { transition-delay: .47s; }
[data-reveal-stagger].is-revealed > *:nth-child(n+8) { transition-delay: .54s; }

/* ── Form mechanics (brand-colour-free) ────────────────────────────── */
/* Wrap each field in a container with class="u-field" */
.u-field { margin-bottom: 1.1rem; }
.u-field label {
  display: block;
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  margin-bottom: .45rem;
}
.u-field input,
.u-field select,
.u-field textarea {
  width: 100%;
  font-family: inherit;
  font-size: 16px; /* 16px prevents iOS zoom */
  color: var(--input-color, #111);
  background: var(--input-bg, #fff);
  border: 1px solid var(--input-border, #ccc);
  border-radius: var(--input-radius, 3px);
  padding: 13px 15px;
  min-height: 48px; /* tap target */
  transition: border-color .2s ease, box-shadow .2s ease;
}
.u-field textarea { min-height: 110px; resize: vertical; line-height: 1.5; }
.u-field select {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  padding-right: 38px;
}
.u-field input:focus,
.u-field select:focus,
.u-field textarea:focus {
  outline: none;
  border-color: var(--input-border-focus, #666);
  box-shadow: 0 0 0 3px var(--focus-ring, rgba(0,0,0,.12));
}

/* Validation */
.u-field.is-invalid input,
.u-field.is-invalid textarea,
.u-field.is-invalid select {
  border-color: var(--error-color, #c0392b);
  background: var(--error-bg, #fdf6f3);
}
.u-field__err {
  display: none;
  margin-top: .4rem;
  font-size: .86rem;
  color: var(--error-color, #c0392b);
}
.u-field.is-invalid .u-field__err { display: block; }

/* ── Button mechanics (NO brand colours) ──────────────────────────── */
/* Build's :root sets --btn-bg / --btn-color / --btn-border / --btn-radius.
   Variant classes (.btn--outline, .btn--ghost etc.) live in bespoke CSS. */
.u-btn {
  position: relative; overflow: hidden; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  background: var(--btn-bg, #111);
  color: var(--btn-color, #fff);
  text-decoration: none;
  font-family: inherit; font-size: .85rem;
  letter-spacing: .14em; text-transform: uppercase;
  padding: 15px 30px;
  border: 1px solid var(--btn-border, #111);
  border-radius: var(--btn-radius, 3px);
  cursor: pointer; line-height: 1; min-height: 48px;
  transition:
    transform .35s var(--ease),
    background .35s var(--ease),
    border-color .35s var(--ease),
    box-shadow .35s var(--ease),
    color .35s var(--ease);
}
.u-btn > * { position: relative; z-index: 1; }

/* Shimmer sweep on hover — cosmetic hook, no colours */
.u-btn::before {
  content: ''; position: absolute; top: 0; left: -130%; width: 60%; height: 100%; z-index: 0;
  background: linear-gradient(
    115deg,
    transparent 0%, rgba(255,255,255,0) 30%,
    rgba(255,255,255,.22) 50%,
    rgba(255,255,255,0) 70%, transparent 100%
  );
  transform: skewX(-18deg); pointer-events: none;
  transition: left .9s var(--ease);
}
.u-btn:hover { transform: translateY(-2px); }
.u-btn:hover::before { left: 135%; }
.u-btn--sm { padding: 10px 20px; font-size: .76rem; min-height: 40px; }
.u-btn--block { width: 100%; }

/* ── Utility layer ─────────────────────────────────────────────────── */

/*
   EQUAL-HEIGHT CARDS FIX (.u-cards-equal)
   ─────────────────────────────────────────
   Bug: in a grid row, cards with different copy lengths have unequal heights
   and their CTA buttons don't align at the bottom.
   Fix: set align-items:stretch on the grid, give each card display:flex +
   flex-direction:column, and apply margin-top:auto to the CTA element.

   Usage:
     <div class="your-grid u-cards-equal">
       <div class="your-card">
         <p>Short text</p>
         <a class="u-btn" style="margin-top:auto">Book</a>
       </div>
       <div class="your-card">
         <p>Much longer text that would otherwise push the button down...</p>
         <a class="u-btn" style="margin-top:auto">Book</a>
       </div>
     </div>

   Apply to the card element itself via bespoke CSS:
     .your-card { display:flex; flex-direction:column; }
     .your-card .u-btn { margin-top:auto; }
*/
.u-cards-equal { align-items: stretch; }
.u-cards-equal > * { display: flex; flex-direction: column; }

/*
   ╔══════════════════════════════════════════════════════════════╗
   ║  CONTRAST GUARD — READ BEFORE BUILDING DARK SECTIONS        ║
   ║                                                              ║
   ║  Headings on dark-background sections MUST be set to a      ║
   ║  light colour explicitly in the bespoke CSS. Never let a    ║
   ║  heading inherit a dark token (e.g. --ink, --espresso) on   ║
   ║  a dark background — this shipped as a live contrast bug     ║
   ║  on Skulpt (heading invisible against dark section).         ║
   ║                                                              ║
   ║  Rule: for every dark section, add an explicit rule:         ║
   ║    .your-dark-section h2,                                    ║
   ║    .your-dark-section h3 { color: var(--light-token); }     ║
   ║                                                              ║
   ║  Do NOT rely on inherited colour from a parent :root.        ║
   ╚══════════════════════════════════════════════════════════════╝

   PRICE / ACCENT TEXT — AA CONTRAST REMINDER
   ───────────────────────────────────────────
   Accent / price text on light backgrounds must meet WCAG AA
   (≥4.5:1 contrast ratio against the background). Warm accent
   colours (gold, rust, bronze) often fail on cream/white — test
   at https://webaim.org/resources/contrastchecker/ and pick a
   shade dark enough to pass before shipping.
*/

/* ── Reduced-motion — force-reveal everything, kill animations ─────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,*::before,*::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* Force-reveal scroll-triggered elements */
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  [data-reveal-stagger] > * { opacity: 1 !important; transform: none !important; }
  /* Kill any hero load-stagger the build defines (target .is-hero-animate in build) */
  .is-hero-animate { opacity: 1 !important; animation: none !important; }
}
