/* ============================================================================
   Bling Besties — stylesheet
   Values mirror brand.json (the brand source of truth, per [ref]).
   Change a colour THERE first, then here. Nowhere else.

   Built hand-authored with no build step ON PURPOSE: the founders must be able to
   open this file and change it. Modern CSS is what makes that viable — nesting,
   custom properties and container queries replace the tooling a 2020 site needed.
   ============================================================================ */

/* ---- 1. TOKENS — [ref] tokens not values, [ref] tokens carry intent ---- */
:root {
  /* brand constants (theme-independent) */
  --brand-violet:  #6D28D9;
  --brand-fuchsia: #DB2777;
  --brand-cyan:    #0891B2;
  --brand-gold:    #B45309;

  /* light theme — the default. [ref]: theme via token modes, not a second stylesheet */
  --bg:            #FDFCFF;
  --surface:       #FFFFFF;
  --surface-alt:   #F6F3FB;
  --text:          #1E1B2E;
  --text-muted:    #565073;
  --border:        #E6E0F0;
  --accent:        var(--brand-violet);   /* derive, never restate the hex — [ref] */
  --accent-contrast: #FFFFFF;
  /* Text-safe companions. --brand-fuchsia (#DB2777) is a BRAND constant and only reaches
     4.497:1 on --bg — a hair under the 4.5 AA floor, so it must never carry text. These two
     are the theme-aware tokens that do. Verified: 5.91:1 and 4.14:1 on their own grounds. */
  --fuchsia-text:  #BE185D;
  --accent-muted:  #7E6BB0;
  --shadow: 0 1px 2px rgba(30,27,46,.06), 0 8px 24px rgba(109,40,217,.08);
  --shadow-lg: 0 2px 4px rgba(30,27,46,.06), 0 16px 48px rgba(109,40,217,.14);

  /* shape */
  --radius: 14px;
  --radius-sm: 8px;
  --radius-pill: 999px;

  /* type — [ref] stepped, zoom-safe (rem-based clamp), measure capped below */
  --font-display: 'Trebuchet MS', 'Segoe UI', 'Avenir Next', Avenir, 'Century Gothic', system-ui, sans-serif;
  --font-body: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --step--1: clamp(.83rem, .8rem + .15vw, .92rem);
  --step-0:  clamp(1rem, .96rem + .2vw, 1.09rem);
  --step-1:  clamp(1.2rem, 1.1rem + .5vw, 1.5rem);
  --step-2:  clamp(1.5rem, 1.3rem + 1vw, 2.1rem);
  --step-3:  clamp(1.95rem, 1.6rem + 1.8vw, 3.2rem);

  /* space */
  --sp-1: .5rem; --sp-2: .75rem; --sp-3: 1rem; --sp-4: 1.5rem;
  --sp-5: 2rem;  --sp-6: 3rem;   --sp-7: 4.5rem;

  --wrap: 72rem;
  --measure: 62ch;
  --transition: 180ms ease;
}

/* color-scheme tells the BROWSER which way round we are, so its own widgets — form
   controls, scrollbars, the autofill overlay — are drawn to match. It is declared on
   bare :root so it holds for EVERY light state: the default, an explicit
   data-theme="light", and data-theme="auto" on a light device. The dark states each
   re-declare it below.

   It used to say `[data-theme="dark"], [data-theme="auto"] { color-scheme: light }`,
   which was two bugs in one line: it claimed light for the DARK theme (only harmless
   because a later same-specificity rule happened to win on source order), and it left
   the explicit light state undeclared entirely — so a visitor who pressed the toggle
   to light got dark scrollbars and dark form widgets on a white page. Caught by the
   web-design validator 2026-09-01. A rule whose correctness depends on which line it
   sits on is a trap in a file a beginner is meant to edit. */
:root { color-scheme: light; }

