/* ============================================================
   Faye K Face Skin Clinic — Liquid Glass Design System
   ============================================================ */

:root {
  /* ---- Faye's brand colours, supplied Aug 2026. These three are exact. ---- */
  --bg: #F6F5F4;            /* brand — off-white ground */
  --accent: #D16F50;        /* brand — lighter terracotta */
  --accent-strong: #BD6429; /* brand — burnt orange; fills, buttons, logotype */

  /* Derived, not invented: #BD6429 only reaches 3.8:1 on #F6F5F4, which fails AA for
     small text. This is the same hue pushed darker for links, labels and captions, so
     the brand still reads as one colour but stays legible. Fills keep the exact brand
     orange above, where contrast rules don't bite. */
  --accent-deep: #A5551F;

  --ink: #3B2B24;
  --ink-soft: #716057;
  --ink-faint: #9C8B81;

  /* Tints of the two brand oranges — drifting background blobs and image mats. */
  --accent-soft: #E8B7A8;
  --peach: #E6C4AE;
  --rose: #EDC5B9;
  --amber: #F1DCC0;

  --white: #FFFFFF;
  --radius: 24px;
  --radius-sm: 16px;
  /* Faye's brand face, on every heading and the wordmark. Neue Montreal is licensed from
     Pangram Pangram and is NOT installed — the first two names take over automatically the
     moment the licensed webfont files are self-hosted here and given an @font-face rule.
     Schibsted Grotesk is the stand-in until that happens; nothing else needs to change. */
  --font-display: "PP Neue Montreal", "Neue Montreal", "Schibsted Grotesk", "Inter", sans-serif;
  --font-body: "Inter", -apple-system, "Segoe UI", sans-serif;
  /* Client testimonials keep the serif. They're quotations, not headings — the different
     voice is deliberate, and it stops the long stories reading as more UI. */
  --font-quote: "Fraunces", Georgia, serif;
  --shadow-lift: 0 24px 48px -24px rgba(80, 42, 24, 0.28), 0 8px 20px -10px rgba(80, 42, 24, 0.14);
  --nav-h: 76px;
}

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

html { scroll-behavior: smooth; scroll-padding-top: calc(var(--nav-h) + 16px); }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--bg);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

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

/* Weights and tracking are set for a grotesque, not the serif this replaced: a bold
   sans needs more weight to feel deliberate and tighter tracking to stop it sprawling. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.022em;
  color: var(--ink);
  margin: 0 0 0.5em;
}

h1 { font-size: clamp(2.6rem, 6.5vw, 4.6rem); }
h2 { font-size: clamp(1.9rem, 4vw, 2.9rem); }
h3 { font-size: clamp(1.3rem, 2.4vw, 1.7rem); }

p { margin: 0 0 1em; color: var(--ink-soft); }
p:last-child { margin-bottom: 0; }

a { color: var(--accent-deep); text-decoration-thickness: 1px; text-underline-offset: 3px; }

a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent-deep);
  outline-offset: 3px;
  border-radius: 4px;
}

.eyebrow {
  display: inline-block;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-deep);
  margin-bottom: 1rem;
}

.wrap { width: min(1160px, 92vw); margin: 0 auto; }
.wrap-narrow { width: min(820px, 92vw); margin: 0 auto; }

section { padding: clamp(4rem, 9vw, 7.5rem) 0; position: relative; }

.section-head { max-width: 640px; margin-bottom: clamp(2rem, 5vw, 3.5rem); }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }

/* ============================================================
   Animated gradient blob background + grain
   ============================================================ */

.bg-scene {
  position: fixed;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 80% -10%, #FAEEE9 0%, transparent 60%),
    var(--bg);
}

.blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.75;
  will-change: transform;
}

.blob.b1 {
  width: 55vmax; height: 55vmax; top: -18vmax; left: -12vmax;
  background: radial-gradient(circle at 35% 35%, var(--peach), transparent 68%);
  animation: drift1 46s ease-in-out infinite alternate;
}
.blob.b2 {
  width: 46vmax; height: 46vmax; top: 22vh; right: -16vmax;
  background: radial-gradient(circle at 60% 40%, var(--rose), transparent 66%);
  animation: drift2 58s ease-in-out infinite alternate;
}
.blob.b3 {
  width: 42vmax; height: 42vmax; bottom: -16vmax; left: 12vw;
  background: radial-gradient(circle at 45% 55%, var(--amber), transparent 64%);
  animation: drift3 52s ease-in-out infinite alternate;
}
.blob.b4 {
  width: 30vmax; height: 30vmax; top: 52vh; left: 38vw;
  background: radial-gradient(circle at 50% 50%, var(--accent-soft), transparent 62%);
  opacity: 0.5;
  animation: drift4 64s ease-in-out infinite alternate;
}

@keyframes drift1 { to { transform: translate(9vmax, 7vmax) scale(1.12) rotate(12deg); } }
@keyframes drift2 { to { transform: translate(-8vmax, 10vmax) scale(0.92) rotate(-10deg); } }
@keyframes drift3 { to { transform: translate(10vmax, -7vmax) scale(1.08); } }
@keyframes drift4 { to { transform: translate(-9vmax, -9vmax) scale(1.18); } }

.grain {
  position: absolute;
  inset: 0;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  pointer-events: none;
}

/* ============================================================
   Liquid glass components
   ============================================================ */

.glass {
  position: relative;
  background: linear-gradient(150deg, rgba(255,255,255,0.30), rgba(255,255,255,0.10) 55%, rgba(255,255,255,0.18));
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  backdrop-filter: blur(24px) saturate(160%);
  border-radius: var(--radius);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.65),
    var(--shadow-lift);
}

/* gradient hairline border faking refracted edge light */
.glass::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(160deg, rgba(255,255,255,0.95), rgba(255,255,255,0.12) 42%, rgba(255,255,255,0.45) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

/* faint top-edge specular highlight */
.glass::after {
  content: "";
  position: absolute;
  top: 0; left: 8%; right: 8%;
  height: 42%;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255,255,255,0.28), transparent 80%);
  pointer-events: none;
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass, .nav.scrolled .nav-inner, .nav-links {
    background: rgba(255, 252, 249, 0.94);
  }
}

.glass-pad { padding: clamp(1.5rem, 3.5vw, 2.5rem); }

/* --- Tilt cards with cursor glare --- */

.tilt-wrap { perspective: 1000px; }

[data-tilt] {
  transform-style: preserve-3d;
  transition: box-shadow 0.35s ease;
  will-change: transform;
}

[data-tilt] .glare {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(420px circle at var(--gx, 50%) var(--gy, 20%), rgba(255,255,255,0.42), transparent 55%);
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
  z-index: 2;
}

[data-tilt]:hover .glare { opacity: 1; }

