/* ==========================================================================
   Refresh Dental — Version 4 · work in progress
   Palette: Navy #263a78 · Light Blue #00a8c8 · White
   Seeded from Version 3's top section; further sections are being built one at\n   a time. Rules for sections not yet on the page are kept ready to use.\n   Type: Fraunces (display) + Karla (body/UI)
   Imagery is faded into sections with mask gradients so it never competes
   with the text. Textures and instrument line-art are inline SVG — no extra
   image requests.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,600;9..144,700&family=Karla:wght@400;500;700&display=swap');

:root {
  --navy: #263a78;
  --navy-mid: #1d2d5e;
  --navy-deep: #16234a;
  --navy-ink: #101a37;
  --cyan: #00a8c8;
  --cyan-deep: #00819c;
  --cyan-pale: #d6f0f6;
  --white: #ffffff;
  --paper: #f7fafc;
  --mist: #edf5f8;
  --line: #dde8ee;
  --text: #3f4c63;
  --muted: #71809a;

  --display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --ui: "Karla", "Helvetica Neue", Arial, sans-serif;

  --container: 1220px;
  --radius: 4px;
  --lift: 0 30px 70px -40px rgba(16, 26, 55, 0.55);

  /* ---- Inline textures ---------------------------------------------------- */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.88' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23g)' opacity='0.06'/%3E%3C/svg%3E");
  --grain-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23g)' opacity='0.17'/%3E%3C/svg%3E");
  /* the logo's four-point sparkle, scattered irregularly and barely there */
  --motif: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='190' height='190'%3E%3Cg fill='%23263a78' fill-opacity='0.032'%3E%3Cpath d='M44 28c.8 5.8 1.8 6.8 7.6 7.6-5.8.8-6.8 1.8-7.6 7.6-.8-5.8-1.8-6.8-7.6-7.6 5.8-.8 6.8-1.8 7.6-7.6z'/%3E%3Cpath d='M148 104c.6 4.3 1.3 5 5.6 5.6-4.3.6-5 1.3-5.6 5.6-.6-4.3-1.3-5-5.6-5.6 4.3-.6 5-1.3 5.6-5.6z'/%3E%3Cpath d='M100 160c.4 3.2 1 3.8 4.2 4.2-3.2.4-3.8 1-4.2 4.2-.4-3.2-1-3.8-4.2-4.2 3.2-.4 3.8-1 4.2-4.2z'/%3E%3C/g%3E%3C/svg%3E");
  --motif-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='190' height='190'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M44 28c.8 5.8 1.8 6.8 7.6 7.6-5.8.8-6.8 1.8-7.6 7.6-.8-5.8-1.8-6.8-7.6-7.6 5.8-.8 6.8-1.8 7.6-7.6z'/%3E%3Cpath d='M148 104c.6 4.3 1.3 5 5.6 5.6-4.3.6-5 1.3-5.6 5.6-.6-4.3-1.3-5-5.6-5.6 4.3-.6 5-1.3 5.6-5.6z'/%3E%3Cpath d='M100 160c.4 3.2 1 3.8 4.2 4.2-3.2.4-3.8 1-4.2 4.2-.4-3.2-1-3.8-4.2-4.2 3.2-.4 3.8-1 4.2-4.2z'/%3E%3C/g%3E%3C/svg%3E");
  /* same sparkle glyph, brighter — used for the animated twinkle layer on title banners */
  --motif-spark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='190' height='190'%3E%3Cg fill='%23ffffff' fill-opacity='0.09'%3E%3Cpath d='M44 28c.8 5.8 1.8 6.8 7.6 7.6-5.8.8-6.8 1.8-7.6 7.6-.8-5.8-1.8-6.8-7.6-7.6 5.8-.8 6.8-1.8 7.6-7.6z'/%3E%3Cpath d='M148 104c.6 4.3 1.3 5 5.6 5.6-4.3.6-5 1.3-5.6 5.6-.6-4.3-1.3-5-5.6-5.6 4.3-.6 5-1.3 5.6-5.6z'/%3E%3Cpath d='M100 160c.4 3.2 1 3.8 4.2 4.2-3.2.4-3.8 1-4.2 4.2-.4-3.2-1-3.8-4.2-4.2 3.2-.4 3.8-1 4.2-4.2z'/%3E%3C/g%3E%3C/svg%3E");
  /* generic reviewer silhouette, standing in until real photos are supplied */
  --avatar-placeholder: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ccircle cx='32' cy='32' r='32' fill='%23d6f0f6'/%3E%3Ccircle cx='32' cy='25' r='12' fill='%23263a78'/%3E%3Cpath d='M10 59c0-14.4 9.8-23 22-23s22 8.6 22 23' fill='%23263a78'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--ui);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.72;
  color: var(--text);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: var(--navy); }
a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: 3px;
  border-radius: 2px;
}

.wrap { max-width: var(--container); margin: 0 auto; padding: 0 40px; }
@media (max-width: 760px) { .wrap { padding: 0 22px; } }

/* Fraunces runs larger per em than Times and takes slight negative tracking
   well at display sizes, so sizes come back down and letter-spacing tightens. */
h1, h2, h3 { margin: 0 0 20px; color: var(--navy-deep); }
h1, h2 { font-family: var(--display); font-weight: 400; line-height: 1.08; letter-spacing: -0.015em; }
h1 { font-size: clamp(2.5rem, 5.2vw, 4.1rem); }
h2 { font-size: clamp(2rem, 3.9vw, 3.1rem); }
h3 { font-family: var(--ui); font-size: 1.2rem; font-weight: 700; letter-spacing: -0.005em; }
p { margin: 0 0 20px; }
.lede { font-size: 1.1rem; color: var(--text); }

/* Eyebrow: a cyan tick plus spaced caps ------------------------------------ */
.kicker {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--cyan-deep);
  margin-bottom: 20px;
}
/* Leading dot + line, drawn as one box so ::after stays free for the
   trailing mirror on centred kickers. */
.kicker::before {
  content: "";
  width: 40px; height: 6px;
  background:
    radial-gradient(circle, var(--cyan) 3px, transparent 3px) left center / 6px 6px no-repeat,
    linear-gradient(var(--cyan), var(--cyan)) right center / 26px 2px no-repeat;
  flex-shrink: 0;
}
.kicker.on-dark { color: var(--cyan); }
.kicker.centred { justify-content: center; }
/* Centred kickers get a mirrored line + dot after the text too, so the
   eyebrow reads dot–line–TEXT–line–dot instead of trailing off on one side. */
.kicker.centred::after {
  content: "";
  width: 40px; height: 6px;
  background:
    linear-gradient(var(--cyan), var(--cyan)) left center / 26px 2px no-repeat,
    radial-gradient(circle, var(--cyan) 3px, transparent 3px) right center / 6px 6px no-repeat;
  flex-shrink: 0;
}

/* Buttons ------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--ui);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 13px 26px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease, transform 0.3s ease;
}
.btn svg { width: 15px; height: 15px; }
.btn--cyan { background: var(--cyan); color: #06282f; }
.btn--cyan:hover { background: var(--cyan-deep); color: #fff; transform: translateY(-2px); }
.band--navy .btn--cyan, .closer-cta .btn--cyan { color: #fff; }
.btn--navy { background: var(--navy); color: #fff; }
.btn--navy:hover { background: var(--navy-deep); transform: translateY(-2px); }
.btn--outline { border-color: rgba(38, 58, 120, 0.35); color: var(--navy); }
.btn--outline:hover { background: var(--navy); border-color: var(--navy); color: #fff; }
.btn--ghost-light { border-color: rgba(255, 255, 255, 0.45); color: #fff; }
.btn--ghost-light:hover { background: #fff; color: var(--navy-deep); border-color: #fff; }

.arrowlink {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--navy);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--cyan);
  transition: gap 0.25s ease, color 0.25s ease;
}
.arrowlink::after { content: "→"; font-size: 0.95rem; line-height: 1; }
.arrowlink:hover { gap: 16px; color: var(--cyan-deep); }
.arrowlink.on-dark { color: #fff; }

/* Header -------------------------------------------------------------------- */
.masthead {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 60;
  transition: background 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease;
  border-bottom: 1px solid transparent;
}
.masthead.solid {
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(12px);
  border-bottom-color: var(--line);
  box-shadow: 0 10px 30px -26px rgba(16, 26, 55, 0.6);
}
.masthead-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 26px;
  padding: 16px 40px;
  max-width: var(--container);
  margin: 0 auto;
}
@media (max-width: 760px) { .masthead-in { padding: 12px 22px; } }