@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] { color-scheme: dark; }
  :root[data-theme="auto"] {
    --bg: #12101C; --surface: #1B1830; --surface-alt: #241F3D;
    --text: #F4F1FA; --text-muted: #B0A8C8; --border: #332C4F;
    --accent: #C4B5FD; --accent-contrast: #1E1B2E;
    --fuchsia-text: #F472B6; --accent-muted: #8578C0;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.35);
    --shadow-lg: 0 2px 4px rgba(0,0,0,.45), 0 16px 48px rgba(0,0,0,.5);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #12101C; --surface: #1B1830; --surface-alt: #241F3D;
  --text: #F4F1FA; --text-muted: #B0A8C8; --border: #332C4F;
  --accent: #C4B5FD; --accent-contrast: #1E1B2E;
  --fuchsia-text: #F472B6; --accent-muted: #8578C0;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.35);
  --shadow-lg: 0 2px 4px rgba(0,0,0,.45), 0 16px 48px rgba(0,0,0,.5);
}

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

/* scroll-padding-top is not cosmetic: the header is sticky and ~69px tall, so without
   this an in-page jump (#shop, #how) parks the target heading UNDERNEATH it - the heading
   you just asked for is the one thing you cannot see, and a keyboard user landing there
   has focus obscured (WCAG 2.4.11). Kit 4l: test the JUMP, not the link. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: var(--font-display);
  line-height: 1.15;
  letter-spacing: -.015em;
  text-wrap: balance;   /* progressive enhancement — ignored where unsupported */
}
h1 { font-size: var(--step-3); }
h2 { font-size: var(--step-2); }
h3 { font-size: var(--step-1); }

p { text-wrap: pretty; max-width: var(--measure); }   /* [ref] measure cap */

a { color: var(--accent); text-underline-offset: .18em; }
img { max-width: 100%; height: auto; display: block; }

/* [ref]/[ref] focus must always be visible and never removed */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

.wrap { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: var(--accent-contrast);
  padding: var(--sp-2) var(--sp-3); border-radius: 0 0 var(--radius-sm) 0;
}
.skip:focus { left: 0; }

.small { font-size: var(--step--1); }
.muted { color: var(--text-muted); }
.section-head { margin-bottom: var(--sp-5); }
.section-head p { color: var(--text-muted); }

section { padding-block: var(--sp-7); }

/* ---- 3. HEADER ---- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
@supports not (backdrop-filter: blur(10px)) { .site-header { background: var(--bg); } }

.header-inner {
  display: flex; align-items: center; gap: var(--sp-4);
  min-height: 60px; padding-block: var(--sp-2);
}
.logo {
  display: inline-flex; align-items: center; gap: .45rem; min-height: 44px;
  font-family: var(--font-display); font-weight: 700; font-size: 1.15rem;
  color: var(--text); text-decoration: none; margin-inline-end: auto;
}
.logo-mark { color: var(--fuchsia-text); font-size: 1.2em; }
.logo-accent { color: var(--accent); }

.nav { display: flex; gap: var(--sp-4); list-style: none; padding: 0; }
.nav a {
  color: var(--text-muted); text-decoration: none; font-size: var(--step--1);
  /* [ref] touch floor — 44px min target, met via padding not font-size */
  display: inline-flex; align-items: center; min-height: 44px;
  transition: color var(--transition);
}
.nav a:hover { color: var(--accent); }
/* [4l] NAV VISIBLE BEATS HIDDEN. NN/g (179 users): hamburger-only HALVES nav discovery and
   cuts task completion 21%; it is for browse-mostly content sites, not a 3-link shop window.
   So on narrow screens the nav WRAPS to its own full-width row instead of collapsing into a
   menu button. (The household's crochet site uses a hamburger - deliberately NOT copied.) */
@media (max-width: 40rem) {
  .header-inner { flex-wrap: wrap; gap: var(--sp-2); }
  .logo { margin-inline-end: 0; }
  .header-inner > nav { order: 3; width: 100%; }
  .nav {
    width: 100%; justify-content: space-between;
    gap: var(--sp-2); border-top: 1px solid var(--border); padding-top: 2px;
  }
  .nav a { font-size: .82rem; min-height: 40px; }
}