/* --- Buttons --- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.9rem 1.7rem;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.98rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  border: 0;
  transition: transform 0.25s ease, box-shadow 0.25s ease, background-color 0.25s ease;
}

.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn-primary {
  /* Leads with the exact brand orange and grades into the deeper derived tone, so the
     button reads as #BD6429 while the label stays legible across the whole fill. */
  background: linear-gradient(160deg, var(--accent-strong), var(--accent-deep));
  color: #FFFFFF;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.35),
    0 14px 28px -12px rgba(189, 100, 41,0.55);
}
.btn-primary:hover { box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 18px 34px -12px rgba(189, 100, 41,0.6); }

.btn-glass {
  position: relative;
  background: linear-gradient(150deg, rgba(255,255,255,0.42), rgba(255,255,255,0.16));
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  backdrop-filter: blur(16px) saturate(150%);
  color: var(--ink);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), inset 0 0 0 1px rgba(255,255,255,0.35), 0 10px 22px -12px rgba(80,42,24,0.35);
}

/* ============================================================
   Navigation
   ============================================================ */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  padding: 14px 0;
  transition: padding 0.3s ease;
}

.nav-inner {
  width: min(1160px, 94vw);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /* Tightened vertically when the logo grew, so a bigger mark does not simply
     push the whole pill taller. */
  padding: 0.4rem 1.1rem 0.4rem 1.2rem;
  border-radius: 999px;
  transition: background 0.35s ease, box-shadow 0.35s ease, backdrop-filter 0.35s ease;
}

.nav.scrolled .nav-inner {
  background: linear-gradient(150deg, rgba(255,255,255,0.55), rgba(255,255,255,0.28));
  -webkit-backdrop-filter: blur(20px) saturate(170%);
  backdrop-filter: blur(20px) saturate(170%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), inset 0 0 0 1px rgba(255,255,255,0.3), 0 12px 32px -16px rgba(80,42,24,0.3);
}

.brand {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
/* Kept for the alt text, which is what shows if the logo file is ever missing. */
.brand em { font-style: normal; color: var(--accent-strong); }

/* The logotype. A near-square stacked lockup: "faye" set over "k face".

   Height-driven with width:auto so the artwork's own proportions decide the
   width — forcing both dimensions would squash it the first time Faye supplies
   a re-export at a different size. The width/height attributes on the tag give
   the browser the aspect ratio up front, so the nav does not jump as it loads.

   The file is transparent PNG. It has to be: the supplied artwork sat on pure
   white, and a white tile on the --bg header would read as a visible box. */
/* Sized larger than a wordmark would be. This lockup is square, so at a height
   that suits a wide "Faye K Face" it reads as a small stamp rather than a
   logo — a square mark needs more height to carry the same visual weight. */
.brand-logo {
  display: block;
  height: 64px;
  width: auto;
}
/* The portal bar is a fixed 76px, so this grows into slack that already
   existed and the bar height does not change. */
.portal-bar .brand-logo { height: 56px; }
@media (max-width: 640px) {
  .brand-logo { height: 50px; }
  .portal-bar .brand-logo { height: 44px; }
}

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(0.4rem, 1.6vw, 1.4rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-links a:not(.btn) {
  color: var(--ink);
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 500;
  padding: 0.4rem 0.35rem;
  border-radius: 8px;
}
.nav-links a:not(.btn):hover { color: var(--accent-deep); }
.nav-links a[aria-current="page"] { color: var(--accent-deep); font-weight: 600; }

.nav-links .btn { padding: 0.62rem 1.25rem; font-size: 0.9rem; }

.nav-toggle {
  display: none;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0.55rem;
  border-radius: 10px;
}
.nav-toggle span {
  display: block;
  width: 22px; height: 2px;
  background: var(--ink);
  margin: 5px 0;
  border-radius: 2px;
  transition: transform 0.3s ease, opacity 0.3s ease;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 880px) {
  .nav-toggle { display: block; }
  .nav-links {
    position: absolute;
    top: calc(100% + 10px);
    left: 3vw; right: 3vw;
    flex-direction: column;
    align-items: stretch;
    gap: 0.25rem;
    padding: 1rem;
    border-radius: var(--radius);
    background: linear-gradient(150deg, rgba(255,255,255,0.72), rgba(255,255,255,0.5));
    -webkit-backdrop-filter: blur(24px) saturate(160%);
    backdrop-filter: blur(24px) saturate(160%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.8), var(--shadow-lift);
    display: none;
  }
  .nav-links.open { display: flex; }
  .nav-links a:not(.btn) { display: block; padding: 0.7rem 0.8rem; font-size: 1.05rem; }
  .nav-links .btn { justify-content: center; margin-top: 0.5rem; }
}

/* ============================================================
   Hero (3D stage)
   ============================================================ */

.hero {
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: calc(var(--nav-h) + 3rem) 0 4rem;
}

.hero-stage {
  perspective: 1200px;
  width: min(1160px, 92vw);
  margin: 0 auto;
}

.hero-3d {
  position: relative;
  transform-style: preserve-3d;
  will-change: transform;
}

.hero-panel {
  max-width: min(640px, 56%); /* percentage keeps it clear of .hero-photo on narrow laptops */
  padding: clamp(2rem, 5vw, 3.5rem);
  transform: translateZ(40px);
  transform-style: preserve-3d;
}

/* The hero headline is the one place Faye's brand face leads. Bold grotesque needs
   tighter tracking and leading than the serif it replaced, or it reads loose at 4.6rem. */
.hero-panel h1 {
  margin-bottom: 0.4em;
  font-weight: 700;      /* heavier than the other headings — it's the one that shouts */
  letter-spacing: -0.03em;
  line-height: 1.02;
}
.hero-panel .lede { font-size: clamp(1.05rem, 1.6vw, 1.2rem); max-width: 46ch; }

.hero-ctas { display: flex; flex-wrap: wrap; gap: 0.9rem; margin-top: 2rem; }

/* Hero photo — another layer in the 3D stage, sitting behind the floating cards */
.hero-photo {
  position: absolute;
  top: 50%;
  right: 4%;
  width: min(28%, 330px);
  height: auto; /* beats the intrinsic height attribute so aspect-ratio governs */
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 16%;
  transform: translate3d(0, -50%, 12px);
  /* Feathered into the page rather than sitting in a hard card — the photo's plain
     backdrop dissolves into the gradient, so no border, radius or shadow here. */
  -webkit-mask-image: radial-gradient(ellipse 64% 78% at 50% 46%, #000 40%, rgba(0, 0, 0, 0) 92%);
          mask-image: radial-gradient(ellipse 64% 78% at 50% 46%, #000 40%, rgba(0, 0, 0, 0) 92%);
}

.float-card {
  position: absolute;
  padding: 1rem 1.3rem;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}
.float-card strong { font-family: var(--font-display); font-size: 1.25rem; display: block; font-weight: 650; }
.float-card .sub { display: block; color: var(--ink-soft); font-size: 0.82rem; }

.fc-award  { top: -6%; right: 4%;  transform: translateZ(90px); }
.fc-rating { top: 42%; right: 3%;  transform: translateZ(130px); }
.fc-method { bottom: -8%; right: 18%; transform: translateZ(60px); }

@media (max-width: 960px) {
  .fc-award  { top: auto; bottom: auto; right: auto; left: 0; position: relative; display: inline-block; margin: 1.4rem 0.6rem 0 0; transform: none; }
  .fc-rating { position: relative; top: auto; right: auto; display: inline-block; margin: 1.4rem 0.6rem 0 0; transform: none; }
  .fc-method { display: none; }
  .hero { min-height: auto; }

  /* Photo drops into the flow above the copy so mobile leads with a face too */
  .hero-3d { display: flex; flex-direction: column; }
  .hero-photo {
    position: relative;
    top: auto;
    right: auto;
    width: 100%;
    max-width: none;
    aspect-ratio: 4 / 3;
    object-position: 50% 4%; /* source has little headroom — keep the crop near the top */
    transform: none;
    order: -1;
    margin-bottom: 1.4rem;
  }
  .hero-panel { transform: none; max-width: none; }
}

/* ============================================================
   Shared section patterns
   ============================================================ */

.trust-bar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  text-align: center;
}
.trust-bar .glass { padding: 1.4rem 1rem; }
.trust-bar strong { font-family: var(--font-display); font-size: 1.5rem; font-weight: 650; display: block; color: var(--ink); }
.trust-bar span { font-size: 0.85rem; color: var(--ink-soft); }

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(1.2rem, 2.5vw, 2rem);
}

.offer-card { display: flex; flex-direction: column; }
.offer-card .glass-pad { display: flex; flex-direction: column; flex: 1; }
.offer-card h3 { margin-top: 0.4rem; }
.offer-card .btn { margin-top: auto; align-self: flex-start; }
.offer-card .tag {
  align-self: flex-start;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-deep);
  background: rgba(209, 111, 80,0.12);
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
}
.offer-card .price { font-family: var(--font-display); font-size: 1.15rem; font-weight: 650; color: var(--ink); margin-bottom: 1rem; }

.photo {
  width: 100%;
  height: auto; /* beats the intrinsic height attribute so aspect-ratio governs */
  display: block;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radius-sm);
  background: linear-gradient(120deg, var(--peach), var(--rose));
  box-shadow: 0 22px 46px -24px rgba(80, 42, 24, 0.42), 0 4px 12px -6px rgba(80, 42, 24, 0.16);
}