.logo { display: flex; align-items: center; gap: 13px; text-decoration: none; flex-shrink: 0; }
.logo img { height: 50px; width: auto; transition: height 0.3s ease; }
.masthead.solid .logo img { height: 44px; }
/* The supplied logo file has an opaque white background, so the transparent
   mark is used here — white over the hero, brand colours once the bar solidifies. */
.logo-mark { display: flex; align-items: center; flex-shrink: 0; }
.logo-mark .mk-light { display: none; }
.masthead.solid .logo-mark .mk-dark { display: none; }
.masthead.solid .logo-mark .mk-light { display: block; }
.logo-text { display: flex; flex-direction: column; line-height: 1.15; }
.logo-name {
  font-family: var(--display);
  font-size: 1.3rem;
  color: #fff;
  letter-spacing: 0.01em;
  transition: color 0.35s ease;
}
.logo-tag {
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
  transition: color 0.35s ease;
}
.masthead.solid .logo-name { color: var(--navy-deep); }
.masthead.solid .logo-tag { color: var(--cyan-deep); }

.nav > ul { display: flex; align-items: center; gap: 34px; list-style: none; margin: 0; padding: 0; }
.nav a, .nav .dropdown-label {
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  color: rgba(255, 255, 255, 0.9);
  padding-bottom: 4px;
  border-bottom: 1px solid transparent;
  transition: color 0.3s ease, border-color 0.3s ease;
}
.nav a:hover { border-bottom-color: var(--cyan); }
.masthead.solid .nav a, .masthead.solid .nav .dropdown-label { color: var(--navy); }

/* Services dropdown ------------------------------------------------------ */
.has-dropdown { position: relative; }
/* An invisible, absolutely-positioned bridge over the gap between the label
   and the dropdown — hovering it still satisfies :hover on the li, so the
   menu doesn't close while the cursor crosses the space to reach it. Being
   absolutely positioned, it takes no part in the li's layout box, so unlike
   a padding-based bridge it can't skew this item's height (and therefore its
   vertical centering) relative to its siblings. */
.has-dropdown::after { content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 14px; }
/* Deliberately left as plain inline (matching the sibling <a> tags) rather
   than inline-flex — browsers measure a taller box for inline-flex text than
   for inline text at the same font size, which threw this item's vertical
   centering off relative to its siblings. The caret is an inline-block
   pseudo-element positioned with margin instead of flex gap. */
.dropdown-label { cursor: default; outline-offset: 4px; }
.dropdown-label::after {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  margin-left: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
}
.dropdown { display: none; list-style: none; margin: 0; padding: 0; }
.has-dropdown:hover .dropdown,
.has-dropdown:focus-within .dropdown { display: block; }
.dropdown {
  position: absolute;
  top: 100%; left: 50%;
  transform: translateX(-50%);
  margin-top: 14px;
  padding: 12px;
  min-width: 280px;
  background: #fff;
  border-radius: var(--radius);
  box-shadow: var(--lift);
}
.dropdown a {
  display: block;
  color: var(--navy);
  font-size: 0.88rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: none;
  padding: 13px 16px;
  border-radius: 10px;
  border-bottom: none;
  white-space: nowrap;
}
.dropdown a:hover { background: var(--mist); color: var(--cyan-deep); border-bottom-color: transparent; }