.theme-toggle {
  display: inline-grid; place-items: center;
  width: 44px; height: 44px;            /* [ref] */
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface); color: var(--text-muted);
  font-size: 1.1rem; cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
}
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }

/* ---- 4. BUTTONS — [ref]: never de-emphasize an interactive control with opacity ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 48px; padding: .75rem 1.4rem;
  border-radius: var(--radius-pill);
  font: inherit; font-weight: 600; text-decoration: none;
  border: 2px solid transparent; cursor: pointer;
  transition: transform var(--transition), box-shadow var(--transition), background var(--transition);
}
.btn-primary { background: var(--accent); color: var(--accent-contrast); box-shadow: var(--shadow); }
.btn-primary:hover { box-shadow: var(--shadow-lg); transform: translateY(-2px); }
.btn-ghost { background: transparent; color: var(--text); border-color: var(--border); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn-lg { font-size: var(--step-1); padding: 1rem 2rem; }
.btn-icon { font-size: 1.1em; }

@media (prefers-reduced-motion: reduce) {           /* [ref] */
  .btn, .card, .theme-toggle { transition: none; }
  .btn-primary:hover { transform: none; }
}

/* ---- 5. HERO ---- */
.hero { padding-block: clamp(var(--sp-6), 8vw, var(--sp-7)); }
.hero-inner {
  display: grid; gap: var(--sp-6); align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) { .hero-inner { grid-template-columns: 1.1fr .9fr; } }

.eyebrow {
  font-size: var(--step--1); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--fuchsia-text); margin-bottom: var(--sp-2);
}
.hero h1 em {
  font-style: normal;
  background: linear-gradient(100deg, var(--brand-fuchsia), var(--brand-violet) 55%, var(--brand-cyan));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.lede { font-size: var(--step-1); color: var(--text-muted); margin-top: var(--sp-3); }
.cta-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); max-width: none; }
.reassure { margin-top: var(--sp-3); font-size: var(--step--1); color: var(--text-muted); }

/* CSS-drawn case. Stands in for a photo we don't have yet — deliberately abstract,
   so nobody mistakes it for a real product shot. */
.hero-art { display: grid; place-items: center; }
.case-mock {
  position: relative; width: min(70vw, 240px); aspect-ratio: 1 / 2;
  border-radius: 34px;
  background: linear-gradient(155deg, var(--brand-violet), var(--brand-fuchsia) 50%, var(--brand-cyan));
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.case-shine {
  position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255,255,255,.45) 50%, transparent 65%);
}
.case-lens {
  position: absolute; top: 16px; left: 16px; width: 62px; height: 62px;
  border-radius: 18px; background: rgba(0,0,0,.28);
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.25);
}
.gems { position: absolute; inset: 0; }
.gems span {
  position: absolute; width: 12px; height: 12px; border-radius: 50%;
  background: rgba(255,255,255,.85);
  box-shadow: 0 0 8px 2px rgba(255,255,255,.6);
}
.gems span:nth-child(1){top:22%;left:18%} .gems span:nth-child(2){top:31%;left:62%}
.gems span:nth-child(3){top:44%;left:34%} .gems span:nth-child(4){top:52%;left:74%}
.gems span:nth-child(5){top:63%;left:22%} .gems span:nth-child(6){top:70%;left:55%}
.gems span:nth-child(7){top:80%;left:38%} .gems span:nth-child(8){top:37%;left:12%}
.gems span:nth-child(9){top:88%;left:68%} .gems span:nth-child(10){top:14%;left:46%}

@media (prefers-reduced-motion: no-preference) {
  .gems span { animation: twinkle 3.5s ease-in-out infinite; }
  .gems span:nth-child(even) { animation-delay: 1.2s; }
  .gems span:nth-child(3n) { animation-delay: 2.1s; }
  @keyframes twinkle { 0%,100% { opacity:.35; transform: scale(.8);} 50% { opacity:1; transform: scale(1.15);} }
}