.img-placeholder {
  background:
    linear-gradient(150deg, rgba(255,255,255,0.5), rgba(255,255,255,0.15)),
    linear-gradient(120deg, var(--peach), var(--rose));
  border-radius: var(--radius-sm);
  min-height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-soft);
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
  padding: 1rem;
}

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
@media (max-width: 820px) { .split { grid-template-columns: 1fr; } }

/* --- Scroll reveal --- */

.reveal {
  opacity: 0;
  transform: translateY(34px) scale(0.985);
  transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform, opacity;
}
.reveal.in-view { opacity: 1; transform: none; }
.reveal-d1 { transition-delay: 0.1s; }
.reveal-d2 { transition-delay: 0.2s; }
.reveal-d3 { transition-delay: 0.3s; }

/* ============================================================
   Timeline (About)
   ============================================================ */

.timeline { position: relative; padding-left: 0; }

.timeline::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0; bottom: 0;
  width: 1px;
  background: linear-gradient(180deg, transparent, rgba(189, 100, 41,0.4) 8%, rgba(189, 100, 41,0.4) 92%, transparent);
  transform: translateX(-50%);
}

.timeline-item {
  position: relative;
  width: calc(50% - 3rem);
  margin-bottom: 3rem;
}
.timeline-item:nth-child(odd)  { margin-right: auto; }
.timeline-item:nth-child(even) { margin-left: auto; }

.timeline-item .dot {
  position: absolute;
  top: 2rem;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 5px rgba(209, 111, 80,0.18);
}
.timeline-item:nth-child(odd) .dot  { right: -3rem; transform: translateX(50%); }
.timeline-item:nth-child(even) .dot { left: -3rem; transform: translateX(-50%); }

.timeline-item .age {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-deep);
}

@media (max-width: 760px) {
  .timeline::before { left: 8px; transform: none; }
  .timeline-item,
  .timeline-item:nth-child(odd),
  .timeline-item:nth-child(even) { width: auto; margin-left: 2.4rem; margin-right: 0; }
  .timeline-item:nth-child(odd) .dot,
  .timeline-item:nth-child(even) .dot { left: -2.4rem; right: auto; transform: translateX(calc(-50% + 8.5px)); }
}

/* ============================================================
   FAQ / details
   ============================================================ */

.faq details {
  margin-bottom: 0.9rem;
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.faq summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--ink);
  padding: 1.1rem 1.4rem;
  list-style: none;
  position: relative;
  z-index: 1;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  float: right;
  font-family: var(--font-display);
  font-size: 1.3rem;
  color: var(--accent-deep);
  transition: transform 0.25s ease;
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq .faq-body { padding: 0 1.4rem 1.2rem; position: relative; z-index: 1; }

/* ============================================================
   Forms (Netlify contact form)
   ============================================================ */

.form-grid { display: grid; gap: 1.1rem; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
@media (max-width: 640px) { .form-row { grid-template-columns: 1fr; } }

label { font-size: 0.88rem; font-weight: 600; color: var(--ink); display: block; margin-bottom: 0.35rem; }

input[type="text"], input[type="email"], select, textarea {
  width: 100%;
  padding: 0.85rem 1rem;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(189, 100, 41,0.22);
  border-radius: 12px;
  transition: border-color 0.2s ease, background 0.2s ease;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.85);
}
textarea { resize: vertical; min-height: 140px; }

.hidden-field { display: none; }

/* ============================================================
   Legal / long-form text pages
   ============================================================ */

.legal { font-size: 1rem; }
.legal h2 {
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  margin-top: 2.6rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid rgba(59, 43, 36, 0.12);
}
.legal > h2:first-child { margin-top: 0; }
.legal h3 { font-size: 1.03rem; font-family: var(--font-body); font-weight: 600; margin: 1.6rem 0 0.5rem; }
.legal ul { color: var(--ink-soft); padding-left: 1.2rem; margin: 0 0 1.1rem; }
.legal li { margin-bottom: 0.5rem; }
.legal dl { margin: 0 0 1.2rem; }
.legal dt { font-weight: 600; color: var(--ink); margin-top: 0.9rem; }
.legal dd { margin: 0.2rem 0 0; color: var(--ink-soft); }