.head-actions { display: flex; align-items: center; gap: 14px; }
.callbtn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  font-size: 0.84rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 12px 22px;
  border-radius: var(--radius);
  background: var(--cyan);
  color: #06282f;
  white-space: nowrap;
  transition: background 0.3s ease, color 0.3s ease;
}
.callbtn:hover { background: #fff; color: var(--navy-deep); }
.callbtn svg { width: 15px; height: 15px; flex-shrink: 0; }

.bookbtn {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  font-size: 0.84rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 12px 20px;
  border-radius: var(--radius);
  background: var(--navy-deep);
  color: #fff;
  white-space: nowrap;
  transition: background 0.3s ease, color 0.3s ease;
}
.bookbtn:hover { background: var(--navy-ink); }

.burger {
  display: none;
  width: 46px; height: 46px;
  align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: var(--radius);
  color: #fff;
  cursor: pointer;
}
.masthead.solid .burger { border-color: var(--line); color: var(--navy); }
.burger svg { width: 20px; height: 20px; }

@media (max-width: 1080px) {
  .nav {
    display: none;
    position: absolute;
    top: 100%; left: 0; right: 0;
    background: #fff;
    border-bottom: 1px solid var(--line);
    box-shadow: var(--lift);
  }
  .nav.open { display: block; }
  .nav > ul { flex-direction: column; align-items: stretch; gap: 0; padding: 10px 40px 22px; }
  /* the desktop hover-bridge would otherwise sit on top of the always-open
     mobile sublist and intercept taps on its first link */
  .has-dropdown::after { display: none; }
  .nav a { display: block; color: var(--navy); padding: 14px 0; border-bottom: 1px solid var(--line); }
  .nav .dropdown-label { display: flex; color: var(--navy); padding: 14px 0; border-bottom: 1px solid var(--line); }
  .dropdown {
    display: block;
    position: static;
    transform: none;
    margin-top: 0;
    padding: 0 0 4px 16px;
    min-width: 0;
    background: transparent;
    box-shadow: none;
  }
  .dropdown a { font-size: 0.76rem; text-transform: uppercase; padding: 13px 0; border-radius: 0; border-bottom: 1px solid var(--line); }
  .burger { display: inline-flex; }
}
@media (max-width: 560px) {
  .logo-tag { display: none; }
  .logo-name { font-size: 1.1rem; }
  .callbtn .num { display: none; }
  .callbtn { padding: 12px 15px; }
  .bookbtn { display: none; }
}

/* Hero ----------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 92vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: var(--navy-ink);
}
.hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  will-change: transform;
}
/* subject sits right of centre, so the crop favours that side and keeps the
   open left-hand side of the room under the copy */
.hero-bg img { width: 100%; height: 100%; object-fit: cover; object-position: 72% 25%; }
/* Navy veil: a flat, faint wash rather than the directional gradient V4 uses,
   so the photograph reads clearly across the whole hero. */
.hero-veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(16,26,55,0.65);
}
.hero-in { position: relative; z-index: 4; width: 100%; padding: 168px 0 110px; }
.hero-copy { max-width: 720px; }
.hero h1 { color: #fff; }
.hero h1 .ital { font-style: italic; color: var(--cyan-pale); }
.hero p { color: #c8d3ea; font-size: 1.12rem; max-width: 52ch; }
.hero-cta { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 34px; }

/* Faint oversized instrument art, drifting behind the hero copy */
.hero-art { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.hero-art .tool { position: absolute; color: var(--cyan); opacity: 0.16; animation: sway 18s ease-in-out infinite; }
.hero-art svg { width: 100%; height: auto; display: block; }
.tool-a { width: 74px; top: 18%; left: 4%; animation-duration: 16s; }
.tool-b { width: 52px; top: 66%; left: 10%; animation-duration: 21s; animation-delay: -6s; }
.tool-c { width: 88px; top: 24%; right: 12%; opacity: 0.1; animation-duration: 24s; animation-delay: -11s; }
.tool-d { width: 44px; top: 78%; right: 26%; opacity: 0.12; animation-duration: 19s; animation-delay: -3s; }
@keyframes sway {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(-4deg); }
  50% { transform: translate3d(0, -26px, 0) rotate(6deg); }
}
@media (max-width: 900px) {
  .hero { min-height: 0; }
  .hero-in { padding: 132px 0 84px; }
  .tool-c, .tool-d { display: none; }
}

/* Scroll cue */
.scroll-cue {
  position: absolute;
  left: 50%; bottom: 30px;
  transform: translateX(-50%);
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
.scroll-cue span.rail { display: block; width: 1px; height: 44px; background: linear-gradient(to bottom, rgba(255,255,255,0.5), transparent); position: relative; overflow: hidden; }
.scroll-cue span.rail::after {
  content: ""; position: absolute; top: -44px; left: 0;
  width: 1px; height: 44px; background: var(--cyan);
  animation: railrun 2.6s ease-in-out infinite;
}
@keyframes railrun { 0% { top: -44px; } 60%, 100% { top: 44px; } }
@media (max-width: 900px) { .scroll-cue { display: none; } }

/* Bands ---------------------------------------------------------------------- */
.band { position: relative; padding: 118px 0; background-color: var(--white); background-image: var(--grain); background-size: 150px 150px; }
.band--tint { background-color: var(--mist); background-image: var(--motif), var(--grain); background-size: 190px 190px, 150px 150px; }
.band--paper { padding-top: 60px; padding-bottom: 60px; background-color: var(--paper); background-image: var(--motif), var(--grain); background-size: 190px 190px, 150px 150px; }

/* Same four instrument icons as the hero, reused very faint as background
   texture. Never given a z-index, so it sits behind .band > .wrap's z-index:2
   automatically — only visible in the open background, never over a card. */
.svc-bg-icons { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.svc-bg-icons .tool { position: absolute; color: var(--navy); opacity: 0.1; animation: sway 20s ease-in-out infinite; }
.svc-bg-icons svg { width: 100%; height: auto; display: block; }
.svc-icon-a { width: 62px; top: 7%; left: 5%; animation-duration: 17s; }
.svc-icon-b { width: 46px; top: 11%; right: 8%; opacity: 0.08; animation-duration: 22s; animation-delay: -7s; }
.svc-icon-c { width: 72px; bottom: 9%; left: 10%; opacity: 0.09; animation-duration: 19s; animation-delay: -4s; }
.svc-icon-d { width: 42px; bottom: 13%; right: 6%; animation-duration: 24s; animation-delay: -12s; }
@media (max-width: 900px) {
  .svc-icon-b, .svc-icon-c { display: none; }
}
.band--navy {
  background-color: var(--navy-deep);
  color: #c5d0e8;
}
.band--navy h2, .band--navy h3 { color: #fff; }
.band--navy p { color: #b9c5e0; }
@media (max-width: 760px) { .band { padding: 74px 0; } }

.band > .wrap { position: relative; z-index: 2; }

/* Logo watermark ------------------------------------------------------------- */
.wm { overflow: hidden; }
.wm::after {
  content: "";
  position: absolute;
  z-index: 0;
  pointer-events: none;
  background: url("../images/web/logo-mark.png") no-repeat center / contain;
  opacity: 0.045;
}
.wm--r::after { width: 520px; height: 520px; right: -140px; top: 50%; translate: 0 -50%; }
.wm--l::after { width: 440px; height: 440px; left: -130px; bottom: -110px; }
.wm--tl::after { width: 440px; height: 440px; left: -130px; top: -110px; }

/* Watermark drifts: a slow full rotation with a separate, faster breathe.
   These use the individual `rotate` and `scale` properties rather than the
   `transform` shorthand — two animations on `transform` would overwrite one
   another, whereas these are independent properties and compose cleanly. It
   also frees the centred variant to hold its offset via `translate`, so no
   second set of keyframes is needed. The two cycle lengths are deliberately
   not multiples of each other, so the pairing never visibly repeats. */
@keyframes wmSpin {
  to { rotate: 360deg; }
}
@keyframes wmPulse {
  0%, 100% { scale: 1; }
  50% { scale: 1.18; }
}
@keyframes twinkle {
  0%, 100% { opacity: 0; }
  50% { opacity: 1; }
}
.wm::after {
  transform-origin: center;
  /* The mark sits at very low opacity, so a small, very slow move reads as no
     movement at all. This amplitude and pace are the point where it becomes
     perceptible without drawing attention. */
  animation: wmSpin 90s linear infinite, wmPulse 9s ease-in-out infinite;
  will-change: rotate, scale;
  opacity: 0.07;
}
.band--navy.wm::after { background-image: url("../images/web/logo-mark-white.png"); opacity: 0.06; }
@media (max-width: 900px) { .wm::after { width: 300px; height: 300px; } }

/* One-off: enlarged and centred instead of tucked into a corner, so the
   mark reads as a big, faint watermark spanning the section rather than a
   small corner accent. Compound selector for extra specificity, so it
   still wins over the 900px-and-below rule above regardless of source
   order. */
.wm.wm--full::after {
  width: min(85%, 900px);
  height: min(85%, 900px);
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  animation: wmPulse 9s ease-in-out infinite;
}

/* Opt-in: the watermark (and, on sections that have one, the ghost image)
   slide in from off-viewport like the .slide-group pair, and lead it — they
   move first, the pair follows a beat later (see the transition-delay on
   .slide-left/.slide-right below). Same one-shot trigger as the pair,
   offset purely through delay: see the comment in script.js. Both variants
   slide from the left, matching where the mark's corner sits; only wired up
   for --tl/--l since --r already spends `translate` centring the mark
   vertically. Not scoped under .band--navy: its watermark uses a different
   resting opacity that this would need to account for, and no navy section
   uses this yet. */
.wm-slide.wm--tl::after, .wm-slide.wm--l::after {
  opacity: 0;
  translate: -100vw 0;
  transition: translate 1.1s cubic-bezier(0.22, 1, 0.36, 1), opacity 1.1s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: translate;
}
.wm-slide.in.wm--tl::after, .wm-slide.in.wm--l::after { opacity: 0.07; translate: none; }

.wm-slide .ghost-img.behind-text {
  opacity: 0;
  translate: 100vw 0;
  transition: translate 1.1s cubic-bezier(0.22, 1, 0.36, 1), opacity 1.1s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: translate;
}
.wm-slide.in .ghost-img.behind-text { opacity: 0.1; translate: none; }

@media (max-width: 940px) {
  .wm-slide.wm--tl::after, .wm-slide.wm--l::after, .wm-slide .ghost-img.behind-text { transition-duration: 0.8s; }
}

/* Section imagery faded in with a mask — never sits under the words ---------- */
.ghost-img {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  opacity: 0.16;
  -webkit-mask-image: linear-gradient(to left, #000 20%, transparent 96%);
  mask-image: linear-gradient(to left, #000 20%, transparent 96%);
}
.ghost-img img { width: 100%; height: 100%; object-fit: cover; }
.ghost-img--r {
    right: 0;
    top: 0;
    bottom: 0;
    width: 40%;
}
.ghost-img--l {
  left: 0; top: 0; bottom: 0; width: 46%;
  -webkit-mask-image: linear-gradient(to right, #000 8%, transparent 78%);
  mask-image: linear-gradient(to right, #000 8%, transparent 78%);
}
/* Faded backdrop sitting alongside the copy: lower opacity, inset from the
   section edges, and masked so all four edges dissolve into the page.

   The stops matter. With the default farthest-corner sizing centred at 50/50,
   the mid-points of the edges fall at 1/√2 ≈ 70.7% along the gradient, and the
   corners at 100%. Landing fully transparent at 64% therefore clears every
   edge and corner. Earlier versions used explicit radii wider than the box,
   which left 20–55% alpha at the edges and showed as a hard rectangle.
   A radial fade needs no direction, so it is shared by both anchor variants. */
.ghost-img.behind-text {
  opacity: 0.1;
  width: 38%;
  /* nudged outward; the right offset is negative so it drifts past the section
     edge, which the radial fade absorbs without showing a cut */
  top: 10%;
  bottom: 0%;
  right: -6%;
  /* Centre sits below the middle and the falloff band is tighter, so density
     carries further down before dropping away. The transparent stop stays
     inside the nearest edge's normalised distance (the bottom, at ~58%) so no
     edge can leave a residue. */
  -webkit-mask-image: radial-gradient(ellipse at 50% 55%, rgba(0, 0, 0, 0.97) 0%, rgba(0, 0, 0, 0.85) 34%, rgba(0, 0, 0, 0) 56%);
  mask-image: radial-gradient(ellipse at 50% 55%, rgba(0, 0, 0, 0.97) 0%, rgba(0, 0, 0, 0.85) 34%, rgba(0, 0, 0, 0) 56%);
}
.band--navy .ghost-img { opacity: 0.2; mix-blend-mode: luminosity; }
/* Darker on the left, blending into the standard navy-deep well before the
   section's right edge, so most of the width still reads as gradient rather
   than settling into flat colour early. */
.showcase.band--navy { background: linear-gradient(to right, var(--navy-ink) 0%, var(--navy-deep) 55%); }
/* Smaller than the standard ghost-img--r footprint — this section's cards
   already fill most of the width, so the backdrop only needs to read as a
   corner accent, not a full-height column. */
.showcase .ghost-img--l {
    width: 65%;
    top: 0;
    bottom: 0;
    height: 100%;
}
/* Shift the cover-crop down so more of the lower part of the photo shows,
   rather than cropping in evenly from top and bottom. */
.showcase .ghost-img img { object-position: center 85%; }
@media (max-width: 900px) {
  .ghost-img { display: none; }
  /* Dental Anxiety's background photo specifically — shown on mobile as a
     full-width strip across the top of the section instead of the desktop
     side column, fading down into the stacked text below it. */
  .band--navy .ghost-img--r {
    display: block;
    left: 0;
    right: 0;
    top: 0;
    bottom: auto;
    width: auto;
    height: 320px;
    -webkit-mask-image: linear-gradient(to bottom, #000 20%, transparent 92%);
    mask-image: linear-gradient(to bottom, #000 20%, transparent 92%);
  }
}

/* CTA bar ---------------------------------------------------------------------
   Deliberately slim, so it punctuates the page between sections rather than
   reading as another section of its own. */
.ctabar {
  background-color: var(--navy-deep);
  background-image: var(--motif-light), var(--grain-dark);
  background-size: 190px 190px, 150px 150px;
}
.ctabar-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 30px;
  padding-top: 26px;
  padding-bottom: 26px;
  flex-wrap: wrap;
}
.ctabar-facts {
  display: flex;
  align-items: center;
  gap: 34px;
  margin: 0;
  padding: 0;
  list-style: none;
  flex-wrap: wrap;
}
.ctabar-facts li { display: flex; align-items: center; gap: 11px; }
.ctabar-facts svg { width: 19px; height: 19px; color: var(--cyan); flex-shrink: 0; }
.ctabar-facts a {
  color: #fff;
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 500;
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s ease;
}
.ctabar-facts a:hover { border-bottom-color: var(--cyan); }

.ctabar-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.ctabar-actions .btn { padding: 14px 26px; }

@media (max-width: 860px) {
  .ctabar-in { flex-direction: column; align-items: flex-start; gap: 22px; }
  .ctabar-facts { gap: 14px; flex-direction: column; align-items: flex-start; }
}
@media (max-width: 460px) {
  .ctabar-actions { width: 100%; }
  .ctabar-actions .btn { flex: 1 1 100%; }
}

/* Split ---------------------------------------------------------------------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 82px; align-items: center; }
.split--top { align-items: start; }
.split--wide-text { grid-template-columns: 1.12fr 0.88fr; }
.split--wide-text-r { grid-template-columns: 0.4fr 0.5fr; }
.split--media-first .split-media { order: -1; }
@media (max-width: 940px) {
  .split, .split--wide-text { grid-template-columns: 1fr; gap: 40px; }
  .split-media { order: -1; }
  /* Once the split collapses to one column, .pic's box goes nearly
     full-width while its height (tuned for the narrower desktop column)
     stays short — a very wide, short crop window that, against a portrait
     photo, pushes most of the subject (often the head) out of frame.
     Capping the width back down keeps the crop box closer to the
     proportions it was actually designed for. */
  .split-media .pic { max-width: 340px; margin: 0 auto; }
  .pic img { height: 480px; }
}
.split-head { max-width: 100ch; margin-bottom: 58px; }
.split-head.centred { margin-left: auto; margin-right: auto; text-align: center; }

/* Oversized, very faint duplicate of the heading sitting behind it — an echo
   rather than a label. The wrap only exists to give the ghost text a box the
   same height as the real heading to centre against; it deliberately has no
   overflow:hidden, since .split-head's 62ch text column is far narrower than
   this is meant to read at — it's left to spill past that column into the
   open band on either side. body's overflow-x:hidden (not this) is what
   keeps that from ever causing a horizontal scrollbar on narrow screens. */
.ghost-head-wrap { position: relative; }
.ghost-head-wrap h2 { position: relative; z-index: 1; }
.ghost-heading {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.6rem, 11vw, 8rem);
  letter-spacing: -0.01em;
  color: var(--navy-deep);
  opacity: 0.045;
  z-index: 0;
  pointer-events: none;
  user-select: none;
}
.band--navy .ghost-heading { color: #fff; opacity: 0.06; }

/* Framed picture with a cyan rule offset behind it. Corners swoop on the
   diagonal — .pic (right-aligned image) rounds top-left/bottom-right,
   .pic--flip (left-aligned image) rounds the opposite pair, top-right/
   bottom-left — so the two alternate rather than mirroring identically. */
.pic { position: relative; }
.pic img {
    width: 100%;
    height: clamp(380px, 44vw, 560px);
    object-fit: cover;
    object-position: center;
    border-radius: 120px 26px 120px 26px;
}
.pic--flip img { border-radius: 26px 120px 26px 120px; }
/* Costs section's photo specifically — shifted down further than the shared
   default so more of the chair below the subjects is visible. */
.pic--costs img { object-position: center 45%; }
/* Portrait photos framed in .pic's short, wide box lose the top of the
   subject's head to the default centred crop — shift the crop window up. */
.pic--top img { object-position: center 15%; }
.pic::before {
  content: "";
  position: absolute;
  top: 26px; bottom: -26px; left: -26px; right: 26px;
  border: 1px solid var(--cyan);
  opacity: 0.5;
  border-radius: 120px 26px 120px 26px;
  z-index: -1;
}
.pic--flip::before { left: 26px; right: -26px; border-radius: 26px 120px 26px 120px; }
@media (max-width: 940px) { .pic::before { display: none; } }
@media (max-width: 640px) {
  .pic img, .pic--flip img { border-radius: 60px 22px 60px 22px; }
  .pic--flip img { border-radius: 22px 60px 22px 60px; }
}

/* Services — photography, not icons ------------------------------------------ */
.services { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; }
@media (max-width: 960px) { .services { grid-template-columns: 1fr; max-width: 520px; margin: 0 auto; } }

.service {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.45s ease, border-color 0.45s ease;
}
.service:hover { transform: translateY(-8px); box-shadow: var(--lift); border-color: transparent; }

.service-figure { position: relative; overflow: hidden; height: 268px; }
.service-figure img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* photographs sit under a navy veil until hovered, then bloom into colour */
  filter: saturate(0.55) contrast(1.04);
  transform: scale(1.02);
  transition: transform 1s cubic-bezier(0.22, 1, 0.36, 1), filter 0.7s ease;
}
.service:hover .service-figure img { transform: scale(1.09); filter: saturate(1) contrast(1); }
.service-figure::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(22,35,74,0.86) 0%, rgba(22,35,74,0.32) 52%, rgba(22,35,74,0.12) 100%);
  transition: opacity 0.6s ease;
}
.service:hover .service-figure::after { opacity: 0.72; }
.service-figure h3 {
  position: absolute;
  left: 28px; right: 28px; bottom: 22px;
  z-index: 2;
  margin: 0;
  color: #fff;
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.66rem;
  letter-spacing: 0;
}
.service-body { padding: 28px 28px 30px; display: flex; flex-direction: column; gap: 20px; flex-grow: 1; }
.service-body p { color: var(--muted); font-size: 0.97rem; margin: 0; flex-grow: 1; }

/* ═══════════════════════════════════════════════════════════════════════════
   SERVICES — two layout options left, built side by side for comparison.
   Once one is chosen, delete the other section and its block here, plus the
   .variant-tag rule. Everything is namespaced .svcB / .svcC.
   ═══════════════════════════════════════════════════════════════════════════ */

/* temporary build marker, remove with the losing variants */
.variant-tag {
  display: inline-block;
  font-family: var(--ui);
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
  color: #8a6d1f; background: #fdf3d6; border: 1px dashed #d9c48a;
  border-radius: 999px; padding: 5px 14px; margin-bottom: 20px;
}

/* shared card chrome ------------------------------------------------------- */
.svc {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 20px;
  overflow: hidden;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.45s ease, border-color 0.45s ease;
}
.svc:hover { transform: translateY(-6px); box-shadow: var(--lift); border-color: transparent; }
.svc-fig { position: relative; overflow: hidden; }
.svc-fig img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(0.62) contrast(1.03);
  transform: scale(1.02);
  transition: transform 1s cubic-bezier(0.22, 1, 0.36, 1), filter 0.7s ease;
}
.svc:hover .svc-fig img { transform: scale(1.08); filter: saturate(1) contrast(1); }
.svc-body { padding: 26px 28px 28px; display: flex; flex-direction: column; gap: 16px; flex-grow: 1; }
.svc-body h3 { margin: 0; font-family: var(--display); font-weight: 600; font-size: 1.45rem; color: var(--navy-deep); }
.svc-body p { margin: 0; color: var(--muted); font-size: 0.96rem; flex-grow: 1; }

/* B — wide stacked rows, each its own white card since the band is tinted -- */
.svcB-list { display: flex; flex-direction: column; gap: 24px; }
.svcB-row {
  display: grid;
  grid-template-columns: 0.34fr 1fr;
  gap: 40px;
  align-items: center;
  background: var(--white);
  border-radius: 24px;
  padding: 32px 36px;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.45s ease;
}
.svcB-row:hover { transform: translateY(-6px); box-shadow: var(--lift); }
.svcB-row .svc-fig { border-radius: 16px; overflow: hidden; }
.svcB-row .svc-fig img { height: clamp(200px, 20vw, 260px); border-radius: 16px; }
.svcB-row:hover .svc-fig img { transform: scale(1.06); filter: saturate(1) contrast(1); }
.svcB-copy h3 { margin: 0 0 12px; font-family: var(--display); font-weight: 600; font-size: 1.6rem; color: var(--navy-deep); }
.svcB-copy p { margin: 0 0 18px; color: var(--muted); }
@media (max-width: 900px) {
  .svcB-row { grid-template-columns: 1fr; gap: 20px; padding: 26px 24px; }
}

/* C — staggered trio -------------------------------------------------------- */
.svcC-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; align-items: start; }
.svcC-grid .svc:nth-child(1) .svc-fig { height: 300px; }
.svcC-grid .svc:nth-child(2) .svc-fig { height: 372px; }
.svcC-grid .svc:nth-child(3) .svc-fig { height: 300px; }
.svcC-grid .svc:nth-child(2) { margin-top: 68px; }
@media (max-width: 960px) {
  .svcC-grid { grid-template-columns: 1fr; max-width: 520px; margin: 0 auto; }
  .svcC-grid .svc:nth-child(2) { margin-top: 0; }
  .svcC-grid .svc .svc-fig { height: 260px; }
}

/* Services showcase — photo grid, loosely modelled on the "SEE OUR SEIKO
   Lenses" section at waynesmithoptometrist.co.za. Heading/intro reused
   verbatim from "What We Treat" above (its .split-head.centred styling
   handles the head here too). Each card is an image (10px radius) with a
   body below it in normal flow, same width as the image — but pulled up
   with a negative margin so only the label overlaps into the photo, with
   the gap that follows it (not the label itself) landing on the photo's
   bottom edge and the description sitting fully below. One outlined CTA
   centred below the row. ------------------------------------------------ */
.showcase-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; align-items: stretch; }
.showcase-card {
  position: relative;
  display: flex;
  flex-direction: column;
  text-decoration: none;
}
.showcase-media { position: relative; display: block; height: 420px; overflow: hidden; border-radius: 10px; }
.showcase-media img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(0.85);
  transform: scale(1.02);
  transition: transform 0.8s cubic-bezier(0.22, 1, 0.36, 1), filter 0.6s ease;
}
.showcase-card:hover .showcase-media img { transform: scale(1.08); filter: saturate(1); }
/* Light navy tint so the three photos read as one consistent set rather than
   whatever colour temperature each one happened to be shot in. */
.showcase-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(16, 26, 55, 0.22);
  pointer-events: none;
}
/* Body sits below the image in normal flow, then a negative top margin
   pulls it up just far enough that the label lands inside the photo —
   sized so the gap that follows the label (not the label itself) is what
   lines up with the photo's bottom edge, putting the description cleanly
   below it. Same background as before (a light translucent white) works
   in both zones: over the photo it reads as a scrim, over the plain
   section background beneath it it's indistinguishable from white. */
.showcase-body {
  position: relative;
  z-index: 2;
  flex: 1;
  width: 95%;
  margin: -50px auto 0;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  padding: 26px 24px 24px;
  background: rgba(255, 255, 255, 0.85);
  /* the shadow lives here, not on .showcase-card, so its shape actually
     follows this panel's own rounded/inset edges — on the card it was a
     plain full-width rectangle with square corners, visibly mismatched
     against (and clipped square behind) this narrower rounded panel.
     Kept soft/ambient (low alpha, wide blur, gentle spread) rather than a
     tight, dark, hard-edged shadow so it reads as lift, not a smudge. */
  box-shadow: 0 5px 36px -15px rgba(16, 26, 55, 0.22);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.showcase-label { font-family: var(--display); font-weight: 500; font-size: 1.25rem; line-height: 1.2; letter-spacing: 0.5px; text-transform: capitalize; color: var(--navy-deep); }
/* a flex item would otherwise shrink to its own content width instead of
   wrapping across the panel like the label/button do */
.showcase-desc { display: block; align-self: stretch; font-family: var(--ui); font-size: 0.86rem; line-height: 1.6; color: var(--text); margin: -4px 0 0; }
.showcase-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  align-self: stretch;
  margin-top: auto;
  padding-bottom: 6px;
  font-family: var(--ui);
  font-size: 1rem;
  font-weight: 700;
  color: var(--cyan-deep);
  text-decoration: none;
  border-bottom: 1px solid var(--cyan);
  transition: gap 0.25s ease, color 0.3s ease;
}
.showcase-btn::after { content: "→"; font-size: 0.95rem; line-height: 1; }
.showcase-card:hover .showcase-btn { gap: 14px; color: var(--navy-deep); }

/* Showcase entrance — each card's photo slides in from the left, one after
   another (a stagger, not at once), driven by the same .slide-group/.in
   one-shot mechanism the hero-adjacent slide pairs use (see script.js and
   the .slide-left/.slide-right comment above) rather than .rise, since
   .rise only ever fades up, never sideways.
   The whole white panel below it — not just the description text inside —
   then drops down into place afterwards, as one unit. Its delay starts
   only once that card's own photo has fully finished sliding in (photo's
   delay + duration), rather than overlapping the two, so the downward
   drop reads as its own distinct motion instead of blurring into the
   photo still arriving from the left. translateY is layered on top of
   .showcase-body's existing negative margin-top (its resting position),
   not instead of it — transforms don't affect layout, so the margin still
   places it correctly once the transform clears. */
.showcase-grid.slide-group .showcase-media {
  opacity: 0;
  transform: translateX(-70px);
  transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}
.showcase-grid.slide-group .showcase-card:nth-child(1) .showcase-media { transition-delay: 0s; }
.showcase-grid.slide-group .showcase-card:nth-child(2) .showcase-media { transition-delay: 0.15s; }
.showcase-grid.slide-group .showcase-card:nth-child(3) .showcase-media { transition-delay: 0.3s; }
.showcase-grid.slide-group.in .showcase-media { opacity: 1; transform: none; }

.showcase-grid.slide-group .showcase-body {
  opacity: 0;
  transform: translateY(-36px);
  transition: opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1), transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
.showcase-grid.slide-group .showcase-card:nth-child(1) .showcase-body { transition-delay: 0.8s; }
.showcase-grid.slide-group .showcase-card:nth-child(2) .showcase-body { transition-delay: 0.95s; }
.showcase-grid.slide-group .showcase-card:nth-child(3) .showcase-body { transition-delay: 1.1s; }
.showcase-grid.slide-group.in .showcase-body { opacity: 1; transform: none; }

@media (max-width: 960px) {
  .showcase-grid { grid-template-columns: 1fr; max-width: 420px; margin: 0 auto; gap: 24px; }
  .showcase-media { height: 320px; }
}

/* Instrument frieze — line art that draws itself in --------------------------- */
.frieze {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(28px, 6vw, 78px);
  padding: 6px 0 2px;
}
.frieze .tool-draw { width: clamp(48px, 5.6vw, 66px); color: var(--cyan); opacity: 0.95; }
/* every path carries pathLength="1", so one dash value draws them all evenly */
.frieze .tool-draw path, .frieze .tool-draw circle, .frieze .tool-draw ellipse, .frieze .tool-draw rect { stroke-dasharray: 1; stroke-dashoffset: 1; }
.frieze.in .tool-draw path, .frieze.in .tool-draw circle, .frieze.in .tool-draw ellipse, .frieze.in .tool-draw rect { animation: draw 1.9s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.frieze.in .tool-draw:nth-child(2) path, .frieze.in .tool-draw:nth-child(2) circle, .frieze.in .tool-draw:nth-child(2) ellipse, .frieze.in .tool-draw:nth-child(2) rect { animation-delay: 0.18s; }
.frieze.in .tool-draw:nth-child(3) path, .frieze.in .tool-draw:nth-child(3) circle, .frieze.in .tool-draw:nth-child(3) ellipse, .frieze.in .tool-draw:nth-child(3) rect { animation-delay: 0.36s; }
.frieze.in .tool-draw:nth-child(4) path, .frieze.in .tool-draw:nth-child(4) circle, .frieze.in .tool-draw:nth-child(4) ellipse, .frieze.in .tool-draw:nth-child(4) rect { animation-delay: 0.54s; }
.frieze.in .tool-draw:nth-child(5) path, .frieze.in .tool-draw:nth-child(5) circle, .frieze.in .tool-draw:nth-child(5) ellipse, .frieze.in .tool-draw:nth-child(5) rect { animation-delay: 0.72s; }
@keyframes draw { to { stroke-dashoffset: 0; } }

/* Reviews --------------------------------------------------------------------- */
.rating-head { text-align: center; margin-bottom: 58px; }
.rating-row { display: inline-flex; align-items: center; gap: 16px; flex-wrap: wrap; justify-content: center; }
.rating-figure { font-family: var(--display); font-size: 3.4rem; line-height: 1; color: var(--navy-deep); }
.rating-meta { font-size: 0.9rem; color: var(--muted); }
.rating-meta a { color: var(--navy); font-weight: 600; }

/* Reviews carousel -----------------------------------------------------------
   Built on scroll-snap, so touch swipe, trackpad and keyboard all work without
   JS; the buttons and dots simply drive the same scroll position. */
.carousel { position: relative; }
.carousel-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 90px) / 3);
  gap: 45px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Left padding makes room for the avatar badge hanging off each card's
     bottom-left corner, so the first card's badge isn't clipped. It's only
     paired with the small -4px margin (not a matching -34px) because on an
     auto-width box a negative margin-left shifts the whole box left rather
     than cancelling the padding — a larger negative value here pushed the
     track past .wrap's own gutter and into .wm's overflow:hidden, clipping
     the first badge. The trade-off is the first card sits ~30px right of
     the heading above it, which reads fine for a carousel.
     That padding alone isn't enough, though: .quote's scroll-snap-align
     snaps the CARD's own edge flush with the scrollport edge, which
     silently auto-scrolls straight past this padding on load (scrollLeft
     lands at 30px, not 0) and clips the badge anyway. .quote's matching
     scroll-margin-left is what actually reserves this space in the snap
     calculation — the two values need to stay equal.
     Setting overflow-x also forces the used overflow-y to "auto" (a CSS
     overflow-box rule — you can't mix an auto axis with a visible one), so
     bottom padding gets the same treatment: enough room that the badge
     never actually overflows the scroll box, otherwise it'd be clipped
     top-to-bottom instead of just scrolling sideways. Vertical padding
     doesn't have the horizontal shifting problem, so it's paired with its
     usual -8px margin. */
  padding: 4px 4px 30px 34px;
  margin: -4px -4px -8px -4px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.carousel-track::-webkit-scrollbar { display: none; }
.carousel-track:focus-visible { outline: 3px solid var(--cyan); outline-offset: 4px; }
@media (max-width: 1000px) { .carousel-track { grid-auto-columns: calc((100% - 45px) / 2); } }
@media (max-width: 680px) { .carousel-track { grid-auto-columns: 100%; } }

.carousel-ui { display: flex; align-items: center; justify-content: center; gap: 22px; margin-top: 42px; }
.c-btn {
  width: 48px; height: 48px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--navy);
  cursor: pointer;
  transition: background 0.3s ease, border-color 0.3s ease, color 0.3s ease, opacity 0.3s ease;
}
.c-btn:hover:not(:disabled) { background: var(--navy); border-color: var(--navy); color: #fff; }
.c-btn:disabled { opacity: 0.3; cursor: default; }
.c-btn svg { width: 19px; height: 19px; }

.c-dots { display: flex; align-items: center; gap: 10px; }
.c-dot {
  width: 9px; height: 9px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line);
  cursor: pointer;
  transition: background 0.3s ease, width 0.3s ease;
}
.c-dot[aria-current="true"] { background: var(--cyan); width: 26px; border-radius: 999px; }

.quote {
  scroll-snap-align: start;
  /* Matches .carousel-track's 34px left padding — without this, snapping
     aligns .quote's own edge flush with the scrollport, scrolling straight
     past that padding and clipping the avatar badge that hangs off the
     bottom-left corner. */
  scroll-margin-left: 34px;
  margin: 0;
  padding: 25px 25px 15px;
  background: var(--white);
  border: 1px solid var(--line);
  /* top-left / bottom-right rounded more than the other two corners */
  border-radius: 28px var(--radius) 28px var(--radius);
  position: relative;
  transition: box-shadow 0.4s ease, transform 0.4s ease;
}
.quote:hover { box-shadow: var(--lift); transform: translateY(-4px); }
.quote::before {
  content: "";
  position: absolute;
  top: 0; left: 30px; right: 30px;
  height: 2px;
  background: var(--cyan);
  opacity: 0.85;
}
/* Placeholder reviewer photo — centred exactly on the card's bottom-left
   corner, half hanging off the edge like a pinned badge. */
.quote-avatar {
  position: absolute;
  left: 0;
  bottom: 0;
  transform: translate(-30%, 10%);
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background-image: var(--avatar-placeholder);
  background-size: cover;
  background-position: center;
  border: 3px solid var(--white);
  box-shadow: 0 8px 20px -8px rgba(16, 26, 55, 0.45);
  z-index: 2;
}
.quote p { font-size: 1rem; color: var(--text); margin: 0 0 15px; }
/* cards share a row height, so the attribution is pinned to the bottom
   rather than floating wherever the quote happens to end */
.quote { display: flex; flex-direction: column; }
/* stars stacked below the name rather than beside it, so the footer is now
   a column, not a row — .stars still carries its own margin-bottom (see
   the generic rule further down) meant for stand-alone use elsewhere, so
   it's zeroed out here */
.quote footer { display: flex; flex-direction: column; align-items: flex-start; gap: 0px; margin-top: auto; margin-bottom: -5px; }
/* stacked below the name, the stars now sit in the same lower-left
   territory the avatar badge occupies, so they need the same clearance
   cite gets below */
.quote footer .stars { margin-bottom: 5px; margin-left: 24px; margin-top: -2px; }
/* Cleared past the avatar badge, which is absolutely positioned off the
   card's own padding box (so it ignores .quote's 25px padding-left and
   sits right at the corner) — without this the badge overlaps the first
   letter or two of the name. */
.quote cite { font-style: normal; font-weight: 700; font-size: 0.92rem; color: var(--navy-deep); margin-left: 24px; }
.quote .via { display: inline-flex; align-items: center; gap: 7px; margin-bottom: 14px; font-size: 0.74rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.quote .via svg { width: 14px; height: 14px; }

/* Areas served ----------------------------------------------------------------- */
.suburbs { display: flex; flex-wrap: wrap; gap: 12px; margin: 28px 0 0; padding: 0; list-style: none; }
.suburbs li {
  font-size: 0.86rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  color: var(--navy);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 9px 20px;
}
.mapbox { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--white); }
.mapbox iframe { display: block; width: 100%; height: clamp(320px, 34vw, 430px); border: 0; }

/* Anxiety pull ------------------------------------------------------------------ */
.pull {
  font-family: var(--display);
  font-size: clamp(1.7rem, 3.2vw, 2.5rem);
  line-height: 1.24;
  color: #fff;
  margin: 0;
  max-width: 20ch;
}
.pull span { color: var(--cyan); font-style: italic; }

/* FAQ ---------------------------------------------------------------------------- */
.faq { max-width: 900px; }
.faq details { border-top: 1px solid var(--line); padding: 26px 0; }
.faq details:last-of-type { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: 22px;
  cursor: pointer; list-style: none;
  font-family: var(--display);
  font-size: 1.5rem;
  color: var(--navy-deep);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  flex-shrink: 0;
  width: 30px; height: 30px;
  border: 1px solid var(--cyan);
  border-radius: 50%;
  background:
    linear-gradient(var(--cyan), var(--cyan)) center / 11px 1px no-repeat,
    linear-gradient(var(--cyan), var(--cyan)) center / 1px 11px no-repeat;
  transition: transform 0.35s ease, background-color 0.35s ease;
}
.faq details[open] summary::after { transform: rotate(135deg); }
.faq p { margin: 16px 0 0; max-width: 76ch; color: var(--muted); }

/* Long-form inner-page copy (About, service pages, legal pages) ------------------- */
.prose { max-width: 74ch; }
.prose .lede { font-family: var(--display); font-size: 1.3rem; line-height: 1.5; color: var(--navy-deep); margin-bottom: 44px; }
.prose h2 { font-size: clamp(1.5rem, 2.6vw, 2rem); margin: 64px 0 18px; }
.prose h2:first-of-type { margin-top: 0; }
.prose h3 { margin: 0 0 12px; color: var(--navy-deep); }
.prose p { max-width: 74ch; }
.prose p + h3 { margin-top: 32px; }
.prose ul, .prose ol { margin: 0 0 20px; padding-left: 22px; }
.prose li { margin-bottom: 8px; }
.prose li:last-child { margin-bottom: 0; }
.prose strong { color: var(--navy-deep); }
/* Inline cross-links between service pages read as part of the sentence, not as
   buttons — an underline is enough, matching a { color: var(--navy) } already set
   globally, just adding the line back since body copy doesn't default to one. */
.prose a { text-decoration: underline; text-decoration-color: var(--cyan); text-underline-offset: 3px; }
.prose a:hover { color: var(--cyan-deep); }

/* Service page layout: a lead image followed by the full article in a main
   column, with a persistent contact sidebar alongside it — pattern modelled
   on njabulorenalcare.co.za's service pages, rebuilt in this site's own
   components (.pic's framed photo, .kicker, .btn). Sidebar sits beside the
   article only; FAQ/CTA bands below return to full width. ------------------- */
.service-layout { display: grid; grid-template-columns: 1fr 320px; gap: 64px; align-items: start; }
.service-main { min-width: 0; }
.pic--lead { margin-bottom: 40px; }
.pic--lead img { height: clamp(300px, 34vw, 460px); }
.service-aside { display: flex; flex-direction: column; gap: 24px; position: sticky; top: 104px; }
.aside-card { background: var(--mist); border: 1px solid var(--line); border-radius: 20px; padding: 30px 28px; }
.aside-card h3 { font-size: 1.15rem; margin: 6px 0 20px; }
/* Used on the merged treatments+contact block: without it, that block's own
   fill sat behind the white nav tiles and contact tiles it contains, reading
   as a box nested inside a box. */
.aside-card--plain { background: none; border: none; padding: 0; }
.aside-group + .aside-group { margin-top: 28px; }
.aside-btn { width: 100%; justify-content: center; margin-top: 4px; }
.aside-nav { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.aside-nav a, .aside-nav span {
  display: block; padding: 13px 16px; border-radius: 12px;
  background: #fff; border: 1px solid var(--line);
  color: var(--navy-deep); font-weight: 600; font-size: 0.94rem;
}
.aside-nav a { text-decoration: none; transition: border-color 0.2s ease, color 0.2s ease; }
.aside-nav a:hover { border-color: var(--cyan); color: var(--cyan-deep); }
.aside-nav span.is-active { background: var(--navy-deep); border-color: var(--navy-deep); color: #fff; }
@media (max-width: 940px) {
  .service-layout { grid-template-columns: 1fr; gap: 40px; }
  .service-aside { position: static; }
}

/* About page's opening banner — a shorter, full-width lead photo (not
   confined to a column like a service page's .pic--lead, and without its
   diagonal frame, since that treatment doesn't suit a wide banner crop). */
.about-lead { width: 100%; height: 400px; border-radius: 20px; overflow: hidden; margin-bottom: 48px; }
.about-lead img { width: 100%; height: 100%; object-fit: cover; object-position: center 20%; }
@media (max-width: 640px) { .about-lead { height: 260px; } }

/* A row-of-3-then-2 card grid for a set of short value statements (About's
   "Why Choose..." section). Flexbox rather than CSS grid: with wrap +
   justify-content:center, a leftover last row of two centres itself for
   free, instead of hugging the grid's left edge. */
.value-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 28px; }
.value-card {
  flex: 1 1 300px; max-width: calc(33.333% - 19px);
  background: var(--mist); border: 1px solid var(--line); border-radius: 20px;
  padding: 28px 26px;
}
.value-card h3 { font-size: 1.15rem; margin: 0 0 12px; }
.value-card p { margin: 0; color: var(--muted); font-size: 0.95rem; }
@media (max-width: 900px) { .value-card { max-width: calc(50% - 14px); } }
@media (max-width: 640px) { .value-card { max-width: 100%; } }

/* A prominent sub-heading within flowing copy — content headings read in
   the display serif sitewide (h1/h2 already do); plain h3 defaults to the
   UI sans face for compact labels, which looked out of place used as a
   heading on the Contact page. */
.subhead { font-family: var(--display); font-weight: 600; font-size: 1.5rem; letter-spacing: -0.01em; }

/* Simple enquiry form (sidebar + Contact page). Posts to the Worker's
   /PHPFORMS/contact-form handler via js/ContactUs.js (reCAPTCHA v3 +
   SendGrid) — see templates/ContactUs.template.js in the launch kit. ------ */
.mini-form { display: flex; flex-direction: column; gap: 12px; }
.mini-form input, .mini-form textarea {
  /* 16px minimum — anything smaller makes iOS Safari zoom the page on focus. */
  width: 100%; font: inherit; font-size: 1rem; color: var(--navy-deep);
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 14px;
}
.mini-form textarea { resize: vertical; min-height: 110px; }
.mini-form input::placeholder, .mini-form textarea::placeholder { color: var(--muted); }
.mini-form input:focus, .mini-form textarea:focus { outline: none; border-color: var(--cyan); }
.mini-form button { margin-top: 4px; }

/* Contact detail "blocks" — an icon tile per contact method. The whole tile
   is a link, but deliberately left un-.btn-like (border + white fill, no
   colour fill) so it reads as information to scan rather than a CTA. ----- */
.contact-blocks { display: flex; flex-direction: column; gap: 12px; }
.contact-blocks.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; max-width: 640px; margin: 0 auto; }
.contact-block {
  display: flex; align-items: center; gap: 16px;
  padding: 18px 20px; border: 1px solid var(--line); border-radius: 16px;
  background: var(--white); text-decoration: none; color: inherit;
  transition: border-color 0.2s ease, transform 0.2s ease;
}
.contact-block:hover { border-color: var(--cyan); transform: translateY(-2px); }
.contact-block svg { flex: none; width: 22px; height: 22px; color: var(--cyan-deep); }
.contact-block .cb-label { display: block; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-bottom: 2px; }
.contact-block .cb-value { display: block; font-weight: 600; color: var(--navy-deep); }
@media (max-width: 640px) { .contact-blocks.grid { grid-template-columns: 1fr; } }

/* Footer legal links — a third item in the base row alongside the copyright line,
   the same flex-wrap row absorbing it rather than a whole new layout. */
.foot-legal { display: flex; gap: 18px; flex-wrap: wrap; }
.foot-legal a:hover { color: #fff; }

/* Closing CTA — full-bleed photograph under a navy wash --------------------------- */
.closer { position: relative; overflow: hidden; background: var(--navy-ink); }
.closer-bg { position: absolute; inset: 0; z-index: 0; }
.closer-bg img { width: 100%; height: 100%; object-fit: cover; object-position: center 34%; }
.closer-veil {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(180deg, rgba(16,26,55,0.9) 0%, rgba(16,26,55,0.82) 55%, rgba(16,26,55,0.94) 100%),
    var(--grain-dark);
  background-size: auto, 150px 150px;
}
.closer-in { position: relative; z-index: 2; padding: 128px 0; text-align: center; }
.closer h2 { color: #fff; }
.closer p { color: #c2cee8; max-width: 62ch; margin-left: auto; margin-right: auto; }
.closer p a { color: var(--cyan); text-decoration: underline; }
.closer p a:hover { color: #fff; }
.closer-cta { display: flex; justify-content: center; gap: 16px; flex-wrap: wrap; margin-top: 34px; }
@media (max-width: 760px) { .closer-in { padding: 82px 0; } }

/* Footer ---------------------------------------------------------------------------- */
.foot {
  position: relative;
  overflow: hidden;
  background-color: var(--navy-ink);
  color: #a9b6d4;
  padding: 84px 0 30px;
}
.foot::after {
  content: "";
  position: absolute;
  right: -90px; bottom: -110px;
  width: 400px; height: 400px;
  background: url("../images/web/logo-mark-white.png") no-repeat center / contain;
  opacity: 0.06;
  pointer-events: none;
}
.foot > .wrap { position: relative; z-index: 2; }
.foot-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: 60px; }
@media (max-width: 860px) { .foot-grid { grid-template-columns: 1fr; gap: 40px; } }
.foot-logo { display: inline-flex; align-items: center; gap: 13px; text-decoration: none; margin-bottom: 18px; }
.foot-logo img { height: 52px; width: auto; }
.foot-logo span { font-family: var(--display); font-size: 1.35rem; color: #fff; }
.foot h4 { margin: 0 0 20px; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.22em; text-transform: uppercase; color: var(--cyan); }
.foot a { color: #a9b6d4; text-decoration: none; transition: color 0.25s ease; }
.foot a:hover { color: #fff; }
.foot ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; font-size: 0.95rem; }
.socials { display: flex; gap: 12px; margin-top: 22px; }
.socials a {
  width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 50%;
  transition: border-color 0.3s ease, background 0.3s ease, transform 0.3s ease;
}
.socials a:hover { border-color: var(--cyan); background: rgba(0, 168, 200, 0.16); transform: translateY(-3px); }
.socials svg { width: 17px; height: 17px; }
.foot-base {
  margin-top: 62px; padding-top: 26px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
  font-size: 0.82rem; color: #7e8cae;
}

/* Sticky mobile actions ---------------------------------------------------------------- */
.thumbbar { display: none; position: fixed; left: 0; right: 0; bottom: 0; z-index: 70; background: #fff; border-top: 1px solid var(--line); }
.thumbbar div { display: grid; grid-template-columns: 1fr 1fr; }
.thumbbar a {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 8px; text-decoration: none;
  font-size: 0.76rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase;
}
.thumbbar svg { width: 16px; height: 16px; }
.thumbbar .t-call { color: var(--navy); }
.thumbbar .t-wa { background: var(--cyan); color: #06282f; }
@media (max-width: 700px) {
  .thumbbar { display: block; }
  body { padding-bottom: 58px; }
}

/* Reveal --------------------------------------------------------------------------------- */
.rise { opacity: 0; transform: translateY(26px); transition: opacity 0.85s cubic-bezier(0.22, 1, 0.36, 1), transform 0.85s cubic-bezier(0.22, 1, 0.36, 1); }
.rise.in { opacity: 1; transform: none; }
.rise.d1 { transition-delay: 0.1s; }
.rise.d2 { transition-delay: 0.2s; }
.rise.d3 { transition-delay: 0.3s; }

/* Slide-in pair: copy from one side, media from the other, each entering from
   fully off the browser viewport rather than just past its own container edge.
   translateX is a displacement relative to the element's own resting position,
   so ±100vw clears the viewport regardless of where in the layout the element
   sits: an element on-screen is always within 100vw of either edge, so moving
   it a further 100vw in that direction guarantees it starts off-screen.

   Reveal is one-shot: script.js adds .in the first time .slide-group scrolls
   into view and never removes it, so once the pair has slid in it stays —
   see the matching comment in script.js.

   On sections with a .wm-slide watermark/ghost image, this pair follows
   rather than leads: the base transition-delay below holds it back so the
   background moves first, in both directions, and .d1 layers the existing
   photo/text stagger on top of that shared baseline. */
.slide-left, .slide-right {
  opacity: 0;
  transition: opacity 1.1s cubic-bezier(0.22, 1, 0.36, 1), transform 1.1s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: 0.3s;
  will-change: transform;
}
.slide-left { transform: translateX(-100vw); }
.slide-right { transform: translateX(100vw); }
.slide-group.in .slide-left, .slide-group.in .slide-right { opacity: 1; transform: none; }
.slide-group.in .slide-left.d1, .slide-group.in .slide-right.d1 { transition-delay: 0.45s; }
.slide-group.in .slide-left.d2, .slide-group.in .slide-right.d2 { transition-delay: 0.6s; }
@media (max-width: 940px) {
  /* columns stack on mobile; a full-viewport horizontal travel reads fine at
     phone widths, so this only softens the very largest desktop distances */
  .slide-left, .slide-right { transition-duration: 0.8s; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   V2 VERBATIM STYLING — FAQ is lifted whole from v2/index.html: markup,
   colours, type sizing, spacing, all of it, rather than restated in V4's
   own components. (Costs was ported the same way too, but has since gone
   back to V3's version of the section — V4's own band/split/pic/kicker —
   so only what FAQ still needs is kept here.) Every selector is prefixed
   v2- specifically so it can never collide with (or silently override)
   V4's own .split / .faq / .label-equivalent rules used everywhere else on
   this page. Nothing here is meant to be reused outside FAQ. Fraunces/Karla
   are already loaded for V4, and v2 uses the exact same two families, so
   this reuses V4's --display/--ui rather than redeclaring them. */
.v2-section {
  --v2-ink: var(--navy-deep);
  --v2-sand: var(--cyan);
  --v2-sand-soft: var(--cyan-pale);
  --v2-body-text: var(--text);
  --v2-container: 1200px;
  --v2-grain-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23g)' opacity='0.06'/%3E%3C/svg%3E");

  position: relative;
  padding: 104px 0;
  background-image: var(--v2-grain-soft);
  background-size: 150px 150px;
  color: var(--v2-body-text);
}
@media (max-width: 700px) { .v2-section { padding: 66px 0; } }
.v2-section h1, .v2-section h2, .v2-section h3 {
  font-family: var(--display);
  font-weight: 400;
  color: var(--v2-ink);
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0 0 20px;
}
.v2-section h3 { font-size: 1.35rem; font-weight: 400; }
.v2-section p { margin: 0 0 18px; }

.v2-container { max-width: var(--v2-container); margin: 0 auto; padding: 0 32px; }
@media (max-width: 640px) { .v2-container { padding: 0 22px; } }

.v2-measure { max-width: 60ch; margin: 0 auto; text-align: center; }

.v2-label {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--ui);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--v2-sand);
  margin-bottom: 22px;
}
.v2-label::after { content: ""; height: 1px; flex: 1; background: var(--v2-sand-soft); max-width: 90px; }

.v2-faq { margin: 0 auto; }
.v2-faq details { padding: 24px 0; border-bottom: 1px solid var(--line); }
.v2-faq summary {
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: 1.28rem;
  font-weight: 400;
  color: var(--v2-ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}
.v2-faq summary::-webkit-details-marker { display: none; }
.v2-faq summary::after {
  content: "";
  width: 11px; height: 11px;
  border-right: 1px solid var(--v2-sand);
  border-bottom: 1px solid var(--v2-sand);
  transform: rotate(45deg);
  flex-shrink: 0;
  transition: transform 0.25s ease;
}
.v2-faq details[open] summary::after { transform: rotate(225deg); }
.v2-faq p { margin: 16px 0 0; }

.v2-reveal { opacity: 0; transform: translateY(22px); transition: opacity 0.8s ease, transform 0.8s ease; }
.v2-reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rise, .slide-left, .slide-right { opacity: 1; transform: none; }
  .showcase-media, .showcase-body { opacity: 1; transform: none; }
  .v2-reveal { opacity: 1; transform: none; }
  .wm-slide.wm--tl::after, .wm-slide.wm--l::after { opacity: 0.07; translate: none; }
  .wm-slide .ghost-img.behind-text { opacity: 0.1; translate: none; }
  .hero-art .tool, .svc-bg-icons .tool, .scroll-cue span.rail::after { animation: none; }
  .wm::after { animation: none; rotate: none; scale: none; }
  .stub::before, .stub::after { animation: none; opacity: 0.6; }
  .frieze .tool-draw path, .frieze .tool-draw circle, .frieze .tool-draw ellipse, .frieze .tool-draw rect { stroke-dashoffset: 0; animation: none; }
  .hero-bg { transform: none !important; }
  * { transition-duration: 0.001ms !important; }
}

/* Inner placeholder pages ------------------------------------------------------------------ */
.stub {
  position: relative;
  overflow: hidden;
  background-color: var(--navy-deep);
  background-image: var(--motif-light), var(--grain-dark);
  background-size: 190px 190px, 150px 150px;
  padding: 190px 0 96px;
}
.stub::before, .stub::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--motif-spark);
  background-size: 190px 190px;
  pointer-events: none;
  animation: twinkle 4.4s ease-in-out infinite;
}
.stub::after {
  background-position: 95px 95px;
  background-size: 230px 230px;
  animation-duration: 6.2s;
  animation-delay: -2.4s;
}
.stub .wrap { position: relative; z-index: 2; }
.stub h1 { color: #fff; }
.stub .kicker { color: var(--cyan); }
.stub-body { padding: 96px 0; }
.stub-body p { max-width: 62ch; }
.stub-cta { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 34px; }

/* Stars --------------------------------------------------------------------------- */
.stars { display: inline-flex; gap: 4px; margin-bottom: 18px; }
.stars svg { width: 16px; height: 16px; color: #d9a520; }
.rating-row .stars { margin-bottom: 0; }

/* Avily "designed by" credit (templates/designed-by-avily.html) ------------------- */
.avily-credit .avily-link { text-decoration: none; }
.avily-credit .avily-link:hover { text-decoration: underline; }
.avily-credit img { height: 1em; width: auto; vertical-align: middle; margin: 0 4px; }