/* ---- 6. THE TWO LINES ---- */
.lines { padding-block: var(--sp-5); }
.line-list { display: grid; gap: var(--sp-4); list-style: none; padding: 0; grid-template-columns: 1fr; }
@media (min-width: 44rem) { .line-list { grid-template-columns: 1fr 1fr; } }
.line-card {
  position: relative; padding: var(--sp-5);
  background: var(--surface-alt); border: 1px solid var(--border); border-radius: var(--radius);
}
/* NOT `opacity:.35` on the accent - that alpha-blends the text toward the card and
   computes to ~1.8:1, failing even the relaxed 3:1 large-text floor. Muted SOLID token. */
.line-num {
  font-family: var(--font-display); font-size: var(--step-2); font-weight: 700;
  color: var(--accent-muted); display: block; line-height: 1;
}
.line-card h3 { margin-block: var(--sp-2) var(--sp-1); }
.line-card p { color: var(--text-muted); }

/* ---- 7. SHOP GRID — [ref] the card queries its own container ---- */
.grid {
  display: grid; gap: var(--sp-4); list-style: none; padding: 0;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
}
.card {
  container-type: inline-size;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow);
  transition: transform var(--transition), box-shadow var(--transition);
}
.card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
/* width+height are on the <img> too, so the browser reserves the space before the file
   arrives — that's what stops the page jumping as photos load ([ref] CLS). */
.card img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-bottom: 1px solid var(--border); }
.card-body { padding: var(--sp-3); }
.card-body h3 { font-size: var(--step-0); }
.card-body p { font-size: var(--step--1); color: var(--text-muted); }
@container (min-width: 18rem) { .card-body h3 { font-size: var(--step-1); } }

/* (The "photo coming soon" placeholder styles lived here. Deleted 2026-08-31 once real
   sample images were wired in - unreferenced CSS in a file a beginner edits is a trap.) */
.grid-note { margin-top: var(--sp-4); color: var(--text-muted); }

/* ---- 8. CUSTOM ---- */
.custom { background: var(--surface-alt); }
.custom-inner { display: grid; gap: var(--sp-6); align-items: center; grid-template-columns: 1fr; }
@media (min-width: 52rem) { .custom-inner { grid-template-columns: 1.2fr .8fr; } }
.ticks { list-style: none; padding: 0; margin-block: var(--sp-4); display: grid; gap: var(--sp-2); }
.ticks li { padding-left: 1.8rem; position: relative; color: var(--text-muted); }
.ticks li::before {
  content: "✦"; position: absolute; left: 0; color: var(--fuchsia-text); font-size: 1.1em;
}
.swatches { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: center; }
.swatches span {
  width: 56px; height: 56px; border-radius: 50%; background: var(--c);
  box-shadow: var(--shadow); display: block;
}
.swatch-caption {
  text-align: center; margin-top: var(--sp-3);
  font-size: var(--step--1); color: var(--text-muted); margin-inline: auto;
}