.legal-table-wrap { overflow-x: auto; margin: 0 0 1.3rem; }
.legal table { width: 100%; border-collapse: collapse; font-size: 0.94rem; min-width: 520px; }
.legal th {
  text-align: left;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-deep);
  font-weight: 600;
  padding: 0.7rem 1rem 0.7rem 0;
  border-bottom: 1px solid rgba(59, 43, 36, 0.18);
}
.legal td { padding: 0.75rem 1rem 0.75rem 0; border-bottom: 1px solid rgba(59, 43, 36, 0.08); color: var(--ink-soft); vertical-align: top; }
.legal td:first-child { color: var(--ink); font-weight: 500; }

/* Unmissable marker for details only Faye can supply */
.todo {
  display: inline-block;
  background: rgba(209, 111, 80,0.16);
  color: var(--accent-deep);
  padding: 0.1em 0.5em;
  border-radius: 5px;
  font-size: 0.88em;
  font-weight: 600;
  box-shadow: inset 0 0 0 1px rgba(189, 100, 41,0.35);
}

.updated {
  font-size: 0.88rem;
  color: var(--ink-faint);
  margin-bottom: 2rem;
}

/* Consent checkbox on the enquiry form */
.consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.7rem;
  align-items: start;
}
.consent input[type="checkbox"] {
  width: 1.1rem;
  height: 1.1rem;
  margin: 0.2rem 0 0;
  accent-color: var(--accent-deep);
  flex-shrink: 0;
}
.consent label {
  font-weight: 400;
  font-size: 0.88rem;
  color: var(--ink-soft);
  margin: 0;
  line-height: 1.55;
}

/* ============================================================
   Banners, notes, misc
   ============================================================ */

.banner {
  padding: 1.1rem 1.5rem;
  border-radius: var(--radius-sm);
  font-size: 0.95rem;
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
}
.banner strong { color: var(--accent-deep); }

.testimonial-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 1.5rem; }
.testimonial-card blockquote { margin: 0; font-family: var(--font-quote); font-size: 1.1rem; color: var(--ink); font-style: italic; }
.testimonial-card cite { display: block; margin-top: 1rem; font-style: normal; font-size: 0.85rem; color: var(--ink-faint); }
.stars { color: var(--accent); letter-spacing: 0.15em; margin-bottom: 0.8rem; font-size: 0.95rem; }

/* --- Featured testimonial: one long client story given room to breathe --- */

.testimonial-featured { position: relative; margin-bottom: 1.5rem; }
/* Text is indented into a gutter so the oversized quote glyph has somewhere to live. */
.testimonial-featured blockquote,
.testimonial-featured cite {
  padding-left: clamp(1.4rem, 3vw, 2.6rem);
  position: relative;
}
.testimonial-featured blockquote {
  margin: 0;
  max-width: 64ch;
  font-family: var(--font-quote);
  font-size: clamp(1.08rem, 1.5vw, 1.32rem);
  line-height: 1.6;
  font-style: italic;
  color: var(--ink);
}
.testimonial-featured blockquote p { margin: 0 0 1.1rem; }
.testimonial-featured blockquote p:last-child { margin-bottom: 0; }
.testimonial-featured cite {
  display: block;
  margin-top: 1.4rem;
  font-style: normal;
  font-size: 0.85rem;
  color: var(--ink-faint);
}
/* Oversized opening quote in the display serif — decorative, so it is generated content
   and stays out of the accessibility tree.
   It hangs off the BLOCKQUOTE, never the card: these cards are also .glass, and
   .glass::before is already the gradient hairline border. Putting it there would
   overwrite the border and the glass mask would erase the glyph. */
.testimonial-featured blockquote::before {
  content: "\201C";
  position: absolute;
  top: -0.3em;
  left: -0.02em;
  font-family: var(--font-quote);
  font-size: clamp(3.6rem, 6vw, 5.2rem);
  line-height: 1;
  color: var(--accent);
  opacity: 0.3;
  pointer-events: none;
}

/* --- Before / after client results ---
   Deliberately NO aspect-ratio and NO object-fit crop. Each supplied image is a
   side-by-side pair, so any crop trims one half more than the other and misrepresents
   the result. They keep their natural proportions instead. */
.result-shot {
  width: 100%;
  height: auto; /* beats the intrinsic height attribute */
  display: block;
  border-radius: var(--radius-sm);
  background: linear-gradient(120deg, var(--peach), var(--rose));
  box-shadow: 0 22px 46px -24px rgba(80, 42, 24, 0.42), 0 4px 12px -6px rgba(80, 42, 24, 0.16);
}
.results-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.2rem, 2.5vw, 2rem);
  align-items: start;
}
@media (max-width: 720px) { .results-pair { grid-template-columns: 1fr; } }
.result-caption {
  margin: 0.7rem 0 0;
  font-size: 0.82rem;
  color: var(--ink-faint);
}

/* Quiet disclaimer under a set of testimonials */
.results-note {
  margin: 1.6rem auto 0;
  max-width: 60ch;
  text-align: center;
  font-size: 0.8rem;
  color: var(--ink-faint);
}

.check-list { list-style: none; padding: 0; margin: 0 0 1.5rem; color: var(--ink-soft); }
.check-list li { padding-left: 1.7rem; position: relative; margin-bottom: 0.6rem; }
.check-list li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--accent-deep);
  font-weight: 700;
}

.pill-list { display: flex; flex-wrap: wrap; gap: 0.6rem; list-style: none; padding: 0; margin: 0; }
.pill-list li {
  font-size: 0.85rem;
  font-weight: 500;
  padding: 0.45rem 0.95rem;
  border-radius: 999px;
  background: rgba(255,255,255,0.5);
  box-shadow: inset 0 0 0 1px rgba(189, 100, 41,0.18), inset 0 1px 0 rgba(255,255,255,0.8);
  color: var(--ink-soft);
}

.final-cta { text-align: center; }
.final-cta .glass-pad { padding: clamp(2.5rem, 6vw, 4.5rem); }

/* ============================================================
   Footer
   ============================================================ */

footer {
  margin-top: 3rem;
  padding: 3.5rem 0 2.5rem;
  position: relative;
}
footer::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.35), rgba(255,255,255,0.6));
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  backdrop-filter: blur(20px) saturate(150%);
  border-top: 1px solid rgba(255,255,255,0.7);
  z-index: -1;
}

.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 2.5rem;
}
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr; } }