/* ---- 9. STEPS ---- */
.steps {
  display: grid; gap: var(--sp-4); list-style: none; padding: 0; counter-reset: step;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.step {
  padding: var(--sp-5); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.step-num {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  background: var(--accent); color: var(--accent-contrast);
  font-family: var(--font-display); font-weight: 700; margin-bottom: var(--sp-3);
}
.step h3 { margin-bottom: var(--sp-1); }
.step p { color: var(--text-muted); font-size: var(--step--1); }

.order-cta { margin-top: var(--sp-6); text-align: center; }
.order-note { margin: var(--sp-3) auto 0; color: var(--text-muted); font-size: var(--step--1); }

/* ---- 10. ABOUT / FAQ ---- */
.about-inner { max-width: var(--measure); }
.about-inner .lede { margin-block: var(--sp-3); }
.about-inner .small { color: var(--text-muted); margin-top: var(--sp-3); }

.faq { background: var(--surface-alt); }
.faq-list { display: grid; gap: var(--sp-2); max-width: 48rem; }
.qa {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--sp-3) var(--sp-4);
}
/* `display:flex` on a <summary> removes the browser's default disclosure triangle,
   which leaves no visual sign the row opens. So we draw our own chevron — it also
   looks better and behaves identically across browsers. */
.qa summary {
  cursor: pointer; font-weight: 600; font-family: var(--font-display);
  min-height: 44px;                       /* [ref] touch floor */
  display: flex; align-items: center; gap: var(--sp-3);
  list-style: none;
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
  content: ""; margin-inline-start: auto; flex: none;
  width: .6em; height: .6em;
  border-right: 2.5px solid var(--accent);
  border-bottom: 2.5px solid var(--accent);
  transform: rotate(45deg) translate(-.1em, -.1em);
  transition: transform var(--transition);
}
.qa[open] summary::after { transform: rotate(-135deg) translate(-.15em, -.15em); }
@media (prefers-reduced-motion: reduce) { .qa summary::after { transition: none; } }
.qa p { margin-top: var(--sp-2); color: var(--text-muted); font-size: var(--step--1); }
.qa[open] { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }

/* ---- 11. FOOTER ---- */
.site-footer {
  border-top: 1px solid var(--border); padding-block: var(--sp-6);
  background: var(--surface);
}
.footer-inner { display: grid; gap: var(--sp-2); text-align: center; justify-items: center; }
.footer-inner p { max-width: none; }
.footer-brand { font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); }
.footer-brand span { color: var(--fuchsia-text); }
.footer-link {
  display: inline-flex; align-items: center; min-height: 44px;   /* [ref] */
  font-weight: 600;
}


/* ---- 12. STICKY ORDER BAR (mobile) — kit 4l ----------------------------------
   For a small-business site the sticky element should be the CONTACT/CTA, not a
   secondary section-nav. On a phone the order button would otherwise scroll away
   for most of the page. Desktop keeps the in-page CTAs and shows no bar. */
.order-bar { display: none; }

@media (max-width: 40rem) {
  /* [2.4.11 Focus Not Obscured] The mirror image of scroll-padding-top above. That one
     stops a heading parking UNDER the sticky header; this one stops a focused control
     parking under the sticky order bar. body padding-bottom already protects the end of
     the document, but it reserves space in the DOCUMENT, not in the browser's
     viewport-relative scroll maths - so tabbing through the 20 design links could still
     land a focus ring behind the bar. Caught by the accessibility validator 2026-09-01:
     the top half of this pattern had been solved and the bottom half never written. */
  html { scroll-padding-bottom: calc(5.5rem + env(safe-area-inset-bottom, 0px)); }

  .order-bar {
    display: block; position: fixed; z-index: 60;
    left: 0; right: 0; bottom: 0;
    padding: var(--sp-2) var(--sp-3);
    padding-bottom: calc(var(--sp-2) + env(safe-area-inset-bottom, 0px));
    background: color-mix(in srgb, var(--bg) 92%, transparent);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--border);
  }
  @supports not (backdrop-filter: blur(10px)) { .order-bar { background: var(--bg); } }
  .order-bar .btn { width: 100%; }
  /* keep the footer clear of the bar */
  body { padding-bottom: 5.5rem; }
}

/* ---- 13. INTERACTION STATES — kit 4j ----------------------------------------
   State completeness is the #1 template-UI tell: every interactive element needs
   hover, a :focus-visible DISTINCT from hover, and a pressed state under 150ms. */
.btn:active { transform: translateY(1px); }
.btn-primary:active { box-shadow: var(--shadow); }
.nav a:active, .footer-link:active { opacity: 1; }         /* never fade a control - [ref] */
.theme-toggle:active { transform: scale(.94); }
.qa summary:hover { color: var(--accent); }

/* focus-visible must not merely repeat hover: hover tints, focus draws a ring */
.btn:focus-visible, .nav a:focus-visible, .theme-toggle:focus-visible,
.qa summary:focus-visible, .footer-link:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .btn:active, .theme-toggle:active { transform: none; }
}