.footer-grid h4 { font-size: 1.05rem; margin-bottom: 0.8rem; }
.footer-grid ul { list-style: none; padding: 0; margin: 0; }
.footer-grid li { margin-bottom: 0.5rem; }
.footer-grid a { color: var(--ink-soft); text-decoration: none; font-size: 0.95rem; }
.footer-grid a:hover { color: var(--accent-deep); }
.footer-grid address { font-style: normal; color: var(--ink-soft); font-size: 0.95rem; line-height: 1.7; }

.footer-bottom {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(59, 43, 36, 0.1);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem;
  font-size: 0.83rem;
  color: var(--ink-faint);
}

/* ============================================================
   Client portal — login flow and portal shell
   Built entirely from the existing tokens; no new colours, radii or shadows.
   ============================================================ */

/* Available to the whole site: present to screen readers, invisible on screen. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.auth-wrap { width: min(460px, 92vw); margin: 0 auto; }
.auth-card { text-align: left; }
.auth-card h1 { font-size: clamp(1.9rem, 4.4vw, 2.5rem); margin-bottom: 0.5rem; }
.auth-card .lede { font-size: 1rem; margin-bottom: 1.8rem; }

/* Both steps sit in the same card. Reserving a min-height stops the card
   snapping shorter when the email step is swapped for the taller code step. */
.auth-steps { min-height: 268px; }

.auth-note {
  margin: 1.4rem 0 0;
  font-size: 0.85rem;
  color: var(--ink-faint);
  line-height: 1.55;
}

/* Feedback line. Space is reserved whether or not there's a message, so
   nothing below it jumps when an error or success appears. */
.auth-msg {
  min-height: 1.4rem;
  margin: 0.7rem 0 0;
  font-size: 0.87rem;
  line-height: 1.4;
  color: var(--ink-soft);
}
.auth-msg.is-error { color: var(--accent-deep); font-weight: 500; }
.auth-msg.is-success { color: var(--ink-soft); }

.auth-card .btn[disabled] { opacity: 0.55; cursor: not-allowed; }
.auth-card .btn[disabled]:hover { transform: none; }
.auth-card .btn-primary { width: 100%; justify-content: center; }

input[aria-invalid="true"] { border-color: var(--accent-deep); }

.sent-to {
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;   /* long addresses must not widen the card */
}

/* --- The six code boxes --- */

.otp-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: clamp(0.35rem, 2vw, 0.6rem);
  margin: 0.3rem 0 0;
}

.otp-input {
  width: 100%;
  aspect-ratio: 3 / 4;
  padding: 0;
  text-align: center;
  font-family: var(--font-body);
  font-size: clamp(1.1rem, 4.4vw, 1.45rem);
  font-weight: 600;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(189, 100, 41, 0.22);
  border-radius: 12px;
  transition: border-color 0.2s ease, background 0.2s ease;
  /* Safari zooms the page when a focused input is under 16px; the clamp above
     stays over that on phones, and this keeps iOS from restyling the boxes. */
  -webkit-appearance: none;
  appearance: none;
}
.otp-input:focus {
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.9);
}
.otp-grid[data-invalid] .otp-input,
.is-invalid .otp-input { border-color: var(--accent-deep); }

.auth-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.2rem;
  align-items: center;
  margin-top: 1.2rem;
}

/* Text buttons that read as links but stay real <button>s for keyboard use. */
.link-btn {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 0.87rem;
  color: var(--accent-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.link-btn:hover { color: var(--ink); }
.link-btn[disabled] { opacity: 0.55; cursor: not-allowed; text-decoration: none; }

/* --- Portal shell: the reusable frame future portal pages inherit --- */

/* Existing clients signing in aren't the audience the nav is built for, so the
   portal link is deliberately quieter than the booking CTA next to it. */
.nav-links .nav-portal {
  font-size: 0.86rem;
  color: var(--ink-faint);
}
.nav-links .nav-portal:hover { color: var(--accent-deep); }

.portal-bar {
  position: sticky;
  top: 0;
  z-index: 40;
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  background: rgba(255, 255, 255, 0.6);
  border-bottom: 1px solid rgba(189, 100, 41, 0.14);
}
.portal-bar-inner {
  width: min(1120px, 92vw);
  margin: 0 auto;
  min-height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.portal-nav {
  display: flex;
  gap: clamp(0.9rem, 3vw, 1.6rem);
  margin-right: auto;
  margin-left: clamp(1rem, 4vw, 2.5rem);
}
.portal-nav a {
  font-size: 0.9rem;
  color: var(--ink-soft);
  text-decoration: none;
}
.portal-nav a:hover { color: var(--accent-deep); }
.portal-nav a[aria-current="page"] { color: var(--accent-deep); font-weight: 600; }

.portal-main { padding: clamp(2.5rem, 6vw, 4.5rem) 0 clamp(4rem, 8vw, 6rem); }

@media (max-width: 520px) {
  .portal-bar-inner { flex-wrap: wrap; padding: 0.7rem 0; row-gap: 0.5rem; }
  .portal-nav { margin-left: 0; order: 3; width: 100%; }
}

@media (max-width: 420px) {
  .otp-grid { gap: 0.3rem; }
  .auth-steps { min-height: 300px; }
}

/* ============================================================
   The Acne Programme page
   ============================================================ */

/* --- Disclaimer / callout. Deliberately NOT .glass: it needs to read as a note
   from Faye rather than another content card, and .glass already owns ::before
   and ::after, so a left rule is the only safe way to mark it. --- */
.notice {
  border-left: 3px solid var(--accent);
  background: rgba(255, 255, 255, 0.45);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 1.1rem 1.4rem;
  font-size: 0.92rem;
  color: var(--ink-soft);
  max-width: 78ch;
}
.notice strong { color: var(--ink); }

/* --- "The short version": the whole page in a few lines, for anyone who won't
   read the rest. Set larger and in ink rather than ink-soft so it reads as the
   summary it is, not as another paragraph. --- */
.summary-list li {
  font-size: 1.05rem;
  color: var(--ink);
  margin-bottom: 0.85rem;
  line-height: 1.55;
}
.summary-list li strong { font-weight: 600; }

/* --- Quick facts under the hero --- */
.fact-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1rem;
  margin-top: 2.4rem;
}
.fact-row .glass { padding: 1.1rem 1rem; text-align: center; }
.fact-row strong {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 650;
  display: block;
  color: var(--ink);
}
.fact-row span { font-size: 0.82rem; color: var(--ink-soft); }

/* --- "Not for you if" — the mirror of .check-list --- */
.cross-list { list-style: none; padding: 0; margin: 0 0 1.5rem; color: var(--ink-soft); }
.cross-list li { padding-left: 1.7rem; position: relative; margin-bottom: 0.6rem; }
.cross-list li::before {
  content: "\00D7";
  position: absolute;
  left: 0;
  top: -0.06em;
  font-size: 1.15em;
  color: var(--ink-faint);
  font-weight: 700;
}

/* Fit cards sit side by side but hold different amounts of text, so they must
   top-align — .split centres, which would leave one list floating. */
.fit-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.2rem, 2.5vw, 2rem);
  align-items: start;
}
@media (max-width: 820px) { .fit-grid { grid-template-columns: 1fr; } }

/* --- The five foundational pillars. Parallel, not sequential, so deliberately
   unnumbered — numbering them would imply an order that doesn't exist. --- */
.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 1rem;
  margin-top: 1.8rem;
}
.pillars .glass { padding: 1.2rem 1.1rem; }
/* Five items into a two-column grid leaves an orphan. Letting the last one run the
   full width reads as a deliberate finish rather than a gap. */
.pillars > :last-child { grid-column: 1 / -1; }
.pillars h4 {
  font-size: 1rem;
  margin: 0 0 0.35rem;
  color: var(--ink);
}
.pillars p { font-size: 0.86rem; margin: 0; }

/* --- Conventional vs functional range.
   The whole argument of the testing section in one graphic: the same result
   sitting inside a wide "normal" band and outside a narrow optimal one. --- */
.range-demo { margin: 1.8rem 0 0; display: grid; gap: 1.4rem; }
.range-row {
  display: grid;
  grid-template-columns: 190px 1fr 104px;
  align-items: center;
  gap: 1.2rem;
}
.range-label { font-size: 0.9rem; font-weight: 600; color: var(--ink); }
.range-label .range-sub {
  display: block;
  font-weight: 400;
  font-size: 0.78rem;
  color: var(--ink-faint);
}
.range-track {
  position: relative;
  height: 14px;
  border-radius: 999px;
  background: rgba(59, 43, 36, 0.07);
}
.range-band {
  position: absolute;
  top: 0; bottom: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-soft), var(--peach));
}
.range-band.is-optimal { background: linear-gradient(90deg, var(--accent), var(--accent-strong)); }
.range-marker {
  position: absolute;
  top: -9px; bottom: -9px;
  width: 2px;
  background: var(--ink);
  border-radius: 2px;
}
.range-marker::after {
  content: "";
  position: absolute;
  top: -5px; left: 50%;
  width: 9px; height: 9px;
  margin-left: -4.5px;
  border-radius: 50%;
  background: var(--ink);
}
.range-verdict {
  font-size: 0.8rem;
  font-weight: 600;
  text-align: center;
  padding: 0.35rem 0.6rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.55);
  box-shadow: inset 0 0 0 1px rgba(189, 100, 41, 0.18);
  color: var(--ink-faint);
}
.range-verdict.is-flagged {
  color: var(--accent-deep);
  background: rgba(209, 111, 80, 0.14);
  box-shadow: inset 0 0 0 1px rgba(189, 100, 41, 0.3);
}
.range-caption { font-size: 0.82rem; color: var(--ink-faint); margin: 1.4rem 0 0; max-width: 68ch; }
@media (max-width: 720px) {
  .range-row { grid-template-columns: 1fr; gap: 0.7rem; }
  .range-verdict { justify-self: start; }
}

/* --- Phases of the 14 weeks --- */
.phase-weeks {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 650;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-deep);
  background: rgba(209, 111, 80, 0.12);
  padding: 0.32rem 0.8rem;
  border-radius: 999px;
  margin-bottom: 1rem;
}

/* --- What's included --- */
/* Nine items, so the 290px floor is chosen to land on three columns at full width —
   three clean rows rather than a row of four and a stranded ninth. */
.included {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: 1rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
/* Narrower viewports drop to two columns, which strands the ninth again. */
@media (max-width: 900px) { .included > :last-child { grid-column: 1 / -1; } }
.included li { padding: 1.1rem 1.2rem; }
/* h3, not h4: these sit directly under the section's h2, and skipping a level breaks
   heading navigation for screen-reader users. The size is set here instead. */
.included h3 { font-size: 0.98rem; margin: 0 0 0.3rem; }
.included p { font-size: 0.86rem; margin: 0; }

/* --- Numbered process. These ARE a sequence — you cannot do step 4 before
   step 2 — so the numerals carry real information. --- */
.steps { list-style: none; padding: 0; margin: 0; display: grid; gap: 1rem; }
.step { display: grid; grid-template-columns: auto 1fr; gap: 1.2rem; align-items: start; padding: 1.4rem 1.5rem; }
.step-n {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 650;
  line-height: 1;
  color: var(--accent-strong);
  font-variant-numeric: tabular-nums;
  min-width: 2.1ch;
}
.step h3 { font-size: 1.12rem; margin: 0 0 0.35rem; }
.step p { font-size: 0.94rem; margin: 0; }
@media (max-width: 520px) {
  .step { grid-template-columns: 1fr; gap: 0.5rem; padding: 1.2rem 1.2rem; }
}

/* --- Investment --- */
.value-figure {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 5.5vw, 3.4rem);
  font-weight: 650;
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.03em;
  margin: 0.4rem 0 0.6rem;
}

/* ============================================================
   Client shop — Phase 3A
   ============================================================ */

.shop-head { max-width: 640px; margin-bottom: clamp(1.6rem, 4vw, 2.4rem); }
.shop-head h1 { font-size: clamp(1.9rem, 4.4vw, 2.8rem); margin-bottom: 0.4rem; }
.shop-head .lede { font-size: 1rem; margin: 0; }

/* --- Toolbar: search, category, sort --- */

.shop-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-bottom: 1.2rem;
}
.shop-field { flex: 0 1 auto; }
/* Search takes the slack on wide screens and a full row on narrow ones. */
.shop-field-search { flex: 1 1 260px; min-width: 0; }

.shop-toolbar input[type="search"],
.shop-toolbar select {
  width: 100%;
  padding: 0.7rem 0.95rem;
  font-family: var(--font-body);
  font-size: 0.95rem;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid rgba(189, 100, 41, 0.22);
  border-radius: 12px;
  /* 16px stops iOS Safari zooming the whole page when the field is focused. */
  min-height: 44px;
}
@media (max-width: 640px) {
  .shop-toolbar input[type="search"],
  .shop-toolbar select { font-size: 16px; }
  .shop-field { flex: 1 1 100%; }
}

.shop-count {
  font-size: 0.85rem;
  color: var(--ink-faint);
  margin: 0 0 1.2rem;
}

/* --- Grid --- */

.shop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: clamp(1rem, 2.2vw, 1.6rem);
}
/* Two across on phones reads as a shop; one across reads as a list.
   The floor is set from the narrowest case we support: at a 320px viewport
   .wrap is 92vw = 294px, so two columns plus an 11px gap need a floor of at
   most 141px. 140px holds two columns all the way down; raising it drops
   320px phones to a single column. */