/* ---- 14. SCROLL REVEALS — kit 4i motion floor -------------------------------
   Restraint rules: fires once, <=30px travel, <=600ms, skim-path elements only
   (section entrances + cards) and NEVER body text. CSS-first via scroll-driven
   animation; zero libraries ([ref]). The base state is fully visible, so with
   no JS and no support the page is complete - motion is pure enhancement. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .line-card, .card, .step, .qa {
      animation: reveal linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }
    @keyframes reveal {
      from { opacity: 0; transform: translateY(24px); }   /* 24px <= the 30px cap */
      to   { opacity: 1; transform: none; }
    }
  }
}

/* ---- 15. MOTION BORROWED FROM THE CROCHET SITE (studied 2026-08-31) ----------
   The household's nuhas-crochet site has real motion craft. Two ideas earn their
   place here; three deliberately do not.

   ADOPTED — the CTA attention-bounce. On that site the WhatsApp button bounces a
   FIXED THREE TIMES after a 2s delay, then stops for good. That restraint is what
   makes it good: it points at the one action the page exists for, then gets out of
   the way. Bounded repetition is compatible with the kit's motion rules in a way
   perpetual motion is not.

   ADOPTED — a shadow that appears under the sticky header once you scroll. It gives
   the translucent bar an edge when content passes beneath it. Done here with a
   scroll-driven animation so it costs no JavaScript at all (theirs uses a scroll
   listener toggling a class).

   DECLINED — logo-shimmer, yarn-wobble and float: all three run INFINITELY. They
   suit a soft handmade-yarn brand, and they are charming there. But kit 4i is
   explicit that motion is a decision in both directions, and that reveals fire once;
   perpetual decorative motion is the "motion everywhere reads templated" failure, and
   it costs battery and attention on the phones this audience actually uses. There is
   already ONE infinite decorative animation here (the hero gems) - that is the budget. */

@media (prefers-reduced-motion: no-preference) {
  /* fires 3 times, 2.5s after load, then never again */
  .hero .btn-primary { animation: cta-nudge 2.2s ease-in-out 2.5s 3; }
  @keyframes cta-nudge {
    0%, 100%  { transform: translateY(0)    scale(1); }
    30%       { transform: translateY(-8px) scale(1.04); }
    60%       { transform: translateY(-3px) scale(1.02); }
  }

  @supports (animation-timeline: scroll()) {
    .site-header {
      animation: header-lift linear both;
      animation-timeline: scroll();
      animation-range: 0 90px;
    }
    @keyframes header-lift {
      from { box-shadow: 0 0 0 rgba(0,0,0,0); }
      to   { box-shadow: var(--shadow); }
    }
  }
}

/* Footer nav — kit 4l "footer = curated sitemap". Three real destinations, weight-
   differentiated from the brand line above, 44px targets like every other control. */
.footer-nav { display: flex; flex-wrap: wrap; gap: var(--sp-4); justify-content: center; }
.footer-nav a {
  color: var(--text-muted); text-decoration: none; font-size: var(--step--1);
  display: inline-flex; align-items: center; min-height: 44px;
  transition: color var(--transition);
}
.footer-nav a:hover { color: var(--accent); }
.footer-nav a:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }


/* Per-design "ask about this one" link. NOT a competing CTA - it is the SAME goal
   (message us) arriving pre-addressed, which is what the crochet site does well:
   the customer lands in WhatsApp with the design already named, so they only have
   to press send, and the founders instantly know which case is meant. Styled
   secondary to the page's primary buttons so the hierarchy still reads. */
.card-cta {
  display: inline-flex; align-items: center; gap: .35rem;
  min-height: 44px;                     /* touch floor, same as every other control */
  margin-top: var(--sp-1);
  font-size: var(--step--1); font-weight: 600;
  color: var(--accent); text-decoration: none;
  transition: gap var(--transition);
}
.card-cta:hover { gap: .6rem; text-decoration: underline; }
.card-cta:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .card-cta { transition: none; } }