@media (max-width: 560px) {
  .shop-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.7rem; }
  .shop-card-body { padding: 0.75rem 0.8rem 0.9rem; }
  .shop-card-title { font-size: 0.92rem; }
  .shop-price { font-size: 0.98rem; }
  .stock-badge { font-size: 0.62rem; padding: 0.25rem 0.5rem; top: 0.45rem; left: 0.45rem; }
}

/* Flex column so an Add to Bag button below the link is a normal child that
   the card grows to fit. With the link at height:100% it sat past the card's
   bottom edge and overflow:hidden clipped it out of existence. */
.shop-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.35s ease;
}
.shop-card:hover { transform: translateY(-4px); }
.shop-card:focus-within { transform: translateY(-4px); }

.shop-card-link {
  display: flex;
  flex-direction: column;
  /* flex:1, not height:100% — the button below must get its own space. */
  flex: 1;
  text-decoration: none;
  color: inherit;
  position: relative;
  z-index: 1;
}
/* The whole card is one link, so the focus ring belongs on the card edge
   rather than tight around the text. */
.shop-card-link:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: -3px; border-radius: var(--radius); }

.shop-card-frame {
  position: relative;
  border-radius: var(--radius) var(--radius) 0 0;
  overflow: hidden;
  background: linear-gradient(120deg, var(--peach), var(--rose));
}

.shop-img {
  width: 100%;
  height: auto;              /* beats the intrinsic height attribute */
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
}
/* The generated brand placeholder is artwork, not a photo, so it must not be
   cropped to fill the box. */
.shop-img.is-placeholder { object-fit: contain; }

.shop-card-body { padding: 0.95rem 1.05rem 1.15rem; display: flex; flex-direction: column; gap: 0.35rem; }
.shop-card-title {
  font-size: 1rem;
  margin: 0;
  line-height: 1.25;
  /* Long CRM product names must not blow the card apart. */
  overflow-wrap: anywhere;
}

.shop-price { font-family: var(--font-display); font-weight: 650; font-size: 1.05rem; color: var(--ink); margin: 0; }
.shop-price.is-unset { font-family: var(--font-body); font-weight: 500; font-size: 0.9rem; color: var(--ink-faint); }
.shop-price-from { font-family: var(--font-body); font-weight: 400; font-size: 0.82rem; color: var(--ink-faint); }

.shop-card.is-out-of-stock .shop-card-frame { opacity: 0.62; }

/* --- Stock badge --- */

.stock-badge {
  position: absolute;
  top: 0.6rem;
  left: 0.6rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 0.3rem 0.6rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink-soft);
  box-shadow: 0 2px 8px -3px rgba(80, 42, 24, 0.4);
}
/* Availability is carried by the word, not only by the colour — the palette is
   all warm oranges, so hue alone could not distinguish these anyway. */
.stock-badge.is-in-stock { color: #2F6B4F; }
.stock-badge.is-low-stock { color: var(--accent-deep); }
.stock-badge.is-out-of-stock { color: var(--ink-faint); }

/* Static position on the detail page, where there is no image to sit over. */
.product-info .stock-badge { position: static; display: inline-block; box-shadow: none; background: rgba(255,255,255,0.6); }

/* --- Skeletons --- */

.shop-card.is-skeleton { pointer-events: none; }
.skeleton-block { aspect-ratio: 1 / 1; }
.skeleton-block,
.skeleton-line {
  background: linear-gradient(100deg, rgba(230, 196, 174, 0.35) 30%, rgba(255, 255, 255, 0.55) 50%, rgba(230, 196, 174, 0.35) 70%);
  background-size: 220% 100%;
  animation: skeleton-sweep 1.4s ease-in-out infinite;
}
.skeleton-line { height: 0.85rem; border-radius: 6px; margin: 0.55rem 0; }
.skeleton-line.is-short { width: 45%; }

@keyframes skeleton-sweep {
  from { background-position: 180% 0; }
  to { background-position: -80% 0; }
}

/* --- Product detail --- */

.shop-back {
  display: inline-block;
  font-size: 0.9rem;
  margin-bottom: 1.4rem;
  color: var(--accent-deep);
}

.product-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
}
@media (max-width: 820px) { .product-layout { grid-template-columns: 1fr; } }

.shop-gallery-main {
  border-radius: var(--radius);
  overflow: hidden;
  background: linear-gradient(120deg, var(--peach), var(--rose));
  box-shadow: var(--shadow-lift);
}

.shop-thumbs { display: flex; gap: 0.6rem; margin-top: 0.8rem; flex-wrap: wrap; }
.shop-thumb {
  width: 68px;
  padding: 0;
  border: 1px solid rgba(189, 100, 41, 0.2);
  border-radius: 10px;
  overflow: hidden;
  background: none;
  cursor: pointer;
}
.shop-thumb[aria-current="true"] { border-color: var(--accent-strong); box-shadow: 0 0 0 2px rgba(189, 100, 41, 0.25); }

.product-info h1 { font-size: clamp(1.6rem, 3.6vw, 2.3rem); margin-bottom: 0.6rem; overflow-wrap: anywhere; }
.product-info > div { margin-bottom: 0.9rem; }
.product-info .shop-price { font-size: 1.5rem; }
.product-description { color: var(--ink-soft); margin-top: 1.6rem; }
/* pre-line keeps single newlines inside a paragraph — bullet lists and <br>
   breaks from GoHighLevel's descriptions would otherwise collapse onto one
   line, because HTML treats a lone newline as a space. Blank lines are already
   split into separate <p> elements before this. */
.product-description p { margin: 0 0 0.9rem; white-space: pre-line; }
.product-sku { font-size: 0.8rem; color: var(--ink-faint); letter-spacing: 0.04em; margin: 0 0 1rem; }


/* --- Variants --- */

.shop-variant { margin-bottom: 1rem; }
.shop-variant-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 0.5rem;
}
.shop-variant-options { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.shop-variant-option {
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.55rem 1rem;
  min-height: 44px;          /* comfortable touch target */
  border-radius: 999px;
  cursor: pointer;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(189, 100, 41, 0.22);
}
.shop-variant-option[aria-checked="true"] {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  color: var(--white);
}

/* ============================================================
   Reduced motion — kill all movement cleanly
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .blob { animation: none !important; }
  .reveal { opacity: 1; transform: none; transition: none; }
  [data-tilt] { transform: none !important; }
  .hero-3d { transform: none !important; }
  .btn, .btn:hover { transform: none; }
  .shop-card:hover, .shop-card:focus-within { transform: none; }
  .skeleton-block, .skeleton-line { animation: none; }
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ============================================================
   The bag (Phase 3B)
   ============================================================ */

.bag-badge { position: relative; }
.bag-badge-count {
  display: inline-block;
  min-width: 1.35em;
  margin-left: 0.4em;
  padding: 0.05em 0.4em;
  border-radius: 999px;
  background: var(--accent-strong);
  color: var(--white);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* --- Toast. Bottom-centre on mobile so it never sits over the portal bar. --- */
.bag-toast-host {
  position: fixed;
  left: 50%;
  bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 60;
  pointer-events: none;
  width: max-content;
  max-width: 92vw;
}
.bag-toast {
  padding: 0.75rem 1.25rem;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-size: 0.9rem;
  font-weight: 500;
  box-shadow: var(--shadow-lift);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.bag-toast.is-visible { opacity: 1; transform: none; }
.bag-toast.is-error { background: var(--accent-deep); color: var(--white); }

/* --- Quantity stepper. 40px targets: comfortably tappable without being clumsy. --- */
.qty {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.55);
  box-shadow: inset 0 0 0 1px rgba(189, 100, 41, 0.22);
  overflow: hidden;
}
.qty-btn {
  width: 40px;
  height: 40px;
  border: 0;
  background: transparent;
  color: var(--accent-deep);
  font-size: 1.15rem;
  font-weight: 600;
  cursor: pointer;
  line-height: 1;
}
.qty-btn:hover:not(:disabled) { background: rgba(209, 111, 80, 0.12); }
.qty-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.qty-input {
  width: 46px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  text-align: center;
  font-family: var(--font-display);
  font-size: 0.98rem;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  appearance: textfield;
}
.qty-input::-webkit-outer-spin-button,
.qty-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty-input:focus { outline: 2px solid var(--accent-deep); outline-offset: -2px; }

.add-to-bag { width: 100%; justify-content: center; }
.add-to-bag.is-compact { margin: 0 1rem 1rem; width: calc(100% - 2rem); font-size: 0.88rem; padding: 0.6rem 1rem; }
.product-actions { margin: 1.4rem 0 0.8rem; max-width: 320px; }

/* --- Bag page --- */
.bag-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  align-items: start;
}
@media (max-width: 860px) { .bag-layout { grid-template-columns: 1fr; } }

.bag-lines { list-style: none; padding: 0; margin: 0 0 1.2rem; display: grid; gap: 1rem; }
.bag-line {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr) auto;
  gap: 1rem;
  align-items: start;
  padding: 1rem;
}
.bag-line-media {
  width: 84px;
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: linear-gradient(120deg, var(--peach), var(--rose));
}
.bag-line-media img { width: 100%; height: 100%; object-fit: cover; }
.bag-line-media.is-placeholder {
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 650;
  color: var(--accent-deep);
  letter-spacing: 0.06em;
}
.bag-line-body { min-width: 0; }
.bag-line-name { font-size: 1.02rem; margin: 0 0 0.25rem; }
.bag-line-name a { color: var(--ink); text-decoration: none; }
.bag-line-name a:hover { color: var(--accent-deep); text-decoration: underline; }
.bag-line-variant { font-size: 0.85rem; color: var(--ink-faint); margin: 0 0 0.3rem; }
.bag-line-price { font-size: 0.9rem; color: var(--ink-soft); margin: 0 0 0.7rem; }
.bag-line-controls { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }
.bag-remove { font-size: 0.85rem; }
.bag-line-total {
  font-family: var(--font-display);
  font-weight: 650;
  font-size: 1.02rem;
  margin: 0;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
@media (max-width: 520px) {
  .bag-line { grid-template-columns: 64px minmax(0, 1fr); }
  .bag-line-media { width: 64px; }
  /* The line total moves under the controls rather than squeezing the name. */
  .bag-line-total { grid-column: 2; text-align: right; }
}

.bag-summary { position: sticky; top: calc(var(--nav-h) + 1rem); }
.bag-summary h2 { font-size: 1.15rem; margin-bottom: 1rem; }
.bag-summary-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: 0.6rem;
}
.bag-summary-row strong {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.bag-summary-note { font-size: 0.8rem; color: var(--ink-faint); margin: 0.6rem 0 0; }

/* Collect from Faye. A whole-row label so the text is part of the hit area —
   a 16px checkbox on its own is a poor target on a phone. */
.bag-collect {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1rem 0 0;
  padding: 0.7rem 0.8rem;
  border: 1px solid rgba(59, 43, 36, 0.16);
  border-radius: 10px;
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--ink);
}
.bag-collect:hover { border-color: var(--accent-soft); }
.bag-collect input {
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  flex: none;
  accent-color: var(--accent-strong);
  cursor: pointer;
}
.bag-collect:has(input:checked) {
  border-color: var(--accent);
  background: rgba(209, 111, 80, 0.07);
}
.bag-collect:focus-within { outline: 2px solid var(--accent-deep); outline-offset: 2px; }
.bag-checkout { width: 100%; justify-content: center; margin-top: 1rem; }
.bag-continue { display: inline-block; }
.bag-notice { margin-bottom: 1.4rem; }
.bag-notice.is-error { border-left-color: var(--accent-strong); }
.bag-empty { text-align: center; max-width: 520px; margin: 0 auto; }
.bag-empty h1 { font-size: clamp(1.6rem, 3.6vw, 2.2rem); }

.bag-handoff-list { list-style: none; padding: 0; margin: 1.4rem 0; display: grid; gap: 0.6rem; }
.bag-handoff-list li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid rgba(59, 43, 36, 0.08);
  font-size: 0.95rem;
  color: var(--ink-soft);
}
.bag-handoff-list strong { color: var(--ink); font-variant-numeric: tabular-nums; }
/* Test-mode banner. Deliberately loud and deliberately not in the brand
   palette: it must read as scaffolding rather than as part of the design, so
   nobody mistakes a test checkout for a real one. Never shown in live mode. */
.test-mode-banner {
  position: sticky;
  top: 0;
  z-index: 200;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0.5rem 0.75rem;
  padding: 0.55rem 1rem;
  background: #2c2418;
  color: #ffd98a;
  font-family: var(--font-body);
  font-size: 0.85rem;
  text-align: center;
}
.test-mode-banner strong {
  color: #fff;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
}

/* The grand total is the number the customer is agreeing to, so it gets the
   rule above it and the larger type. Subtotal and postage read as workings. */
.bag-handoff-total {
  margin-top: 0.4rem;
  padding-top: 0.7rem;
  border-top: 1px solid rgba(59, 43, 36, 0.16);
  font-size: 1.05rem;
}
.bag-handoff-vat {
  margin: 0.6rem 0 0;
  font-size: 0.85rem;
  color: var(--ink-soft);
}
.bag-handoff-actions { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-top: 1.4rem; }
