/* ============================================================
   Veaivo marketing site
   Standalone: nothing here is shared with the live ../style.css
   Tokens in :root, semantic component classes below.
   ============================================================ */

:root{
  /* Surfaces */
  --page:#ffffff;
  --band:#f6f7f9;
  --band-2:#f0f2f6;
  /* Full-width panels only. A deeper violet tint on the brand hue, so the bands
     read as a deliberate brand surface rather than plain grey, matching the pale
     indigo panels on the Children's Homes IQ site. Small components (chat
     bubbles, chips, table headers) stay on the neutral --band above. */
  --band-panel:#ebe7f8;
  --band-panel-line:#dfdaf3;
  --card:#ffffff;
  --ink-900:#0b0d13;
  --ink-700:#1d2230;
  --ink-500:#4e5666;
  --ink-400:#6b7383;
  --line:#e6e8ee;
  --line-soft:#eef0f4;

  /* One accent, used everywhere interactive */
  --brand:#6c4cf1;
  --brand-strong:#5837e0;
  --brand-tint:#f1edfe;
  --brand-ring:rgba(108,76,241,0.18);
  /* Brand surface, for a violet panel carrying white text. Deep enough to read
     as a surface rather than a large button, so it never competes with --brand
     on the things you can actually click. */
  --brand-deep:#4a29c9;

  /* Supporting signal colours only */
  --good:#12a150;
  --good-tint:#e8f7ee;
  --warn:#e08b00;
  --warn-tint:#fdf3e2;

  /* Dark surfaces */
  --night:#0d0f17;
  --night-2:#161a26;

  /* Full bleed section colours, lifted from the Children's Homes IQ site so the
     two products read as one house style. Used by .band-dark and .band-feat,
     which are what separate one section from the next. */
  --navy:#0B1120;
  --feat:#2B31DA;

  /* Kingswell, the demo school. Its own identity on purpose: the promise on
     every page is that the assistant wears the SCHOOL's colours, so dressing
     the mock school in Veaivo violet quietly argues against us, and a visitor
     cannot tell which purple is whose. Deep navy and gold, the same pair the
     mock school website in the guided demo already uses. */
  --ks:#0f2f4c;
  --ks-strong:#0a2338;
  --ks-gold:#b08b3f;
  --ks-tint:#e9f0f6;

  /* WhatsApp conversation mock. Green is an ACCENT here and nowhere else: it
     appears on the outgoing bubble and the read ticks, which is the only part a
     visitor recognises as WhatsApp. Everything else in the mock, and every other
     element on the page, stays in brand violet or the mock school's navy, or the
     page stops looking like Veaivo. Values taken from the real iOS screens. */
  --wa-paper:#efe7de;
  --wa-out:#d9fdd3;
  --wa-in:#ffffff;
  --wa-tick:#53bdeb;
  --wa-meta:#667781;

  /* Shape */
  --r-sm:8px;
  --r:10px;
  --r-card:16px;
  --r-frame:14px;
  --r-pill:999px;

  /* Elevation, neutral not tinted */
  --sh-sm:0 1px 2px rgba(11,13,19,.05);
  --sh:0 4px 14px -6px rgba(11,13,19,.10), 0 1px 3px rgba(11,13,19,.05);
  --sh-lg:0 32px 64px -24px rgba(11,13,19,.22), 0 8px 20px -12px rgba(11,13,19,.10);
  /* Card lift. Soft and grey rather than dark and tight, so a bordered card
     sits above the page instead of being drawn on it. */
  --sh-card:0 2px 4px rgba(11,13,19,.04), 0 14px 30px -12px rgba(11,13,19,.18);
  /* Product shot bloom. Two offset colours rather than one halo: brand violet
     from the upper right, the deeper indigo from the lower left, so the shot
     sits in a wash of light instead of wearing a symmetrical ring. Same idea
     and the same pairing as the Children's Homes IQ shots, which is where the
     band colours came from too. Sits UNDER --sh-lg in the box-shadow list so
     the real drop shadow still reads on top of it. */
  --glow:58px -42px 112px -38px rgba(108,76,241,.50), -52px 50px 112px -38px rgba(68,76,231,.36);

  --maxw:1200px;
  --gutter:32px;
}

*{box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-top:84px}
body{
  margin:0;
  background:var(--page);
  color:var(--ink-900);
  font-family:"Inter",system-ui,-apple-system,"Segoe UI",sans-serif;
  font-size:16px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  font-feature-settings:"cv11","ss01";
}
img{max-width:100%;display:block}
::selection{background:var(--brand-tint);color:var(--ink-900)}

/* ===== TYPE ===== */
h1,h2,h3,h4{margin:0;font-weight:800;letter-spacing:-0.032em;line-height:1.08;text-wrap:balance}
h1{font-size:clamp(38px,5vw,62px)}
h2{font-size:clamp(30px,3.6vw,46px)}
h3{font-size:clamp(19px,1.6vw,23px);letter-spacing:-0.022em;line-height:1.25}
h4{font-size:15px;font-weight:700;letter-spacing:-0.012em}
p{margin:0 0 14px;max-width:64ch;text-wrap:pretty}
.lede{font-size:clamp(17px,1.35vw,19.5px);line-height:1.55;color:var(--ink-500);max-width:56ch;font-weight:400}
.muted{color:var(--ink-400)}
a{color:inherit}

/* ===== LAYOUT ===== */
.container{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
section{padding:88px 0;position:relative}
section.band{background:var(--band-panel);border-top:1px solid var(--band-panel-line);border-bottom:1px solid var(--band-panel-line)}

/* Strong full bleed bands. These are the only two section colours on the site.
   Inversion is scoped to the section's own heading block ONLY. Setting
   color:#fff on the section itself would cascade into every white card inside
   it and leave white text on white, and would need a reset per card type; this
   way a band can wrap any content without knowing what is in it. */
section.band-dark{background:var(--navy);color:#fff}
section.band-feat{background:var(--feat);color:#fff}
section.band-dark .lede,section.band-feat .lede{color:rgba(255,255,255,.76)}
section.band-dark .caps li,section.band-feat .caps li{color:rgba(255,255,255,.82)}
section.band-dark .caps .ico,section.band-feat .caps .ico{color:#fff}

/* Anything inside a band that paints its own light surface puts the ink back,
   for itself and everything it contains. :where() holds the card list at zero
   specificity, and these rules sit AFTER the inversion above so they win the
   tie on .lede nested inside a card. Without this, copy that sits
   directly on a band is invisible, or card text is, depending which way the
   inversion is written. */
section.band-dark :where(.frame,.live,.card,.col-card,.tier,.faq,.docs,.step-card,.note-band,.mail,.quote,.pack,.tline,.vs-card,.grade,.annot>div),
section.band-feat :where(.frame,.live,.card,.col-card,.tier,.faq,.docs,.step-card,.note-band,.mail,.quote,.pack,.tline,.vs-card,.grade,.annot>div){color:var(--ink-900)}
section.band-dark :where(.frame,.live,.card,.col-card,.tier,.faq,.docs,.step-card,.note-band,.mail,.quote,.pack,.tline,.vs-card,.grade,.annot>div) .lede,
section.band-feat :where(.frame,.live,.card,.col-card,.tier,.faq,.docs,.step-card,.note-band,.mail,.quote,.pack,.tline,.vs-card,.grade,.annot>div) .lede{color:var(--ink-500)}

/* A dark drop shadow is invisible on a dark ground, so every light card sitting
   on a band lost its lift the moment the bands stopped being pale. Restored as
   a hairline light ring, which defines the edge, plus a deeper ambient shadow.
   The ring carries most of the effect on the near black navy, where no amount
   of black shadow would ever show. */
section.band-feat :where(.frame,.live,.card,.col-card,.tier,.faq,.docs,.step-card,.note-band,.mail,.quote,.pack,.tline,.vs-card,.grade,.annot>div){
  box-shadow:0 0 0 1px rgba(255,255,255,.16), 0 26px 54px -20px rgba(0,0,0,.55);
}
section.band-dark :where(.frame,.live,.card,.col-card,.tier,.faq,.docs,.step-card,.note-band,.mail,.quote,.pack,.tline,.vs-card,.grade,.annot>div){
  box-shadow:0 0 0 1px rgba(255,255,255,.12), 0 26px 54px -20px rgba(0,0,0,.65);
}

/* Dot field on every strong band. Drawn as a repeating radial gradient, no
   image file, faded out towards the edges by a mask so it never meets a hard
   boundary. Sits on negative z-index, which paints it above the section's own
   background but below its content; isolation:isolate keeps that contained.
   The dot colour comes from --dot so each band type can set its own: a deeper
   blue on the bright indigo, and the indigo itself on the near black navy, so
   the texture never introduces a third colour. */
section.band-dark,section.band-feat{position:relative;overflow:hidden;isolation:isolate}
section.band-feat{--dots:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22240%22%20height%3D%22240%22%20viewBox%3D%220%200%20240%20240%22%20fill%3D%22%2305073f%22%3E%3Ccircle%20cx%3D%22108.6%22%20cy%3D%22134.3%22%20r%3D%221.28%22%20opacity%3D%220.85%22%2F%3E%3Ccircle%20cx%3D%22221.8%22%20cy%3D%22111.8%22%20r%3D%221.11%22%20opacity%3D%220.58%22%2F%3E%3Ccircle%20cx%3D%2244.3%22%20cy%3D%22122.9%22%20r%3D%221.89%22%20opacity%3D%220.92%22%2F%3E%3Ccircle%20cx%3D%22151.2%22%20cy%3D%22190.3%22%20r%3D%221.98%22%20opacity%3D%220.6%22%2F%3E%3Ccircle%20cx%3D%2222.6%22%20cy%3D%2272.8%22%20r%3D%222.47%22%20opacity%3D%220.56%22%2F%3E%3Ccircle%20cx%3D%2221.8%22%20cy%3D%22194.3%22%20r%3D%221.03%22%20opacity%3D%220.6%22%2F%3E%3Ccircle%20cx%3D%22166.4%22%20cy%3D%2210.1%22%20r%3D%221.71%22%20opacity%3D%220.48%22%2F%3E%3Ccircle%20cx%3D%22235.7%22%20cy%3D%22231.5%22%20r%3D%221.28%22%20opacity%3D%220.65%22%2F%3E%3Ccircle%20cx%3D%22156.9%22%20cy%3D%22147.7%22%20r%3D%221.92%22%20opacity%3D%220.52%22%2F%3E%3Ccircle%20cx%3D%2237.8%22%20cy%3D%223.6%22%20r%3D%221.58%22%20opacity%3D%220.94%22%2F%3E%3Ccircle%20cx%3D%22126.8%22%20cy%3D%2214.3%22%20r%3D%222.57%22%20opacity%3D%220.81%22%2F%3E%3Ccircle%20cx%3D%2245.6%22%20cy%3D%2258.1%22%20r%3D%222.11%22%20opacity%3D%220.77%22%2F%3E%3Ccircle%20cx%3D%227.2%22%20cy%3D%22111.3%22%20r%3D%221.22%22%20opacity%3D%220.47%22%2F%3E%3Ccircle%20cx%3D%22105.7%22%20cy%3D%22202.2%22%20r%3D%221.03%22%20opacity%3D%220.95%22%2F%3E%3Ccircle%20cx%3D%22124.6%22%20cy%3D%22153.7%22%20r%3D%222.12%22%20opacity%3D%220.98%22%2F%3E%3Ccircle%20cx%3D%22109.8%22%20cy%3D%2266.8%22%20r%3D%221.03%22%20opacity%3D%220.8%22%2F%3E%3Ccircle%20cx%3D%22201.7%22%20cy%3D%22169.9%22%20r%3D%221.77%22%20opacity%3D%220.85%22%2F%3E%3Ccircle%20cx%3D%2275.7%22%20cy%3D%2255.1%22%20r%3D%221.51%22%20opacity%3D%221.0%22%2F%3E%3Ccircle%20cx%3D%2269.4%22%20cy%3D%2216.9%22%20r%3D%221.12%22%20opacity%3D%220.75%22%2F%3E%3Ccircle%20cx%3D%22183.9%22%20cy%3D%2296.1%22%20r%3D%222.18%22%20opacity%3D%220.95%22%2F%3E%3Ccircle%20cx%3D%22229.9%22%20cy%3D%22203.4%22%20r%3D%222.18%22%20opacity%3D%220.84%22%2F%3E%3Ccircle%20cx%3D%220.1%22%20cy%3D%2250.3%22%20r%3D%222.27%22%20opacity%3D%220.95%22%2F%3E%3Ccircle%20cx%3D%22235.3%22%20cy%3D%2295.4%22%20r%3D%221.56%22%20opacity%3D%220.83%22%2F%3E%3Ccircle%20cx%3D%2217.5%22%20cy%3D%22151.1%22%20r%3D%222.44%22%20opacity%3D%220.93%22%2F%3E%3Ccircle%20cx%3D%22186.8%22%20cy%3D%2264.7%22%20r%3D%221.67%22%20opacity%3D%220.88%22%2F%3E%3Ccircle%20cx%3D%22231.4%22%20cy%3D%22181.9%22%20r%3D%222.38%22%20opacity%3D%220.77%22%2F%3E%3Ccircle%20cx%3D%22191.3%22%20cy%3D%2242.6%22%20r%3D%222.0%22%20opacity%3D%220.66%22%2F%3E%3Ccircle%20cx%3D%22134.2%22%20cy%3D%22107.4%22%20r%3D%221.93%22%20opacity%3D%220.78%22%2F%3E%3Ccircle%20cx%3D%2245.8%22%20cy%3D%22175.7%22%20r%3D%221.13%22%20opacity%3D%220.8%22%2F%3E%3Ccircle%20cx%3D%2228.0%22%20cy%3D%22101.0%22%20r%3D%222.59%22%20opacity%3D%220.93%22%2F%3E%3Ccircle%20cx%3D%2273.0%22%20cy%3D%22212.4%22%20r%3D%222.17%22%20opacity%3D%220.66%22%2F%3E%3Ccircle%20cx%3D%2250.6%22%20cy%3D%2294.6%22%20r%3D%222.18%22%20opacity%3D%220.77%22%2F%3E%3Ccircle%20cx%3D%2224.1%22%20cy%3D%22237.4%22%20r%3D%221.7%22%20opacity%3D%220.91%22%2F%3E%3Ccircle%20cx%3D%2258.3%22%20cy%3D%22144.3%22%20r%3D%221.13%22%20opacity%3D%220.86%22%2F%3E%3Ccircle%20cx%3D%2289.2%22%20cy%3D%22108.8%22%20r%3D%221.05%22%20opacity%3D%220.78%22%2F%3E%3Ccircle%20cx%3D%22137.9%22%20cy%3D%22208.0%22%20r%3D%221.77%22%20opacity%3D%220.58%22%2F%3E%3Ccircle%20cx%3D%2243.9%22%20cy%3D%2237.0%22%20r%3D%222.12%22%20opacity%3D%220.72%22%2F%3E%3Ccircle%20cx%3D%22177.5%22%20cy%3D%22225.7%22%20r%3D%221.98%22%20opacity%3D%220.96%22%2F%3E%3Ccircle%20cx%3D%2247.2%22%20cy%3D%22228.0%22%20r%3D%221.41%22%20opacity%3D%220.46%22%2F%3E%3Ccircle%20cx%3D%22211.7%22%20cy%3D%22144.8%22%20r%3D%221.48%22%20opacity%3D%220.82%22%2F%3E%3Ccircle%20cx%3D%22101.1%22%20cy%3D%2224.9%22%20r%3D%221.32%22%20opacity%3D%220.54%22%2F%3E%3Ccircle%20cx%3D%22143.2%22%20cy%3D%2270.4%22%20r%3D%222.45%22%20opacity%3D%220.81%22%2F%3E%3C%2Fsvg%3E")}
section.band-dark{--dots:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22240%22%20height%3D%22240%22%20viewBox%3D%220%200%20240%20240%22%20fill%3D%22%234a51ff%22%3E%3Ccircle%20cx%3D%22155.6%22%20cy%3D%22168.3%22%20r%3D%221.36%22%20opacity%3D%220.96%22%2F%3E%3Ccircle%20cx%3D%22229.7%22%20cy%3D%2247.1%22%20r%3D%221.32%22%20opacity%3D%220.76%22%2F%3E%3Ccircle%20cx%3D%2215.7%22%20cy%3D%22197.8%22%20r%3D%221.87%22%20opacity%3D%220.87%22%2F%3E%3Ccircle%20cx%3D%2279.9%22%20cy%3D%2289.4%22%20r%3D%221.59%22%20opacity%3D%220.8%22%2F%3E%3Ccircle%20cx%3D%22195.6%22%20cy%3D%2244.0%22%20r%3D%221.33%22%20opacity%3D%220.83%22%2F%3E%3Ccircle%20cx%3D%22218.3%22%20cy%3D%22117.9%22%20r%3D%221.26%22%20opacity%3D%220.64%22%2F%3E%3Ccircle%20cx%3D%2217.1%22%20cy%3D%22220.3%22%20r%3D%221.83%22%20opacity%3D%220.85%22%2F%3E%3Ccircle%20cx%3D%22137.5%22%20cy%3D%2218.9%22%20r%3D%222.45%22%20opacity%3D%220.98%22%2F%3E%3Ccircle%20cx%3D%22201.3%22%20cy%3D%22186.0%22%20r%3D%221.75%22%20opacity%3D%220.49%22%2F%3E%3Ccircle%20cx%3D%22177.6%22%20cy%3D%22157.8%22%20r%3D%221.95%22%20opacity%3D%220.77%22%2F%3E%3Ccircle%20cx%3D%22238.2%22%20cy%3D%222.9%22%20r%3D%222.17%22%20opacity%3D%220.48%22%2F%3E%3Ccircle%20cx%3D%22233.9%22%20cy%3D%22154.3%22%20r%3D%222.27%22%20opacity%3D%220.52%22%2F%3E%3Ccircle%20cx%3D%2260.7%22%20cy%3D%22147.0%22%20r%3D%222.33%22%20opacity%3D%220.99%22%2F%3E%3Ccircle%20cx%3D%2281.1%22%20cy%3D%22156.1%22%20r%3D%221.87%22%20opacity%3D%220.7%22%2F%3E%3Ccircle%20cx%3D%22169.0%22%20cy%3D%22125.8%22%20r%3D%222.05%22%20opacity%3D%220.52%22%2F%3E%3Ccircle%20cx%3D%2223.7%22%20cy%3D%2294.1%22%20r%3D%222.05%22%20opacity%3D%220.92%22%2F%3E%3Ccircle%20cx%3D%2272.5%22%20cy%3D%22179.9%22%20r%3D%222.5%22%20opacity%3D%220.84%22%2F%3E%3Ccircle%20cx%3D%22223.5%22%20cy%3D%22186.2%22%20r%3D%222.15%22%20opacity%3D%220.98%22%2F%3E%3Ccircle%20cx%3D%22127.3%22%20cy%3D%2240.8%22%20r%3D%221.61%22%20opacity%3D%220.63%22%2F%3E%3Ccircle%20cx%3D%22169.8%22%20cy%3D%2263.6%22%20r%3D%222.59%22%20opacity%3D%220.48%22%2F%3E%3Ccircle%20cx%3D%22187.1%22%20cy%3D%2283.1%22%20r%3D%221.55%22%20opacity%3D%220.86%22%2F%3E%3Ccircle%20cx%3D%22137.8%22%20cy%3D%2299.8%22%20r%3D%222.51%22%20opacity%3D%220.89%22%2F%3E%3Ccircle%20cx%3D%2242.7%22%20cy%3D%2285.8%22%20r%3D%221.3%22%20opacity%3D%220.89%22%2F%3E%3Ccircle%20cx%3D%22123.9%22%20cy%3D%22124.2%22%20r%3D%221.35%22%20opacity%3D%220.74%22%2F%3E%3Ccircle%20cx%3D%2240.8%22%20cy%3D%22183.5%22%20r%3D%221.98%22%20opacity%3D%220.99%22%2F%3E%3Ccircle%20cx%3D%22117.4%22%20cy%3D%2221.9%22%20r%3D%221.36%22%20opacity%3D%220.64%22%2F%3E%3Ccircle%20cx%3D%2281.2%22%20cy%3D%2213.7%22%20r%3D%221.49%22%20opacity%3D%220.61%22%2F%3E%3Ccircle%20cx%3D%22140.6%22%20cy%3D%22217.7%22%20r%3D%221.26%22%20opacity%3D%220.67%22%2F%3E%3Ccircle%20cx%3D%22164.4%22%20cy%3D%220.9%22%20r%3D%221.43%22%20opacity%3D%220.59%22%2F%3E%3Ccircle%20cx%3D%2223.3%22%20cy%3D%22134.9%22%20r%3D%222.33%22%20opacity%3D%220.51%22%2F%3E%3Ccircle%20cx%3D%2298.6%22%20cy%3D%22110.5%22%20r%3D%221.74%22%20opacity%3D%220.47%22%2F%3E%3Ccircle%20cx%3D%22149.0%22%20cy%3D%2254.4%22%20r%3D%221.09%22%20opacity%3D%220.92%22%2F%3E%3Ccircle%20cx%3D%22211.2%22%20cy%3D%2282.8%22%20r%3D%222.25%22%20opacity%3D%220.96%22%2F%3E%3Ccircle%20cx%3D%227.3%22%20cy%3D%22117.8%22%20r%3D%221.18%22%20opacity%3D%220.88%22%2F%3E%3Ccircle%20cx%3D%2274.9%22%20cy%3D%22112.2%22%20r%3D%221.48%22%20opacity%3D%220.88%22%2F%3E%3Ccircle%20cx%3D%22199.5%22%20cy%3D%22104.9%22%20r%3D%221.91%22%20opacity%3D%220.69%22%2F%3E%3Ccircle%20cx%3D%2273.0%22%20cy%3D%2248.8%22%20r%3D%221.99%22%20opacity%3D%220.59%22%2F%3E%3Ccircle%20cx%3D%22171.7%22%20cy%3D%22238.9%22%20r%3D%221.86%22%20opacity%3D%220.91%22%2F%3E%3Ccircle%20cx%3D%22166.0%22%20cy%3D%22216.3%22%20r%3D%222.03%22%20opacity%3D%220.87%22%2F%3E%3Ccircle%20cx%3D%22104.1%22%20cy%3D%2273.5%22%20r%3D%222.55%22%20opacity%3D%220.52%22%2F%3E%3Ccircle%20cx%3D%22225.9%22%20cy%3D%22220.7%22%20r%3D%222.24%22%20opacity%3D%220.98%22%2F%3E%3Ccircle%20cx%3D%22204.2%22%20cy%3D%22144.5%22%20r%3D%221.86%22%20opacity%3D%220.64%22%2F%3E%3C%2Fsvg%3E")}
/* Scattered, not gridded. A repeating radial-gradient is a perfect lattice and
   reads as a matrix; this is an SVG tile of irregularly placed circles with
   varied radius and opacity, laid at two different sizes so the two periods
   rarely line up and the repeat is hard to spot. */
/* One tile, not two. The second layer at 163px carried more than twice the
   density of the first (42 dots in 163 square against 42 in 240 square), so the
   pair came to about 0.0023 dots per pixel and read as static rather than
   texture. Dropping it leaves 0.00073, a little under a third of what was there,
   which is where this was asked to land. The cost is that the repeat is now a
   single period and easier to spot; the mask below hides the edges, and at this
   density the eye stops tracking individual dots anyway. */
section.band-dark::before,section.band-feat::before{
  content:"";position:absolute;inset:0;z-index:-2;pointer-events:none;
  background-image:var(--dots);
  background-size:240px 240px;
  background-position:0 0;
  -webkit-mask-image:radial-gradient(135% 115% at 50% 45%, #000 66%, transparent 99%);
  mask-image:radial-gradient(135% 115% at 50% 45%, #000 66%, transparent 99%);
}

/* The light arc, kept as an accent on a couple of panels rather than every one,
   because a sweep that appears on all of them stops reading as deliberate. */
/* A real arc, not a glow. This is a very large circle whose EDGE sweeps across
   the left of the panel: the gradient is transparent in the middle, brightens
   into a soft band near the rim, then fades again. The previous version was a
   radial blob, which has no edge to see, which is why it read as nothing at all
   on a colour this saturated. */
section.band-sweep::after{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  /* Fixed pixel circle, NOT percentages. These bands vary from ~400px to
     ~2400px tall, and a percentage height turned this into an 8,700px ellipse
     whose rim fell outside the panel entirely, which is why no arc was visible.
     A real circle of known size keeps the rim where it is aimed. */
  left:-620px;top:50%;width:1200px;height:1200px;margin-top:-600px;
  border-radius:50%;
  background:radial-gradient(closest-side,
    rgba(255,255,255,0) 60%,
    rgba(255,255,255,.09) 78%,
    rgba(255,255,255,.30) 91%,
    rgba(255,255,255,.13) 97%,
    rgba(255,255,255,0) 100%);
}

section.tight{padding:52px 0}
/* The eyebrow used to supply the top of every heading block. With all 31 gone
   the headings sat about 44px higher and the sections read top heavy, so some
   of that space is put back deliberately rather than lost by accident. Not all
   of it: the tighter setting is part of the point. */
.head{max-width:720px;margin:0 auto 48px;padding-top:30px;text-align:center}
/* Soft radial lift behind a centred heading on a white section. Uses the band
   indigo rather than a new hue, so it adds depth without adding a colour.
   isolation:isolate keeps the z-index:-1 layer inside .head, so it sits behind
   the text but still above the page background instead of disappearing under
   it. Decorative and deliberately faint: used on two headings, not every one. */
.head.glow{position:relative;isolation:isolate}
.head.glow::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  left:50%;top:46%;transform:translate(-50%,-50%);
  width:min(820px,125%);height:360px;
  background:radial-gradient(50% 50% at 50% 50%,
    rgba(43,49,218,.14) 0%, rgba(43,49,218,.06) 45%, rgba(43,49,218,0) 72%);
}
@media (prefers-reduced-motion:no-preference){
  .head.glow::before{transition:opacity .4s ease}
}
.head.left{margin-left:0;text-align:left}
.head .lede{margin:18px auto 0}
.head.left .lede{margin-left:0}

/* ===== BUTTONS ===== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:12px 20px;border-radius:var(--r);
  font:inherit;font-size:15px;font-weight:600;line-height:1;
  text-decoration:none;border:1px solid transparent;cursor:pointer;
  transition:background .15s ease,border-color .15s ease,transform .12s ease,box-shadow .15s ease;
}
.btn:active{transform:translateY(1px)}
.btn-primary{background:var(--brand);color:#fff;box-shadow:0 1px 2px rgba(11,13,19,.16)}
.btn-primary:hover{background:var(--brand-strong)}
.btn-secondary{background:#fff;color:var(--ink-900);border-color:var(--line)}
.btn-secondary:hover{border-color:#cfd3dc;background:#fcfcfd}
.btn-dark{background:var(--ink-900);color:#fff}
.btn-dark:hover{background:#000}
.btn-ghost{background:transparent;color:var(--brand-strong);padding:12px 6px}
.btn-ghost:hover{color:var(--brand)}
.btn-sm{padding:9px 15px;font-size:14px}
.btn-lg{padding:15px 26px;font-size:16px}
.btn .ico{width:16px;height:16px;flex:none}
.btn:focus-visible,a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:2px solid var(--brand);outline-offset:2px;
}

/* ===== ICONS ===== */
.ico{width:20px;height:20px;display:inline-block;flex:none;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ico-lg{width:24px;height:24px}

/* ===== NAV =====
   No rule under the bar at the top of the page. The hero should read as one
   continuous field from the first pixel, and a hard line directly above the
   headline is what made the top of the page feel cramped. The line fades in
   once the page has scrolled, so content passing under the bar still has an
   edge. Transparent rather than removed, so the nav height never shifts. */
.nav{position:sticky;top:0;z-index:60;background:rgba(255,255,255,.86);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-bottom:1px solid transparent;transition:border-color .18s ease}
.nav.scrolled{border-bottom-color:var(--line-soft)}
/* Open mobile menu always needs the edge: the panel below it is opaque white. */
.nav.open{border-bottom-color:var(--line-soft)}
.nav .inner{max-width:var(--maxw);margin:0 auto;padding:13px var(--gutter);display:flex;align-items:center;gap:34px}
.brand{display:inline-flex;align-items:center;gap:5px;text-decoration:none;font-weight:800;font-size:19px;letter-spacing:-0.03em;color:var(--ink-900)}
/* The mark is a drawn letterform now, not an icon sitting in a violet tile, so
   this box carries no background and no stroke: the SVG brings its own fills.
   The tile still exists, as assets/veaivo-tile.svg, but it is the favicon and
   avatar form only. Beside the wordmark it out-weighs the name. */
.brand-mark{width:28px;height:28px;display:grid;place-items:center;flex:none}
.brand-mark svg{width:28px;height:28px;display:block}
.nav ul{display:flex;gap:26px;list-style:none;margin:0;padding:0;flex:1}
.nav ul a{display:inline-block;font-size:14.5px;font-weight:500;color:var(--ink-500);text-decoration:none}
.nav ul a:hover{color:var(--ink-900)}

/* Current page: bold, and the darker ink with it. Bold on its own is a weak
   signal at 14.5px in mid grey, and colour is what the eye catches first.
   The problem with bolding is that it widens the glyphs themselves, so the
   link's own box grows and every item to its right slides sideways. Padding
   cannot fix that; the box has to stop growing. So each link carries an
   invisible copy of its label already set at weight 700: zero height, hidden,
   not selectable, but it sets the link's width. Every link therefore sits at
   its bold width on every page, and switching the visible weight moves
   nothing.
   It is ::before rather than ::after so the visible text stays the link's last
   line box, which is what the surrounding line aligns its baseline to. As an
   ::after the twin would take over the baseline and drop the whole bar.
   The twin labels live here rather than in the markup because the nav is
   duplicated by hand across seven pages. If a nav label changes, change it
   here too, or that link reserves the wrong width. */
.nav ul a::before,
.nav ul a .nav-lbl::before{
  content:"";display:block;height:0;overflow:hidden;visibility:hidden;
  font-weight:700;white-space:nowrap;pointer-events:none;
}
.nav ul a[href="why-veaivo.html"]::before{content:"Why not general AI"}
.nav ul a[href="features.html"]::before{content:"Features"}
.nav ul a[href="safeguarding.html"]::before{content:"Safeguarding"}
.nav ul a[href="pricing.html"]::before{content:"Pricing"}
.nav ul a[href="trust-centre.html"]::before{content:"Trust"}
/* The WhatsApp link holds the NEW badge as well as its label, so the reserve
   goes on the label span instead of the link. Reserving on the link holds the
   box still but not the badge: the badge follows the label inline, so a label
   that widened under it pushed the badge sideways even though nothing else in
   the bar moved. With the label span carrying its own bold width, the badge
   starts at the same place either way. */
.nav ul a .nav-lbl{display:inline-block}
.nav ul a[href="whatsapp.html"] .nav-lbl::before{content:"WhatsApp"}
.nav ul a[aria-current="page"]{font-weight:700;color:var(--ink-900)}
.nav-actions{display:flex;align-items:center;gap:14px}
.nav-actions .login{font-size:14.5px;font-weight:500;color:var(--ink-500);text-decoration:none}
/* School login also sits inside the nav list, for the folded menu. Hidden here
   so the wide bar shows it once, in the actions, and does not repeat it. It
   therefore does NOT count towards the six items the 1140px breakpoint below is
   measured on. */
.nav ul li.nav-login{display:none}
.nav-actions .login:hover{color:var(--ink-900)}
.burger{display:none;flex-direction:column;gap:5px;background:none;border:0;padding:8px;cursor:pointer}
.burger span{display:block;width:20px;height:2px;background:var(--ink-900);border-radius:2px;transition:transform .2s,opacity .15s}
.nav.open .burger span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav.open .burger span:nth-child(2){opacity:0}
.nav.open .burger span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

/* ===== HERO =====
   The top gap is deliberately large. At 66px the headline started around 160px
   down the page, roughly 90px higher than the reference sites, and a hero that
   begins that close to the nav reads as cramped rather than confident. */
.hero{padding:104px 0 60px}
.hero-grid{display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:center}
.hero h1{margin-bottom:20px}
.hero .lede{margin-bottom:28px}
/* Quiet emphasis for key phrases in the hero lede. The lede sits at --ink-500,
   so highlighted words step up to near black rather than taking a colour. */
.hero .lede strong{color:var(--ink-900);font-weight:600}
.hero-ctas{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:22px}
.hero-notes{display:flex;flex-wrap:wrap;gap:8px 20px;font-size:13.5px;color:var(--ink-400);font-weight:500}
.hero-notes span{display:inline-flex;align-items:center;gap:7px}
.hero-notes .ico{width:15px;height:15px;color:var(--good);stroke-width:2.2}

/* ===== BROWSER FRAME ===== */
/* Cards sitting on a dark band override this box-shadow entirely further up, so
   the bloom applies only where there is a light ground to catch it. */
.frame{background:#fff;border:1px solid var(--line);border-radius:var(--r-frame);box-shadow:var(--sh-lg),var(--glow);overflow:hidden}
.frame-bar{display:flex;align-items:center;gap:10px;padding:10px 14px;background:#fbfbfd;border-bottom:1px solid var(--line-soft)}
.frame-dots{display:flex;gap:6px}
.frame-dots i{width:9px;height:9px;border-radius:var(--r-pill);background:#dfe2e9;display:block}
.frame-url{flex:1;background:#fff;border:1px solid var(--line-soft);border-radius:var(--r-pill);padding:5px 12px;font-size:12px;color:var(--ink-400);display:flex;align-items:center;gap:7px;max-width:340px}
.frame-url .ico{width:12px;height:12px;color:var(--good)}
.frame-body{position:relative;background:#fff}

/* ===== HERO CHAT (static, illustrative) ===== */
.hchat{padding:0}
.hchat-top{display:flex;align-items:center;gap:11px;padding:14px 18px;border-bottom:1px solid var(--line-soft)}
.hchat-top .ava{width:34px;height:34px;border-radius:10px;background:var(--ks);color:#fff;display:grid;place-items:center;font-weight:800;font-size:14px;flex:none}
.hchat-top .who strong{display:block;font-size:14.5px;font-weight:700;letter-spacing:-0.015em}
.hchat-top .who span{font-size:12.5px;color:var(--ink-400);display:inline-flex;align-items:center;gap:6px}
.hchat-top .who span::before{content:"";width:6px;height:6px;border-radius:var(--r-pill);background:var(--good)}
.hchat-body{padding:18px;display:flex;flex-direction:column;gap:10px;min-height:250px}
.msg{max-width:84%;padding:10px 14px;border-radius:14px;font-size:14px;line-height:1.5}
.msg-bot{background:var(--band);color:var(--ink-700);align-self:flex-start;border-bottom-left-radius:5px}
.msg-user{background:var(--ks);color:#fff;align-self:flex-end;border-bottom-right-radius:5px;font-weight:500}
.msg .cite{display:flex;width:fit-content;align-items:center;gap:5px;margin-top:8px;background:#fff;border:1px solid var(--line);border-radius:var(--r-pill);padding:3px 9px;font-size:11.5px;font-weight:600;color:var(--ink-500)}
.msg .cite .ico{width:11px;height:11px;color:var(--ks)}
.hchat-foot{padding:12px 18px;border-top:1px solid var(--line-soft);display:flex;align-items:center;justify-content:space-between;font-size:12px;color:var(--ink-400)}
.hchat-foot .pill{background:var(--band);border-radius:var(--r-pill);padding:4px 10px;font-weight:600}

/* ===== LOGO / PROOF STRIP ===== */
.proof{padding:34px 0;background:var(--navy)}
.proof-title{text-align:center;font-size:12.5px;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:rgba(255,255,255,.56);margin-bottom:22px}
.proof-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:18px}
.proof-item{display:flex;gap:11px;align-items:flex-start;font-size:13.5px;line-height:1.45;color:rgba(255,255,255,.70)}
.proof-item .ico{width:18px;height:18px;color:#fff;margin-top:1px}
.proof-item strong{display:block;color:#fff;font-weight:700;font-size:13.5px;letter-spacing:-0.01em}

/* ============================================================
   GUIDED DEMO  (the Supademo signature component)
   ============================================================ */
.demo-wrap{display:grid;grid-template-columns:330px 1fr;gap:36px;align-items:start}

.rail{position:sticky;top:96px}
.rail-progress{height:4px;background:var(--band-2);border-radius:var(--r-pill);overflow:hidden;margin-bottom:22px}
.rail-progress i{display:block;height:100%;width:25%;background:var(--brand);border-radius:var(--r-pill);transition:width .35s cubic-bezier(.4,0,.2,1)}
.rail ol{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.rail li{position:relative}
.rail button.step{
  width:100%;text-align:left;display:flex;gap:13px;align-items:flex-start;
  background:transparent;border:1px solid transparent;border-radius:var(--r-card);
  padding:13px 15px;cursor:pointer;font:inherit;color:var(--ink-400);
  transition:background .18s,border-color .18s,color .18s;
}
.rail button.step:hover{background:#fff;border-color:var(--line-soft)}
.rail button.step .n{
  width:24px;height:24px;border-radius:var(--r-pill);flex:none;
  display:grid;place-items:center;font-size:12.5px;font-weight:700;
  background:var(--band-2);color:var(--ink-400);transition:background .18s,color .18s;
}
.rail button.step strong{display:block;font-size:15px;font-weight:700;letter-spacing:-0.018em;color:var(--ink-700);margin-bottom:2px}
.rail button.step p{margin:0;font-size:13.5px;line-height:1.45;color:var(--ink-400);max-width:none}
/* The active step. A white card on a near white page needs more than a hairline
   border to read as "you are here", so it gets the brand colour on the border
   plus a soft brand tinted ring. Deliberately not a dark or heavy outline. */
.rail li.on button.step{background:#fff;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-ring),var(--sh)}
.rail li.on button.step .n{background:var(--brand);color:#fff}
.rail li.on button.step strong{color:var(--ink-900)}
.rail li.done button.step .n{background:var(--good-tint);color:var(--good)}
.rail-controls{display:flex;gap:8px;margin-top:22px;align-items:center}
.rail-count{margin-left:auto;font-size:13px;color:var(--ink-400);font-weight:600;font-variant-numeric:tabular-nums}
.icon-btn{width:38px;height:38px;border-radius:var(--r);border:1px solid var(--line);background:#fff;display:grid;place-items:center;cursor:pointer;color:var(--ink-700)}
.icon-btn:hover:not(:disabled){border-color:#cfd3dc}
.icon-btn:disabled{opacity:.4;cursor:default}

/* Stage */
.stage-shell{position:relative}
.stage{position:relative;height:560px;overflow:hidden;background:#fff}

/* Mock school site behind the assistant.
   Scoped to .stage on purpose: a bare .site would also match the page
   footer, which carries class="site".
   Its own visual world on purpose: this is meant to look like a school's
   website, not like Veaivo. Deep navy and a serif wordmark, nothing violet. */
.stage .schoolsite{position:absolute;inset:0;display:flex;flex-direction:column;background:#fff;transition:filter .35s ease,opacity .35s ease}

/* Utility bar */
.ss-util{display:flex;align-items:center;gap:18px;padding:0 22px;height:30px;background:#0f2f4c;color:rgba(255,255,255,.78);font-size:11px;letter-spacing:.01em;flex:none}
.ss-util .sep{opacity:.4}
.ss-util .right{margin-left:auto;display:flex;gap:16px;align-items:center}
.ss-util .right b{font-weight:600;color:#fff}

/* Masthead */
.ss-nav{display:flex;align-items:center;gap:20px;padding:12px 22px;background:#fff;border-bottom:1px solid #e6eaef;flex:none}
.ss-brand{display:flex;align-items:center;gap:10px;flex:none}
.ss-crest{width:32px;height:36px;flex:none}
.ss-word{line-height:1.05}
.ss-word b{display:block;font-family:Georgia,"Times New Roman",serif;font-weight:600;font-size:16px;letter-spacing:.01em;color:#0f2f4c}
.ss-word span{display:block;font-size:8.5px;letter-spacing:.22em;text-transform:uppercase;color:#8996a5;margin-top:2px}
.ss-nav ul{display:flex;gap:15px;list-style:none;margin:0;padding:0;font-size:11.5px;color:#41546b;font-weight:600;letter-spacing:.01em}
.ss-nav ul li.on{color:#0f2f4c;box-shadow:inset 0 -2px 0 #b08b3f;padding-bottom:3px}
.ss-nav .ss-cta{margin-left:auto;background:#0f2f4c;color:#fff;font-size:11px;font-weight:600;padding:8px 13px;border-radius:3px;flex:none}

/* Photographic hero, same image the live site uses.
   The deep bottom padding is what the ask bar sits in: the bar has to land on
   the dark part of the photograph to read as white and lit, so the school's own
   copy stops well short of the bottom edge and leaves that band clear. */
/* The photo and its scrim are separate layers, not one stacked background, so
   the image can be filtered without filtering the words sitting on it: a filter
   on .ss-hero itself would take the headline and buttons with it.

   The picture was reading heavy against the rest of the page, which is mostly
   white and violet. It is lifted and warmed slightly, and the scrim it sits
   under is pulled back from .30/.82 to .16/.62. The scrim cannot go further:
   the white serif headline and the gold eyebrow both sit on it, and the ask bar
   below needs a dark strip to land on. The headline's shadow is deepened to pay
   for what the scrim gave up. */
.ss-hero{
  flex:1;position:relative;display:flex;flex-direction:column;justify-content:flex-end;
  padding:22px 22px 122px;overflow:hidden;isolation:isolate;
  background:#123a5e;
}
.ss-hero::before{
  content:"";position:absolute;inset:0;z-index:-2;pointer-events:none;
  background:url('images/hero-bg.jpg') center 28%/cover no-repeat;
  filter:brightness(1.13) saturate(1.16) contrast(.97);
}
.ss-hero::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,rgba(10,32,54,.16) 0%,rgba(10,32,54,.62) 74%);
}
.ss-hero .ss-eyebrow{font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:#e3c98d;font-weight:700;margin-bottom:8px}
.ss-hero .ss-head{font-family:Georgia,"Times New Roman",serif;font-weight:400;font-size:27px;line-height:1.14;color:#fff;letter-spacing:-0.01em;max-width:17ch;text-shadow:0 1px 3px rgba(4,18,32,.45),0 2px 16px rgba(4,18,32,.5)}
.ss-hero .ss-sub{margin-top:9px;font-size:12.5px;line-height:1.5;color:rgba(255,255,255,.9);max-width:44ch;text-shadow:0 1px 3px rgba(4,18,32,.55)}
.ss-hero .ss-btns{display:flex;gap:9px;margin-top:14px}
.ss-hero .ss-btns span{font-size:11px;font-weight:600;padding:8px 14px;border-radius:3px}
.ss-hero .ss-btns .a{background:#b08b3f;color:#fff}
.ss-hero .ss-btns .b{border:1px solid rgba(255,255,255,.55);color:#fff}

/* Quick links strip, the row every school site has */
.ss-strip{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid #e6eaef;background:#f7f9fb;flex:none}
.ss-strip div{padding:11px 14px;border-right:1px solid #e6eaef;font-size:11px;font-weight:700;color:#0f2f4c}
.ss-strip div:last-child{border-right:0}
.ss-strip div span{display:block;font-weight:500;color:#7c8a99;font-size:10.5px;margin-top:2px}
.ss-strip div i{font-style:normal;color:#b08b3f}

/* The ask bar floats over the photograph, not over the quick links strip */
.stage .schoolsite{padding-bottom:0}

/* The embedded ask bar (what a visitor actually sees).
   `bottom` is set high enough to clear the pale quick links strip: on white the
   bar disappeared into the page, and the whole point of this frame is that the
   one thing Veaivo adds is visible at a glance. */
.askbar{
  position:absolute;left:26px;right:26px;bottom:100px;z-index:3;
  background:#fff;border:1px solid var(--line);border-radius:var(--r-pill);
  box-shadow:0 12px 30px -12px rgba(11,13,19,.20);
  display:flex;align-items:center;gap:12px;padding:11px 14px 11px 16px;
  transition:transform .35s ease,opacity .3s ease;
}
.askbar .ava{width:28px;height:28px;border-radius:8px;background:var(--ks);display:grid;place-items:center;color:#fff;font-weight:800;font-size:12px;flex:none}
.askbar .txt{flex:1;font-size:14px;color:var(--ink-400)}
.askbar .txt b{color:var(--ink-900);font-weight:600}
.askbar .go{width:32px;height:32px;border-radius:var(--r-pill);background:var(--ks);display:grid;place-items:center;flex:none}
.askbar .go .ico{width:15px;height:15px;stroke:#fff}
.stage[data-step="5"] .askbar{opacity:0;transform:translateY(14px)}

/* Chat panel that expands from the ask bar. It sits lower than the bar because
   it needs the height: the bar is raised to land on the dark part of the photo,
   the panel is not, and the panel covers the bar completely once open, so the
   two offsets never have to agree. Step 4 in particular needs every pixel: the
   capture form is a four field stack. */
.chatpanel{
  position:absolute;left:26px;right:26px;bottom:44px;z-index:4;
  background:#fff;border:1px solid var(--line);border-radius:18px;
  box-shadow:var(--sh-lg);overflow:hidden;
  opacity:0;transform:translateY(16px) scale(.985);pointer-events:none;
  transition:opacity .3s ease,transform .35s cubic-bezier(.4,0,.2,1);
}
.stage[data-step="2"] .chatpanel,
.stage[data-step="3"] .chatpanel,
.stage[data-step="4"] .chatpanel{opacity:1;transform:none;pointer-events:auto}
.chatpanel-top{display:flex;align-items:center;gap:10px;padding:12px 16px;border-bottom:1px solid var(--line-soft)}
.chatpanel-top .ava{width:30px;height:30px;border-radius:8px;background:var(--ks);color:#fff;display:grid;place-items:center;font-weight:800;font-size:12px}
.chatpanel-top strong{font-size:14px;font-weight:700;letter-spacing:-0.015em}
.chatpanel-top .lang{margin-left:auto;font-size:11.5px;font-weight:600;color:var(--ink-400);background:var(--band);border-radius:var(--r-pill);padding:4px 10px}
/* The floor is low on purpose. The panel is anchored by its bottom edge, so a
   short conversation makes a short panel and each new message grows it upward,
   the way the real widget behaves. A tall floor left a white void above the
   greeting that read as a rendering fault. */
.chatpanel-body{padding:16px;display:flex;flex-direction:column;gap:10px;min-height:96px}
/* Bubbles arrive in sequence. display, not opacity, so a hidden bubble
   takes no room and the panel grows the way a real chat does. */
.chatpanel .m-user,
.chatpanel .m-think,
.chatpanel .m-answer,
.chatpanel .m-follow,
.chatpanel .m-offer,
.chatpanel .m-form,
.chatpanel .qsug{display:none}
.chatpanel .m-user,
.chatpanel .m-think,
.chatpanel .m-answer,
.chatpanel .m-follow,
.chatpanel .m-offer,
.chatpanel .m-form{animation:fade .32s ease both}
/* The form bubble takes the full width, exactly as .v-enq-bubble does in the
   product: at the normal 84% cap the email field is cramped. */
.chatpanel .m-form{max-width:100%;align-self:stretch}

/* step 2: the question has been sent, the assistant is thinking */
.stage.is-asked[data-step="2"] .chatpanel .m-user,
.stage.is-asked[data-step="2"] .chatpanel .m-think{display:block}

/* step 3: the grounded answer, plus the follow-ups a parent would reach for */
.stage[data-step="3"] .chatpanel .m-user,
.stage[data-step="3"] .chatpanel .m-answer{display:block}
.stage[data-step="3"] .chatpanel .qsug{display:flex}

/* While the answer is still being written, its receipts and the suggested
   follow-ups are not there yet. A citation under half a sentence, or a next
   question offered before there is an answer to follow up, both read as the
   page having rendered out of order. Held on opacity rather than display so
   the panel does not jump a second time when they arrive. */
.chatpanel .m-answer .cite,
.chatpanel .qsug{transition:opacity .3s ease}
.stage.is-writing .chatpanel .m-answer .cite,
.stage.is-writing .chatpanel .qsug{opacity:0}

/* step 4: the question it cannot answer, and the offer to pass it on */
.stage[data-step="4"] .chatpanel .m-user,
.stage[data-step="4"] .chatpanel .m-answer,
.stage[data-step="4"] .chatpanel .m-follow,
.stage[data-step="4"] .chatpanel .m-offer,
.stage[data-step="4"] .chatpanel .m-form{display:block}

/* The conversation scrolls like a real one: newest at the bottom, older
   clipped off the top rather than stretching the panel past the stage.
   Step 4 gets more room because the capture form is a four field stack, and
   without it the parent's own question scrolls out of sight. */
.chatpanel-body{max-height:252px;overflow:hidden;justify-content:flex-end}
.stage[data-step="4"] .chatpanel-body{max-height:386px}

/* Suggested follow-ups */
.qsug{display:flex;gap:7px;flex-wrap:wrap;padding:0 16px 12px}
.qsug button{
  font:inherit;font-size:12px;font-weight:600;color:var(--brand-strong);
  background:var(--brand-tint);border:1px solid rgba(108,76,241,.18);
  border-radius:var(--r-pill);padding:7px 12px;cursor:pointer;line-height:1.2;
}
.qsug button:hover{background:#e8e1fd}

/* The in-widget enquiry form. Field for field, and in the same order, as the
   real one in the product widget: first name, surname, email, then a nature of
   enquiry the assistant has already written from the conversation, with a plain
   Cancel beside the send. One field per row, as in the product, which also
   leaves the right hand side of each input empty for the step tooltip to sit
   over without hiding anything. */
.q-form{display:flex;flex-direction:column;gap:6px}
.q-field{display:flex;flex-direction:column;gap:2px}
.q-field i{font-style:normal;font-size:10.5px;font-weight:700;color:var(--ink-400);letter-spacing:.01em}
.q-input{
  background:#fff;border:1.5px solid var(--line);border-radius:8px;
  padding:6px 9px;font-size:12px;line-height:1.45;color:var(--ink-700);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.q-area{white-space:normal;min-height:32px}
.q-actions{display:flex;align-items:center;gap:10px;margin-top:1px}
.q-send{
  display:inline-flex;align-items:center;gap:6px;background:var(--brand);color:#fff;
  border-radius:10px;padding:8px 13px;font-size:12px;font-weight:700;cursor:pointer;
}
.q-send .ico{width:13px;height:13px}
.q-cancel{font-size:12px;font-weight:600;color:var(--ink-400);cursor:pointer}

/* Once the answer has landed the input sits there with the caret blinking,
   so it reads as a live conversation waiting on you rather than a
   screenshot. The caret element itself is added and removed by app.js;
   :empty cannot drive the hint here because the caret is a child. */
.stage[data-step="3"] .chatpanel-input .box::after,
.stage[data-step="4"] .chatpanel-input .box::after{
  content:"Ask another question";color:var(--ink-400);margin-left:6px;
}
.chatpanel .typing{display:inline-flex;gap:4px;align-items:center}
.chatpanel .typing i{width:6px;height:6px;border-radius:var(--r-pill);background:#b9bfcb;animation:bob 1.3s infinite ease-in-out}
.chatpanel .typing i:nth-child(2){animation-delay:.15s}
.chatpanel .typing i:nth-child(3){animation-delay:.3s}
.stage[data-step="3"] .chatpanel .thinking{display:none}
@keyframes bob{0%,80%,100%{transform:translateY(0);opacity:.45}40%{transform:translateY(-3px);opacity:1}}
.chatpanel-input{display:flex;align-items:center;gap:10px;padding:12px 16px;border-top:1px solid var(--line-soft)}
.chatpanel-input .box{flex:1;font-size:14px;color:var(--ink-900);min-height:20px}
.chatpanel-input .box:empty::before{content:"Ask anything about the school";color:var(--ink-400)}
.chatpanel-input .caret{display:inline-block;width:1.5px;height:16px;background:var(--ks);vertical-align:-3px;margin-left:1px;animation:blink 1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
.chatpanel-input .go{width:30px;height:30px;border-radius:var(--r-pill);background:var(--ks);display:grid;place-items:center;flex:none}
.chatpanel-input .go .ico{width:14px;height:14px;stroke:#fff}
/* The question is typed and the send is what moves the walkthrough on, so the
   button asks for the click rather than the step answering itself. */
.stage.is-typed .chatpanel-input .go{animation:sendpulse 1.9s cubic-bezier(0,0,.2,1) infinite}
@keyframes sendpulse{
  0%{box-shadow:0 0 0 0 rgba(15,47,76,.42)}
  70%{box-shadow:0 0 0 11px rgba(15,47,76,0)}
  100%{box-shadow:0 0 0 0 rgba(15,47,76,0)}
}

/* Dashboard overlay for the final step */
.dashpop{
  position:absolute;inset:0;z-index:5;background:rgba(246,247,249,.72);backdrop-filter:blur(3px);
  display:grid;place-items:center start;padding:26px;
  opacity:0;pointer-events:none;transition:opacity .3s ease;
}
.stage[data-step="5"] .dashpop{opacity:1;pointer-events:auto}
.dashcard{width:100%;max-width:430px;background:#fff;border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--sh-lg);overflow:hidden;transform:translateY(10px);transition:transform .35s cubic-bezier(.4,0,.2,1)}
.stage[data-step="5"] .dashcard{transform:none}
/* Product chrome. The card on its own read as one more panel belonging to the
   school's website; the mark, the account line and the address say plainly
   that the enquiry has arrived somewhere else, in Veaivo. */
.dashcard-app{display:flex;align-items:center;gap:10px;padding:11px 14px;background:var(--night);color:#fff}
/* The one place on the site that uses the TILE rather than the bare mark, and
   it follows the rule rather than breaking it: this is a 24px box mocking the
   product's own chrome, below the 18px floor for the bare letterform, so it
   takes the container form. The tile brings its own corners, hence no radius
   on the box. */
.dashcard-app .brand-mark{width:24px;height:24px}
.dashcard-app .brand-mark svg{width:24px;height:24px}
.dashcard-who{line-height:1.15}
.dashcard-who strong{display:block;font-size:12.5px;font-weight:700;letter-spacing:-0.01em}
.dashcard-who span{display:block;font-size:10.5px;color:rgba(255,255,255,.6);margin-top:1px}
.dashcard-url{margin-left:auto;font-size:10.5px;color:rgba(255,255,255,.62);background:rgba(255,255,255,.09);border-radius:var(--r-pill);padding:3px 9px}
.dashcard-tabs{display:flex;gap:16px;padding:0 14px;border-bottom:1px solid var(--line);font-size:11.5px;font-weight:600;color:var(--ink-400);background:#fff}
.dashcard-tabs span{padding:9px 0}
.dashcard-tabs span.on{color:var(--brand);box-shadow:inset 0 -2px 0 var(--brand)}

.dashcard-top{display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--line-soft);font-size:13.5px;font-weight:700}
.dashcard-top .ico{width:16px;height:16px;color:var(--brand)}
.dashcard-top .new{margin-left:auto;background:var(--good-tint);color:var(--good);font-size:11px;font-weight:700;border-radius:var(--r-pill);padding:3px 9px;text-transform:uppercase;letter-spacing:.05em}
.enq .meta{display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex:none}
.enq .when{font-size:10.5px;color:var(--ink-400);font-weight:600}
.enq{display:flex;gap:12px;padding:13px 16px;border-bottom:1px solid var(--line-soft);align-items:flex-start}
.enq:last-child{border-bottom:0}
.enq .who{width:28px;height:28px;border-radius:var(--r-pill);background:var(--band-2);display:grid;place-items:center;font-size:11px;font-weight:700;color:var(--ink-500);flex:none}
.enq .detail{flex:1;min-width:0}
.enq .detail strong{display:block;font-size:13.5px;font-weight:700;letter-spacing:-0.012em}
.enq .detail span{font-size:12.5px;color:var(--ink-400);display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.enq .tag{font-size:11px;font-weight:700;border-radius:var(--r-pill);padding:3px 9px;background:var(--brand-tint);color:var(--brand-strong);flex:none}
.enq.fresh{background:var(--brand-tint)}

/* Hotspot beacon + tooltip */
.beacon{
  position:absolute;z-index:8;width:30px;height:30px;border-radius:var(--r-pill);
  background:var(--brand);color:#fff;font-size:13px;font-weight:700;
  display:grid;place-items:center;border:0;cursor:pointer;padding:0;
  box-shadow:0 0 0 5px rgba(108,76,241,.20);
  transition:left .45s cubic-bezier(.4,0,.2,1),top .45s cubic-bezier(.4,0,.2,1);
}
.beacon::after{
  content:"";position:absolute;inset:-5px;border-radius:var(--r-pill);
  border:2px solid var(--brand);animation:ping 1.9s cubic-bezier(0,0,.2,1) infinite;
}
@keyframes ping{0%{transform:scale(.9);opacity:.7}70%{transform:scale(1.7);opacity:0}100%{opacity:0}}

/* Violet, not near black. Two reasons beyond standing out. The callout crosses
   opposite backdrops, a dark hero photo on step 1 and the pale frosted dash
   overlay on step 5, and only a mid deep saturated colour reads on both; a pale
   tint would fix the first and vanish on the second. And the mock school is
   navy and gold on purpose, so violet is the one colour that says this card is
   Veaivo talking rather than another panel of Kingswell's website. */
.tip{
  position:absolute;z-index:9;max-width:min(290px,42%);background:var(--brand-deep);color:#fff;
  border-radius:12px;padding:14px 16px;
  /* Raised off the page rather than outlined on it: a tight contact shadow with
     a short spread behind it, reaching only a few pixels. A wide halo or ring
     reads as a box drawn around the callout, which is the thing to avoid.
     Tinted to the card, since a grey shadow under violet reads as dirt. */
  box-shadow:0 1px 2px rgba(28,14,84,.34),
             0 5px 14px -3px rgba(28,14,84,.44);
  transition:left .45s cubic-bezier(.4,0,.2,1),top .45s cubic-bezier(.4,0,.2,1);
}

/* Hotspot and tooltip anchors, per step.
   These are percentages of the stage, set in CSS on purpose: measuring the
   stage in JS collapses both to the corner whenever the box is read before
   it has layout (offscreen, hidden tab, mid font swap). */
.stage[data-step="1"] .beacon{left:3%;top:69.5%} /* top left corner of the ask bar */
.stage[data-step="2"] .beacon{left:1.5%;top:84%} /* beside the input, never over the typed text */
/* Beside the answer itself, not the follow-up chips below it. The step is
   about the answer, so the number has to land on it or a viewer has to work
   out which of the two things below the question is being pointed at. Low in
   the bubble on purpose: the bubble is bottom anchored and grows upward as the
   sentence is written, so its lower half is the only part that holds still. */
.stage[data-step="3"] .beacon{left:1.5%;top:60%}
.stage[data-step="4"] .beacon{left:1.5%;top:72%} /* the send button on the enquiry form */
.stage[data-step="5"] .beacon{left:2%;top:48%}   /* the new enquiry row */
/* Beat two of step 2: the question is typed and the send is waiting to be
   pressed, so the hotspot walks across to sit beside it. */
.stage.is-typed[data-step="2"] .beacon{left:85.5%;top:84%}
.stage[data-step="1"] .tip{left:50%;top:24%}
.stage[data-step="2"] .tip{left:46%;top:14%}
.stage[data-step="3"] .tip{left:52%;top:5%}
/* Sits below the message it is describing, over the empty right hand side of
   the form fields, so it never covers the words or a value. */
.stage[data-step="4"] .tip{left:52%;top:30%}
.stage[data-step="5"] .tip{left:60%;top:20%}
.tip strong{display:block;font-size:14px;font-weight:700;letter-spacing:-0.015em;margin-bottom:5px}
/* Both secondary tones sit higher than they would on near black: white loses
   contrast faster over a saturated colour than over ink, and .72 body over the
   violet fell under the 4.5:1 floor. */
.tip p{margin:0;font-size:13px;line-height:1.5;color:rgba(255,255,255,.8);max-width:none}
.tip .tip-foot{display:flex;align-items:center;gap:10px;margin-top:12px}
.tip .tip-next{background:#fff;color:var(--brand-deep);border:0;border-radius:var(--r-sm);padding:7px 12px;font:inherit;font-size:12.5px;font-weight:700;cursor:pointer}
.tip .tip-next:hover{background:var(--brand-tint)}
.tip .tip-of{font-size:12px;color:rgba(255,255,255,.68);font-weight:600;font-variant-numeric:tabular-nums}

.stage-foot{display:flex;align-items:center;gap:14px;margin-top:16px;font-size:13px;color:var(--ink-400)}
.stage-foot .ico{width:15px;height:15px}
.stage-foot .spacer{flex:1}

/* ===== LIVE ASSISTANT BAND ===== */
.live{border:1px solid var(--line);border-radius:var(--r-card);background:#fff;padding:30px;box-shadow:var(--sh)}
.live-head{display:flex;gap:20px;align-items:flex-start;flex-wrap:wrap;margin-bottom:20px}
.live-head .lede{margin:8px 0 0}
/* No height reserved here on purpose. embed-inline.js inserts its own container
   that permanently holds 60px of flow, and the iframe is absolutely positioned
   and anchored to the bottom of it, so the chat grows UPWARD as an overlay and
   never pushes page content. Reserving anything taller just leaves dead space
   under the bar that nothing will ever fill. */
.live-slot{border-radius:var(--r);padding:4px 0}
.live-hint{font-size:13px;color:var(--ink-400);margin:14px 0 0}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
.chip{background:var(--band);border:1px solid var(--line-soft);border-radius:var(--r-pill);padding:4px 11px;font-size:13px;font-weight:500;color:var(--ink-500)}

/* ===== COMPARISON ===== */
.cols{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-bottom:34px}
.col-card{border:1px solid var(--line);border-radius:var(--r-card);padding:26px;background:#fff}
.col-card.bad{background:var(--band)}
.col-card.good{border-color:var(--brand-ring);box-shadow:0 0 0 3px var(--brand-ring)}
.col-card h3{margin-bottom:4px}
.col-card .sub{font-size:13px;font-weight:600;color:var(--ink-400);margin-bottom:18px}
.col-card ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:13px}
.col-card li{display:flex;gap:11px;font-size:14.5px;line-height:1.5;color:var(--ink-500)}
.col-card li strong{color:var(--ink-900);font-weight:600}
.col-card li .ico{width:17px;height:17px;flex:none;margin-top:2px}
.col-card.bad li .ico{color:#a8b0bd}
.col-card.good li .ico{color:var(--good)}

.table-wrap{border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;background:#fff}
table.cmp{width:100%;border-collapse:collapse;font-size:14.5px}
table.cmp th,table.cmp td{padding:14px 18px;text-align:left;border-bottom:1px solid var(--line-soft)}
table.cmp thead th{background:var(--band);font-size:12.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-400)}
table.cmp thead th.us{color:var(--brand-strong);background:var(--brand-tint)}
table.cmp tbody th{font-weight:600;color:var(--ink-900);width:30%}
table.cmp td.them{color:var(--ink-400)}
table.cmp td.us{color:var(--ink-900);font-weight:600;background:rgba(108,76,241,.035)}
table.cmp tr:last-child th,table.cmp tr:last-child td{border-bottom:0}

/* ===== STEPPER ===== */
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
/* Each step is its own bordered block. The card is a flex column and the meta
   footer takes margin-top:auto, so the "Veaivo / You" lines sit on one shared
   baseline across all four. Left to flow, each footer lands wherever its
   paragraph happens to stop and the row reads as ragged. Grid stretches the
   cards to equal height, which is what makes the pinning line up. */
.step-card{
  display:flex;flex-direction:column;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
  padding:22px;box-shadow:var(--sh-sm);
}
.step-card .n{width:34px;height:34px;border-radius:var(--r-pill);background:var(--brand);color:#fff;display:grid;place-items:center;font-weight:700;font-size:14px;margin-bottom:16px}
.step-card h3{margin-bottom:8px}
.step-card p{font-size:14.5px;color:var(--ink-500);margin-bottom:18px}
.step-card .meta{margin-top:auto;font-size:12.5px;color:var(--ink-400);font-weight:600;border-top:1px solid var(--line-soft);padding-top:12px}
.step-card .meta b{color:var(--ink-900)}
.note-band{margin-top:34px;background:#fff;border:1px solid var(--line);border-radius:var(--r-card);padding:20px 24px;font-size:14.5px;color:var(--ink-500)}
.note-band strong{color:var(--ink-900)}

/* ===== TABS ===== */
.tabs{display:flex;gap:6px;justify-content:center;flex-wrap:wrap;margin-bottom:30px;background:var(--band);padding:5px;border-radius:var(--r-pill);width:fit-content;margin-left:auto;margin-right:auto}
.tab{border:0;background:transparent;font:inherit;font-size:14.5px;font-weight:600;color:var(--ink-500);padding:10px 20px;border-radius:var(--r-pill);cursor:pointer;transition:background .16s,color .16s}
.tab:hover{color:var(--ink-900)}
.tab[aria-selected="true"]{background:#fff;color:var(--ink-900);box-shadow:var(--sh-sm)}
.panel{display:none}
.panel.on{display:block;animation:fade .3s ease}
@keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.panel-grid{display:grid;grid-template-columns:1fr 1fr;gap:26px;align-items:start}
.caps{list-style:none;margin:16px 0 0;padding:0;display:flex;flex-direction:column;gap:11px}
.caps li{display:flex;gap:10px;font-size:14.5px;color:var(--ink-500);line-height:1.45}
.caps li .ico{width:16px;height:16px;color:var(--good);flex:none;margin-top:3px;stroke-width:2.4}
.qa{background:#fff;border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;box-shadow:var(--sh)}
.qa-head{padding:12px 18px;background:var(--band);border-bottom:1px solid var(--line-soft);font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-400)}
.qa-body{padding:18px}
.qa-q{font-size:15px;font-weight:700;letter-spacing:-0.015em;margin-bottom:14px}
.qa-a{font-size:14.5px;color:var(--ink-500);margin:0}
.qa-a em{font-style:normal;font-weight:600;color:var(--ink-900)}

/* ===== ANALYTICS ===== */
.dash{background:#fff}
.dash-top{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:18px 22px;border-bottom:1px solid var(--line-soft);flex-wrap:wrap}
.dash-top .school{font-size:16px;font-weight:800;letter-spacing:-0.02em}
.dash-top .when{font-size:12.5px;color:var(--ink-400)}
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line-soft)}
.kpi{background:#fff;padding:20px 22px}
.kpi .k{font-size:12.5px;color:var(--ink-400);font-weight:600;margin-bottom:8px}
.kpi .v{font-size:32px;font-weight:800;letter-spacing:-0.035em;line-height:1;font-variant-numeric:tabular-nums}
.kpi .d{font-size:12.5px;font-weight:600;color:var(--good);margin-top:7px;display:inline-flex;align-items:center;gap:5px}
.kpi .d.flat{color:var(--ink-400)}
.dash-panels{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line-soft);border-top:1px solid var(--line-soft)}
.dpanel{background:#fff;padding:20px 22px}
.dpanel h4{margin-bottom:16px;color:var(--ink-900)}
.bars{display:flex;flex-direction:column;gap:11px}
.bar-row{display:grid;grid-template-columns:1fr 96px 42px;align-items:center;gap:12px;font-size:13.5px}
.bar-row .q{color:var(--ink-500);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bar-row .t{height:7px;background:var(--band-2);border-radius:var(--r-pill);overflow:hidden}
.bar-row .t i{display:block;height:100%;background:var(--brand);border-radius:var(--r-pill)}
.bar-row .t.warn i{background:var(--warn)}
.bar-row .n{text-align:right;font-weight:700;font-variant-numeric:tabular-nums;color:var(--ink-900);font-size:13px}
.dpanel .foot-note{font-size:12.5px;color:var(--ink-400);margin:16px 0 0}
.safe-row{display:flex;align-items:center;gap:14px;background:var(--good-tint);border-radius:var(--r);padding:14px 16px;margin-top:4px}
.safe-row .big{font-size:30px;font-weight:800;color:var(--good);line-height:1}
.safe-row div{font-size:13px;color:var(--ink-500)}
.dash-foot{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:13px 22px;border-top:1px solid var(--line-soft);font-size:12.5px;color:var(--ink-400);flex-wrap:wrap}

.annot{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:28px}
.annot div{background:#fff;border:1px solid var(--line);border-radius:var(--r-card);padding:20px}
.annot .n{width:26px;height:26px;border-radius:var(--r-pill);background:var(--brand-tint);color:var(--brand-strong);font-size:12.5px;font-weight:700;display:grid;place-items:center;margin-bottom:12px}
.annot h4{margin-bottom:6px}
.annot p{font-size:14px;color:var(--ink-500);margin:0}

/* ===== TRUST ===== */
.trust-grid{display:grid;grid-template-columns:1.15fr .85fr;gap:26px;align-items:start}
/* Homepage trust section: the guarantee alone, centred, with the route through
   to the full Trust Centre page. */
.trust-solo{max-width:720px;margin:0 auto;text-align:center}
.trust-solo .guarantee{text-align:left}
.trust-solo-cta{margin-top:22px}
.guarantee{background:var(--night);color:#fff;border-radius:var(--r-card);padding:30px}
.guarantee h3{color:#fff;margin-bottom:12px}
.guarantee p{color:rgba(255,255,255,.70);font-size:15px;margin:0}
.docs{border:1px solid var(--line);border-radius:var(--r-card);background:#fff;padding:26px}
.docs ul{list-style:none;margin:0 0 20px;padding:0;display:flex;flex-direction:column;gap:12px}
.docs li{display:flex;gap:11px;font-size:14.5px;color:var(--ink-500);align-items:center}
.docs li .ico{width:17px;height:17px;color:var(--brand)}
/* Coming soon notice. The document library is not built yet, so the form is
   disabled in place rather than removed: the offer still gets read, and nobody
   hands over an address to something that cannot answer them. */
.tc-notice{
  display:flex;align-items:flex-start;gap:10px;margin:0 0 14px;
  background:var(--warn-tint);border:1px solid rgba(224,139,0,.28);
  border-radius:var(--r);padding:12px 14px;
  font-size:13.5px;font-weight:500;color:var(--ink-700);
}
.tc-notice .ico{width:16px;height:16px;color:var(--warn);margin-top:2px}

.tc-form{display:flex;gap:8px;flex-wrap:wrap}
.tc-form input{flex:1;min-width:200px;border:1px solid var(--line);border-radius:var(--r);padding:12px 14px;font:inherit;font-size:14.5px}
.tc-form input::placeholder{color:var(--ink-400)}
.tc-form input:disabled{background:var(--band);color:var(--ink-400);cursor:not-allowed}
.tc-form .btn:disabled{background:var(--band-2);color:var(--ink-400);box-shadow:none;cursor:not-allowed}
.tc-form .btn:disabled:hover{background:var(--band-2)}
.tc-sent{display:none;margin-top:14px;background:var(--good-tint);color:#0d6b37;border-radius:var(--r);padding:12px 14px;font-size:14px}
.tc-sent.show{display:block}
.tc-note{font-size:12.5px;color:var(--ink-400);margin:12px 0 0}

/* ===== FAQ ===== */
.faq{max-width:800px;margin:0 auto;border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;background:#fff}
.faq details{border-bottom:1px solid var(--line-soft)}
.faq details:last-child{border-bottom:0}
.faq summary{list-style:none;cursor:pointer;padding:18px 22px;font-size:15.5px;font-weight:600;letter-spacing:-0.015em;display:flex;align-items:center;gap:14px}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"";margin-left:auto;width:9px;height:9px;border-right:2px solid var(--ink-400);border-bottom:2px solid var(--ink-400);transform:rotate(45deg);transition:transform .2s;flex:none}
.faq details[open] summary::after{transform:rotate(-135deg)}
.faq .answer{padding:0 22px 20px;font-size:14.5px;color:var(--ink-500);max-width:70ch}

/* ===== CTA + FOOTER ===== */
.cta{background:var(--night);color:#fff;border-radius:20px;padding:56px 40px;text-align:center}
.cta h2{color:#fff;margin-bottom:14px}
.cta p{color:rgba(255,255,255,.68);margin:0 auto 26px;font-size:17px;max-width:52ch}
.cta .btn-secondary{background:transparent;color:#fff;border-color:rgba(255,255,255,.28)}
.cta .btn-secondary:hover{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.45)}
.cta-row{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}

/* Rounded top corners so the footer reads as a panel the page sits on top of,
   rather than the page simply running out. */
footer.site{background:var(--night);color:rgba(255,255,255,.62);padding:60px 0 26px;margin-top:0;border-radius:24px 24px 0 0}
footer.site .cols-grid{display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:40px}
footer.site .brand{color:#fff}
footer.site p{font-size:14px;margin:16px 0 0;max-width:38ch}
footer.site h4{color:#fff;margin-bottom:14px;font-size:13px;letter-spacing:.04em;text-transform:uppercase}
footer.site ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
footer.site a{color:rgba(255,255,255,.62);text-decoration:none;font-size:14px}
footer.site a:hover{color:#fff}
footer.site .bottom{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;border-top:1px solid rgba(255,255,255,.10);margin-top:44px;padding-top:22px;font-size:13px}

/* ===== MODAL ===== */
.overlay{position:fixed;inset:0;z-index:100;background:rgba(11,13,19,.55);backdrop-filter:blur(3px);display:grid;place-items:center;padding:24px;overflow:auto}
.overlay[hidden]{display:none}
.modal{width:100%;max-width:600px;background:#fff;border-radius:18px;box-shadow:var(--sh-lg);position:relative;padding:34px}
.modal-close{position:absolute;top:16px;right:16px;width:32px;height:32px;border-radius:var(--r-pill);border:1px solid var(--line);background:#fff;display:grid;place-items:center;cursor:pointer}
.modal h2{font-size:28px;margin-bottom:10px}
.modal .lede{font-size:15px;margin-bottom:24px}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.field{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
/* The hidden attribute has to be restated here. `.field` sets display:flex from
   the author sheet, which outranks the browser's own [hidden]{display:none}, so
   a field marked hidden in the markup rendered anyway. That is how the WhatsApp
   scope question came to show on all seven enquiry modals rather than only on
   whatsapp.html, which is the one page whose answers mean anything. */
.field[hidden]{display:none}
.field label{font-size:13px;font-weight:600;color:var(--ink-700)}
.field .opt{color:var(--ink-400);font-weight:500}
.field input,.field select,.field textarea{border:1px solid var(--line);border-radius:var(--r);padding:11px 13px;font:inherit;font-size:14.5px;background:#fff;color:var(--ink-900)}
.field textarea{resize:vertical}
.field .err{color:#c0392b;font-size:12.5px}
.field-error{border-color:#c0392b !important}
.form-foot{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:6px}
.form-note{font-size:12.5px;color:var(--ink-400);margin:0}
.modal .sent{display:none;text-align:center;padding:20px 0}
.modal .sent.show{display:block}
.modal .sent .tickcircle{width:52px;height:52px;border-radius:var(--r-pill);background:var(--good-tint);color:var(--good);display:grid;place-items:center;margin:0 auto 16px}
.modal .sent .tickcircle .ico{width:26px;height:26px;stroke-width:2.6}

/* ===== REVEAL ON SCROLL =====
   Set up by the REVEAL ON SCROLL block in app.js, which adds .motion to <html> only when the visitor
   allows motion, so without it every block simply shows. */
.motion .rise{transition:opacity .8s ease,transform 1s cubic-bezier(.2,.7,.2,1);transition-delay:var(--d,0ms)}
.motion .rise:not(.in){opacity:0;transform:translateY(24px)}
.motion .words .w{display:inline-block;overflow:hidden;vertical-align:top;padding:0 .08em .16em 0;margin:0 -.08em -.16em 0}
.motion .words .w>span{display:inline-block;transition:transform .9s cubic-bezier(.2,.75,.2,1);transition-delay:calc(var(--d,0ms) + var(--wi) * 55ms)}
.motion .words:not(.in) .w>span{transform:translateY(115%)}
@media print{.motion .rise,.motion .words .w>span{opacity:1 !important;transform:none !important}}

/* ===== CONCEPT RIBBON (local testing only) ===== */
.ribbon{background:var(--night);color:#fff;font-size:13px;padding:9px 0}
.ribbon .container{display:flex;gap:14px;align-items:center;justify-content:center;flex-wrap:wrap}
.ribbon b{font-weight:700}
.ribbon a{color:#fff;text-decoration:underline;text-underline-offset:3px}

/* ===== RESPONSIVE ===== */
@media (max-width:1080px){
  .demo-wrap{grid-template-columns:1fr}
  .rail{position:static}
  .rail ol{display:grid;grid-template-columns:repeat(2,1fr)}
}
@media (max-width:940px){
  :root{--gutter:22px}
  /* .candid is listed here but does NOT win: see the matching override in the
     second 940px block, below the :has() rule that sets its two column split. */
  .hero-grid,.cols,.panel-grid,.trust-grid,.candid,.page-hero.split-hero .ph-grid{grid-template-columns:1fr}
  /* Stacked, the copy leads again. The side swap is a wide screen idea only. */
  .split-hero .ph-copy{order:1}
  .split-hero .ph-art{order:2}
  /* Same reasoning as the desktop hero, scaled down: the top gap leads, the
     bottom one does not need to match it. */
  .hero{padding:64px 0 44px}
  .steps{grid-template-columns:repeat(2,1fr)}
  .proof-grid{grid-template-columns:repeat(2,1fr);gap:16px}
  .kpis,.dash-panels,.annot{grid-template-columns:1fr}
  footer.site .cols-grid{grid-template-columns:1fr 1fr}
  .tip{max-width:230px}
}

/* ===== NAV BREAKPOINT, ON ITS OWN =====
   The nav used to fold into the burger at the same 940px as everything else.
   With WhatsApp added there are six items, and six no longer fit beside the
   brand and the two actions: measured, the row needs 1106px of content width,
   and below that "Why not general AI" wrapped to four lines and the NEW badge
   dropped under its own label, leaving the bar 99px tall instead of 25px. The
   menu now takes over while there is still room for it. Deliberately a separate
   query rather than a tighter gap: a wrapped nav item is always wrong, and
   trimming the gap only moves the width at which it happens.
   ADDING A SEVENTH NAV ITEM MEANS RAISING THIS NUMBER AGAIN. */
@media (max-width:1140px){
  .nav ul{display:none;position:absolute;top:100%;left:0;right:0;background:#fff;border-bottom:1px solid var(--line);flex-direction:column;gap:0;padding:8px 22px 18px}
  .nav.open ul{display:flex}
  .nav ul a{display:block;padding:11px 0;font-size:16px;border-bottom:1px solid var(--line-soft)}
  /* With the links folded away the bar is three items: brand, call to action,
     burger. The auto margin has to sit on the ACTIONS, not on the burger. On
     the burger it packs the button hard against the wordmark and spends all the
     free space on its right, so the button reads as floating in the middle of
     the bar rather than belonging to either side. Moving it here pushes the
     pair to the right edge, where the thumb is. The inner gap drops to 16px in
     the same breath: 34px between the button and the burger is more than a
     390px phone can spare once the wordmark is on the row. */
  .nav .inner{gap:16px}
  .nav-actions{margin-left:auto}
  .burger{display:flex;margin-left:0}
  .nav-actions .login{display:none}
  /* ...and reappears in the folded menu, where there is room for it. Without
     this the link vanishes entirely below 1140px, on every phone and most
     tablets, leaving a school admin no way into the dashboard from this site. */
  .nav ul li.nav-login{display:block}
  /* A call to action that wraps to two lines makes the whole bar 14px taller
     and reads as broken. It stays on one line, and the wordmark gives way
     first at the widths where the two cannot both fit. */
  .nav-actions .btn{white-space:nowrap}
}
/* Below this the wordmark and a one-line button no longer both fit beside the
   burger: measured, the row needs 349px of content and a 320px phone offers
   276px. The mark alone still identifies the site, so the name is what goes.
   font-size:0 rather than display:none, so the mark keeps its own box and the
   link keeps its tap target. */
@media (max-width:374px){
  .nav .brand{font-size:0}
  .nav .brand .brand-mark{font-size:19px}
  .nav .inner{gap:12px}
  .nav-actions .btn-sm{padding:9px 13px}
}
@media (max-width:640px){
  section{padding:60px 0}
  .rail ol{grid-template-columns:1fr}
  /* The stage keeps its full height at every width: the ask bar has to clear
     the quick links strip, and the capture form on step 4 is a fixed stack of
     fields, so a shorter stage clips one or the other. What gives instead is
     the conversation above the form, and the placeholder in the bar. */
  .stage[data-step="4"] .chatpanel-body{max-height:340px}
  .askbar .txt{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* At this width the school's own standfirst wraps to four lines and pushes
     its headline up under the masthead. The headline, the buttons and the bar
     are the parts this frame is actually about. */
  .ss-hero .ss-sub{display:none}
  .field-row{grid-template-columns:1fr}
  .modal{padding:24px}
  .cta{padding:40px 22px}
  .tabs{width:100%}
  .tip{max-width:200px;padding:12px}
  .table-wrap{overflow-x:auto}
  table.cmp{min-width:560px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important}
  html{scroll-behavior:auto}
}

/* ============================================================
   INNER PAGE COMPONENTS
   Used by why-veaivo, features, safeguarding, trust-centre, pricing.
   ============================================================ */

.crumb{display:flex;gap:8px;align-items:center;font-size:13px;color:var(--ink-400);margin-bottom:22px}
.crumb a{text-decoration:none;color:var(--ink-400)}
.crumb a:hover{color:var(--ink-900)}
.crumb span{color:var(--ink-700);font-weight:600}

/* ===== SPLIT PAGE HERO (copy one side, device the other) ===== */
.split-hero .ph-grid{display:grid;grid-template-columns:1fr 1fr;gap:56px;align-items:center;margin-top:8px}
/* The copy top-aligns, the art stays centred against it. Centring BOTH made the
   headline land in a different place on every page: the row is as tall as the
   taller column, so a page with long copy pinned its h1 to the top of the grid
   while a page with short copy and a tall device pushed its h1 down. Across the
   five sub pages that was a 76px spread (safeguarding 183px, features 259px),
   which read as some pages having been updated and others missed. */
.split-hero .ph-copy{order:1;min-width:0;align-self:start}
.split-hero .ph-art{order:2;min-width:0;display:flex;flex-direction:column;align-items:center}
.split-hero .ph-copy h1{max-width:none}
/* Copy on the right instead, so a sub page does not read as the homepage hero
   repeated. Visual only: the copy stays first in the DOM either way. */
.split-hero.flip .ph-copy{order:2}
.split-hero.flip .ph-art{order:1}

/* Phone. All markup, no screenshot, so it cannot drift from the real styling. */
.phone{
  width:288px;max-width:100%;background:#0b0d13;border:1px solid #262a35;
  border-radius:38px;padding:9px;box-shadow:var(--sh-lg),var(--glow);
}
.phone-speaker{display:block;width:52px;height:4px;border-radius:var(--r-pill);background:#2c313d;margin:2px auto 7px}
.phone-screen{background:#fff;border-radius:30px;overflow:hidden;display:flex;flex-direction:column}
.ph-top{display:flex;align-items:center;gap:9px;padding:13px 14px;border-bottom:1px solid var(--line-soft)}
.ph-ava{width:29px;height:29px;border-radius:9px;background:var(--ks);color:#fff;display:grid;place-items:center;font-weight:800;font-size:13px;flex:none}
.ph-who{display:flex;flex-direction:column;line-height:1.25;min-width:0}
.ph-who b{font-size:13.5px;font-weight:700;letter-spacing:-0.015em}
.ph-who i{font-style:normal;font-size:11px;color:var(--ink-400);display:inline-flex;align-items:center;gap:5px}
.ph-who i::before{content:"";width:5px;height:5px;border-radius:var(--r-pill);background:var(--good)}
.ph-lang{margin-left:auto;flex:none;font-size:10.5px;font-weight:700;letter-spacing:.06em;color:var(--ks);background:var(--ks-tint);border-radius:var(--r-pill);padding:3px 8px}
.ph-body{padding:14px;display:flex;flex-direction:column;gap:9px}
.ph-msg{max-width:88%;padding:9px 12px;border-radius:13px;font-size:12.5px;line-height:1.45}
.ph-user{background:var(--ks);color:#fff;align-self:flex-end;border-bottom-right-radius:4px;font-weight:500}
.ph-bot{background:var(--band);color:var(--ink-700);align-self:flex-start;border-bottom-left-radius:4px}
.ph-cite{display:inline-flex;align-items:center;gap:5px;margin-top:8px;background:#fff;border:1px solid var(--line);border-radius:var(--r-pill);padding:3px 8px;font-size:10.5px;font-weight:600;color:var(--ink-500)}
.ph-cite .ico{width:10px;height:10px;color:var(--ks)}
.ph-input{display:flex;align-items:center;gap:8px;margin:2px 12px 14px;padding:9px 12px;border:1px solid var(--line);border-radius:var(--r-pill);font-size:12px;color:var(--ink-400)}
.ph-input i{margin-left:auto;width:22px;height:22px;border-radius:var(--r-pill);background:var(--ks);flex:none}
.ph-caption{margin:18px 0 0;font-size:13px;color:var(--ink-400);text-align:center;max-width:34ch}

/* Pricing quote. The three lines a school braces to be charged for read zero. */
.quote{width:100%;max-width:400px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--sh-lg);overflow:hidden}
.quote-top{display:flex;align-items:center;gap:10px;padding:14px 18px;background:var(--night);color:#fff}
.quote-school{font-size:13.5px;font-weight:700;letter-spacing:-0.015em}
.quote-plan{margin-left:auto;font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;background:rgba(255,255,255,.14);border-radius:var(--r-pill);padding:3px 9px}
.quote-lines{list-style:none;margin:0;padding:6px 0;display:flex;flex-direction:column}
.quote-lines li{display:flex;align-items:center;gap:12px;padding:10px 18px;font-size:13.5px;color:var(--ink-500)}
.quote-lines b{margin-left:auto;font-weight:700;color:var(--ink-900);font-variant-numeric:tabular-nums}
.quote-lines b.nil{color:var(--good)}
.quote-foot{display:flex;align-items:center;gap:12px;padding:13px 18px;border-top:1px solid var(--line);background:var(--band)}
.quote-foot span{font-size:12.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-400)}
.quote-foot b{margin-left:auto;font-size:20px;font-weight:800;letter-spacing:-0.03em;font-variant-numeric:tabular-nums}
.quote-note{padding:12px 18px;border-top:1px solid var(--line-soft);font-size:12px;color:var(--ink-400);line-height:1.45}
/* On a phone the hero art stacks UNDER the copy, so the example quote lands
   one scroll above the tier cards and reads as the same prices given twice.
   The tiers are the ones that have to be read, so the example goes. Placed
   after `.split-hero .ph-art{display:flex}` on purpose: same specificity, and a
   media query adds none, so an earlier rule would silently lose. */
@media (max-width:640px){
  .split-hero .ph-art-quote{display:none}
}

/* Safeguarding escalation. The routing, never the message that triggered it. */
.tline{width:100%;max-width:420px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--sh-lg);overflow:hidden}
.tline-top{display:flex;align-items:center;gap:9px;padding:14px 18px;background:var(--night);color:#fff;font-size:13px;font-weight:700}
.tline-top .ico{width:15px;height:15px;color:var(--good)}
.tline-steps{list-style:none;margin:0;padding:16px 18px;display:flex;flex-direction:column;gap:0}
.tline-steps li{position:relative;display:flex;gap:14px;padding:0 0 18px 0}
.tline-steps li:last-child{padding-bottom:0}
/* Connector down the timestamp gutter, stopped short on the final step. */
.tline-steps li::before{content:"";position:absolute;left:26px;top:18px;bottom:0;width:2px;background:var(--line)}
.tline-steps li:last-child::before{display:none}
.tline-steps b{position:relative;z-index:1;flex:none;width:54px;font-size:12px;font-weight:700;color:var(--ink-400);font-variant-numeric:tabular-nums;background:var(--card);padding-top:1px}
.tline-steps span{font-size:13.5px;line-height:1.5;color:var(--ink-500)}
.tline-steps strong{color:var(--ink-900);font-weight:700}
.tline-foot{padding:13px 18px;background:var(--band);border-top:1px solid var(--line-soft);font-size:12.5px;color:var(--ink-400)}

/* Same question, answered twice. */
.vs{width:100%;max-width:420px;display:flex;flex-direction:column;gap:12px}
.vs-q{background:var(--ks);color:#fff;border-radius:13px;border-bottom-right-radius:4px;padding:11px 14px;font-size:13.5px;font-weight:500;align-self:flex-end;max-width:92%}
.vs-card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);padding:16px;box-shadow:var(--sh-sm)}
.vs-card p{font-size:13.5px;line-height:1.5;color:var(--ink-700);margin:9px 0 0;max-width:none}
.vs-tag{display:inline-flex;align-items:center;font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;border-radius:var(--r-pill);padding:3px 9px}
.vs-bad{background:var(--band)}
.vs-bad .vs-tag{background:var(--warn-tint);color:#9a6100}
.vs-good{border-color:var(--ks);box-shadow:0 0 0 3px rgba(15,47,76,.10),var(--sh-sm)}
.vs-good .vs-tag{background:var(--ks-tint);color:var(--ks)}
.vs-cite{display:inline-flex;align-items:center;gap:5px;margin-top:10px;background:#fff;border:1px solid var(--line);border-radius:var(--r-pill);padding:3px 9px;font-size:11px;font-weight:600;color:var(--ink-500)}
.vs-cite .ico{width:11px;height:11px;color:var(--ks)}
.vs-note{margin-top:10px;padding-top:10px;border-top:1px solid var(--line-soft);font-size:12px;color:var(--ink-400);line-height:1.45}

/* Trust Centre pack. Same idea as the phone: drawn, not photographed. */
.pack{width:100%;max-width:380px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--sh-lg);overflow:hidden}
.pack-top{display:flex;align-items:center;gap:9px;padding:14px 18px;background:var(--night);color:#fff;font-size:13px;font-weight:700;letter-spacing:-0.01em}
.pack-top .ico{width:15px;height:15px;color:var(--good)}
.pack-list{list-style:none;margin:0;padding:6px 0;display:flex;flex-direction:column}
.pack-list li{display:flex;align-items:center;gap:11px;padding:11px 18px;font-size:13.5px;color:var(--ink-700);border-bottom:1px solid var(--line-soft)}
.pack-list li:last-child{border-bottom:0}
.pack-list .ico{width:15px;height:15px;color:var(--brand);flex:none}
.pack-foot{padding:13px 18px;background:var(--band);border-top:1px solid var(--line-soft);font-size:12.5px;color:var(--ink-400);font-weight:600}

/* The breadcrumb still rides above the hero content, where it reads as
   navigation rather than as part of the headline. It no longer sits hard up
   under the nav though: 26px left it looking stuck to the bar, and now that the
   bar has no bottom border at rest it had nothing to sit against either. The
   20px added here comes straight back out of the crumb's bottom margin, so the
   headline below lands in the same place it always did. Applies to every sub
   page hero. */
.page-hero{padding:46px 0 60px;border-bottom:1px solid var(--line-soft)}
/* Now that the copy top-aligns, this margin IS the gap from crumb to headline
   on every sub page, so it sets where all five headlines start. 88px lands them
   at 215px, which is where the pricing page already sat and read correctly. */
.page-hero .crumb{margin-bottom:88px}
.page-hero h1{font-size:clamp(34px,4.4vw,54px);margin-bottom:20px;max-width:19ch}
.page-hero .lede{max-width:60ch;font-size:clamp(17px,1.3vw,19px)}
.page-hero .hero-ctas{margin-top:30px}

/* Generic card grids */
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:20px}
.card{background:#fff;border:1px solid var(--line);border-radius:var(--r-card);padding:26px}
.card .ico{color:var(--brand);margin-bottom:14px}
.card h3{margin-bottom:8px}
.card p{font-size:14.5px;color:var(--ink-500);margin:0}
.card .kicker{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--brand-strong);margin-bottom:10px;display:block}
.card-num{width:30px;height:30px;border-radius:var(--r-pill);background:var(--brand-tint);color:var(--brand-strong);display:grid;place-items:center;font-size:13px;font-weight:700;margin-bottom:14px}

/* Two-layer safeguarding check */
.layers{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.layer{background:#fff;border:1px solid var(--line);border-radius:var(--r-card);padding:26px;position:relative}
.layer .tagn{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--brand-strong);display:block;margin-bottom:10px}

/* Red and amber grading */
.grade{border-radius:var(--r-card);padding:26px;border:1px solid var(--line);background:#fff}
.grade.red{border-color:#f3c7c2;background:#fdf4f3}
.grade.amber{border-color:#f2ddb4;background:var(--warn-tint)}
.grade .dot{width:10px;height:10px;border-radius:var(--r-pill);display:inline-block;margin-right:8px;vertical-align:1px}
.grade.red .dot{background:#c0392b}
.grade.amber .dot{background:var(--warn)}
.grade h3{margin-bottom:6px}
.grade .sub{font-size:13px;font-weight:600;color:var(--ink-400);margin-bottom:16px}
.grade ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.grade li{display:flex;gap:10px;font-size:14.5px;color:var(--ink-500)}
.grade li .ico{width:16px;height:16px;flex:none;margin-top:3px;color:var(--ink-400)}

/* Pricing */
.tiers{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;align-items:start}
.tier{background:#fff;border:1px solid var(--line);border-radius:var(--r-card);padding:28px;position:relative}
.tier.best{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-ring)}
.tier .flag{position:absolute;top:-11px;left:28px;background:var(--brand);color:#fff;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;padding:4px 11px;border-radius:var(--r-pill)}
.tier h3{margin-bottom:6px}
.tier .who{font-size:14px;color:var(--ink-400);margin-bottom:20px;min-height:68px}
.tier .price{font-size:38px;font-weight:800;letter-spacing:-0.035em;line-height:1}
.tier .price small{font-size:15px;font-weight:600;color:var(--ink-400);letter-spacing:0}
.tier .setup{font-size:13.5px;color:var(--ink-500);margin:8px 0 4px}
.tier .note{font-size:13px;color:var(--ink-400);margin-bottom:20px}
.tier ul{list-style:none;margin:0 0 24px;padding:0;display:flex;flex-direction:column;gap:10px}
.tier li{display:flex;gap:10px;font-size:14px;color:var(--ink-500);line-height:1.45}
.tier li .ico{width:15px;height:15px;flex:none;margin-top:3px;color:var(--good);stroke-width:2.6}
/* This list item shares its class name with the centred section heading block,
   so it was quietly inheriting that block's text-align, auto margins and 30px
   of top padding: "Everything in Essentials, plus" rendered centred, adrift
   from the left aligned list under it, on the pricing page as well as here.
   Every inherited property is put back explicitly rather than renaming the
   class, which would mean editing the markup on both pages. */
.tier li.head{display:block;font-weight:700;color:var(--ink-900);text-align:left;max-width:none;margin:0 0 2px;padding-top:0}
.tier .btn{width:100%}
.price-foot{display:flex;flex-wrap:wrap;gap:10px 26px;justify-content:center;margin-top:30px;font-size:13.5px;color:var(--ink-400)}
.price-foot span{display:inline-flex;align-items:center;gap:7px}
.price-foot .ico{width:15px;height:15px;color:var(--good);stroke-width:2.4}

/* Quote / candid band */
/* The panel runs the full width of the container, so a single column of capped
   text left a dead band down the right hand side. Statement on one side, the
   argument on the other, which uses the width instead of just stretching the
   line length past comfortable reading. */
.candid{background:var(--night);color:#fff;border-radius:20px;padding:44px 40px}
/* Two columns only when the panel actually has the two wrappers. Guarded with
   :has() on purpose: applying the grid to a bare .candid scatters the label,
   heading and paragraph into three separate cells, which is exactly what
   happened when this was written unguarded. Without :has() support it stays a
   single column block, which is the correct fallback either way. */
.candid:has(.candid-head){
  display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);
  gap:44px;align-items:start;
}
.candid h2{color:#fff;margin:0;max-width:18ch}
.candid p{color:rgba(255,255,255,.72);font-size:16px;max-width:60ch}
.candid p:last-child{margin-bottom:0}

/* ===== MONTHLY REVIEW EMAIL ===== */
.mail{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--sh-lg);overflow:hidden}
.mail-top{display:flex;align-items:center;gap:10px;padding:13px 18px;border-bottom:1px solid var(--line-soft);background:#fbfbfd}
.mail-from{display:flex;align-items:center;gap:9px;font-size:13.5px;font-weight:700;letter-spacing:-0.015em}
.mail-ava{width:26px;height:26px;border-radius:8px;background:var(--brand);color:#fff;display:grid;place-items:center;font-size:12px;font-weight:800;flex:none}
.mail-date{margin-left:auto;font-size:12.5px;color:var(--ink-400)}
.mail-subject{padding:16px 18px 0;font-size:16px;font-weight:800;letter-spacing:-0.022em}
.mail-body{padding:14px 18px 20px}
.mail-body p{font-size:14px;color:var(--ink-500);margin:0 0 10px;max-width:none}
.mail-body p:last-child{margin-bottom:0}
.mail-body p b{color:var(--ink-900);font-weight:700}
.mail-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line-soft);border:1px solid var(--line-soft);border-radius:var(--r);overflow:hidden;margin-bottom:16px}
.mail-stats div{background:#fff;padding:13px 14px;display:flex;flex-direction:column;gap:3px}
.mail-stats b{font-size:22px;font-weight:800;letter-spacing:-0.03em;line-height:1;font-variant-numeric:tabular-nums}
.mail-stats span{font-size:11.5px;color:var(--ink-400);font-weight:600}
.mail-note{font-size:13.5px;color:var(--ink-400);margin:18px 0 0;max-width:56ch}

.ticks{list-style:none;margin:18px 0 0;padding:0;display:flex;flex-direction:column;gap:11px}
.ticks li{position:relative;padding-left:28px;font-size:14.5px;color:var(--ink-500);line-height:1.5}
.ticks li::before{
  content:"";position:absolute;left:0;top:4px;width:16px;height:16px;border-radius:var(--r-pill);
  background:var(--brand-tint);
}
/* The check is a rotated box corner, and the INK of that corner does not sit in
   the middle of the box it is drawn in: rotating 45deg puts the elbow low and
   the two arms high, so the visible mark landed about 1.75px below the centre
   of its circle and read as dropped. Offset to centre the ink, not the box. */
.ticks li::after{
  content:"";position:absolute;left:4.25px;top:4.95px;width:5px;height:8px;
  border-right:2px solid var(--brand-strong);border-bottom:2px solid var(--brand-strong);
  transform:rotate(45deg);
}

/* Split feature row */
.split{display:grid;grid-template-columns:1fr 1fr;gap:44px;align-items:center}
.split + .split{margin-top:64px}
.split.flip .split-media{order:-1}
.split h3{margin-bottom:12px}
.split p{font-size:15.5px;color:var(--ink-500)}

@media (max-width:940px){
  .grid-3,.grid-4,.grid-2,.tiers,.layers,.split{grid-template-columns:1fr}
  .split.flip .split-media{order:0}
  /* The earlier 940px block lists .candid, but a media query adds no
     specificity and .candid:has(.candid-head) above is both more specific and
     later in the file, so every candid panel on the site stayed two columns on
     a phone: roughly 93px and 114px wide on a 390px screen. Matched selector,
     placed after the rule it has to beat. */
  .candid:has(.candid-head){grid-template-columns:1fr;gap:18px}
  /* Stacked, so the crumb's bottom margin is the real gap to the headline and
     stays as it is. Only the space above the crumb grows. */
  .page-hero{padding:34px 0 44px}
  .page-hero .crumb{margin-bottom:32px}
}

/* Whatever the current step points at is itself a click target, so a
   30px dot is never the only way to move the walkthrough on. */
.stage .askbar,
.stage .chatpanel-input,
.stage .m-answer,
.stage .qsug button,
.stage .q-form,
.stage .dashcard{cursor:pointer}


/* ===== CARD LIFT =====
   These components were border only, so on a white page they read as drawn on
   rather than sitting above it. A soft grey shadow does the lifting. Cards on a
   dark band are NOT affected: those rules are more specific and still apply the
   light ring treatment, because a grey shadow cannot show on navy. */
.card,.tier,.col-card,.faq,.docs,.note-band,.layer,.grade,.table-wrap,.annot>div{
  box-shadow:var(--sh-card);
}


/* ===== HERO AUDIENCE LINE =====
   The one eyebrow worth keeping, because it says who the product is for and
   that it covers both sectors, which the headline does not. Deliberately NOT
   the old pill: plain muted text, sentence case, no uppercase, no letter
   spacing, no tinted capsule, no dot. That combination is what read as a
   generated template, not the words themselves. */
.hero-kicker{
  margin:0 0 14px;
  font-size:15px;font-weight:500;line-height:1.4;
  color:var(--ink-400);letter-spacing:0;text-transform:none;
}

/* Carries what the "Contractual guarantee" eyebrow used to say, now as a line
   of copy, because it changes the claim above it from a policy to a promise. */
.guarantee .guarantee-note{
  margin:12px 0 0;font-size:13.5px;font-weight:600;color:rgba(255,255,255,.60);
}


/* ============================================================
   WHATSAPP PAGE
   Used by whatsapp.html only, plus the nav badge on every page.
   ============================================================ */

/* NEW badge on the nav item. Same treatment as the .flag "Recommended" tag on
   the Professional tier, so the site has one way of marking something out
   rather than two. Raised against the cap height of the label rather than
   sitting on the baseline, which is what stops it reading as a second word. */
.tag-new{
  display:inline-block;position:relative;top:-6px;margin-left:5px;
  background:var(--brand);color:#fff;
  font-size:10px;font-weight:700;line-height:1;letter-spacing:.06em;text-transform:uppercase;
  padding:3px 6px;border-radius:var(--r-pill);vertical-align:baseline;
}
/* In the burger menu each item is a full width block, so the badge has room to
   sit on the line properly instead of being tucked above it. Matches the nav's
   own 1080px breakpoint, not the site wide 940px one. */
@media (max-width:1140px){
  .tag-new{top:-1px}
}

/* ===== WHATSAPP CONVERSATION MOCK =====
   Drawn in CSS inside the existing .phone shell, not screenshotted and not
   generated. Three reasons, in order: a generated screenshot produces garbled
   bubble text on a page whose entire argument is trust; real WhatsApp chrome in
   third party marketing runs into Meta's brand guidelines; and markup stays
   sharp, weighs nothing and inherits the page's own tokens.
   The .phone, .phone-speaker, .phone-screen and .ph-caption wrappers are the
   ones features.html already uses, so the bloom and the sizing come for free. */
.wa{display:flex;flex-direction:column;min-height:0}

/* Header in the mock SCHOOL's navy, not WhatsApp's own green. This is the
   school's number, and the page argues exactly that. */
.wa-top{display:flex;align-items:center;gap:9px;padding:11px 13px;background:var(--ks);color:#fff}
.wa-back{flex:none;width:8px;height:8px;border-left:2px solid rgba(255,255,255,.75);border-bottom:2px solid rgba(255,255,255,.75);transform:rotate(45deg);margin-right:1px}
.wa-ava{width:29px;height:29px;border-radius:var(--r-pill);background:#fff;color:var(--ks);display:grid;place-items:center;font-weight:800;font-size:12.5px;flex:none}
.wa-who{display:flex;flex-direction:column;line-height:1.25;min-width:0}
.wa-who b{font-size:13px;font-weight:700;letter-spacing:-0.012em}
.wa-who span{font-size:10.5px;color:rgba(255,255,255,.72)}

/* The wallpaper. Cream ground with a faint abstract tile: deliberately NOT a
   copy of WhatsApp's own doodle set, which is their artwork. */
.wa-thread{
  flex:1;padding:14px 10px 12px;display:flex;flex-direction:column;gap:3px;
  background-color:var(--wa-paper);
  background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27108%27%20height%3D%27108%27%20viewBox%3D%270%200%20108%20108%27%20fill%3D%27none%27%20stroke%3D%27%23c6b9a5%27%20stroke-width%3D%271.1%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Ccircle%20cx%3D%2715%27%20cy%3D%2717%27%20r%3D%275.5%27%2F%3E%3Cpath%20d%3D%27M69%2015h10M74%2010v10%27%2F%3E%3Cpath%20d%3D%27M37%2043a9%209%200%200%201%2015-5.5%27%2F%3E%3Crect%20x%3D%2789%27%20y%3D%2750%27%20width%3D%2711%27%20height%3D%2711%27%20rx%3D%272.5%27%20transform%3D%27rotate%2822%2094.5%2055.5%29%27%2F%3E%3Cpath%20d%3D%27M5%2073c4-5%209%205%2013%200s9%205%2013%200%27%2F%3E%3Cpath%20d%3D%27M53%2093l6.5-11%206.5%2011z%27%2F%3E%3Ccircle%20cx%3D%2786%27%20cy%3D%2788%27%20r%3D%272.6%27%2F%3E%3Cpath%20d%3D%27M26%2099a7%207%200%201%200%209-3.5%27%2F%3E%3Cpath%20d%3D%27M100%2012c-4%202-4%208%200%2010%27%2F%3E%3Cpath%20d%3D%27M46%2066h13%27%2F%3E%3C%2Fsvg%3E");
  background-size:108px 108px;
}

/* Centred capsules for the date and the business account notice. */
.wa-pill{
  align-self:center;margin:5px 0;background:rgba(255,255,255,.92);
  border-radius:var(--r-sm);padding:4px 10px;max-width:88%;
  font-size:10.5px;line-height:1.4;font-weight:500;color:var(--wa-meta);text-align:center;
  box-shadow:0 1px 1px rgba(11,13,19,.08);
}

/* flow-root, not overflow:hidden, so the floated timestamp below is contained
   without clipping the tail, which is drawn outside the bubble. */
.wa-msg{
  position:relative;display:flow-root;max-width:84%;padding:6px 9px 5px;border-radius:7px;
  font-size:12.5px;line-height:1.42;color:var(--ink-900);
  box-shadow:0 1px 1px rgba(11,13,19,.13);
}
.wa-in{align-self:flex-start;background:var(--wa-in)}
.wa-out{align-self:flex-end;background:var(--wa-out)}

/* The tail belongs to the FIRST bubble of a run, which is how the real client
   groups them. Done with an adjacency rule rather than a class in the markup,
   so reordering the conversation cannot leave a tail in the wrong place. A
   centred pill between two bubbles correctly starts a new run. */
.wa-msg::after{content:"";position:absolute;top:0;width:0;height:0;border-style:solid}
.wa-in::after{left:-7px;border-width:0 8px 8px 0;border-color:transparent var(--wa-in) transparent transparent}
.wa-out::after{right:-7px;border-width:0 0 8px 8px;border-color:transparent transparent transparent var(--wa-out)}
.wa-in + .wa-in::after,.wa-out + .wa-out::after{display:none}

/* Timestamp and ticks sit INSIDE the bubble, bottom right, which is the detail
   that makes a mocked bubble read as real. The float keeps the last line of
   text wrapping around them the way the client does. */
.wa-meta{float:right;display:inline-flex;align-items:center;gap:3px;margin:6px 0 0 8px;font-size:10px;color:var(--wa-meta);line-height:1}
.wa-meta .wa-ticks{width:15px;height:9px;flex:none;fill:none;stroke:var(--wa-tick);stroke-width:2.1;stroke-linecap:round;stroke-linejoin:round}

/* Citation chip. Same idea as the widget's, sized down to bubble scale. */
.wa-cite{display:inline-flex;align-items:center;gap:5px;background:var(--band);border:1px solid var(--line);border-radius:var(--r-pill);padding:2px 8px;font-size:10px;font-weight:600;color:var(--ink-500)}
.wa-cite .ico{width:10px;height:10px;color:var(--ks);stroke-width:2}

/* When a bubble carries a chip, the timestamp shares the row with it rather
   than floating onto a line of its own underneath. */
.wa-foot{display:flex;align-items:center;gap:8px;margin-top:7px}
.wa-foot .wa-meta{float:none;margin:0 0 0 auto}

/* A captured enquiry, shown as the product's own note rather than a bubble, so
   nobody reads it as something WhatsApp itself does. */
.wa-note{display:flex;align-items:center;gap:6px;margin-top:8px;padding-top:7px;border-top:1px solid var(--line-soft);font-size:10px;font-weight:600;color:var(--brand-strong)}
.wa-note .ico{width:11px;height:11px;stroke-width:2.2}

.wa-input{display:flex;align-items:center;gap:8px;padding:8px 10px;background:#f0f2f5}
.wa-input .wa-box{flex:1;background:#fff;border-radius:var(--r-pill);padding:7px 12px;font-size:11.5px;color:var(--ink-400)}
.wa-input .wa-send{width:26px;height:26px;border-radius:var(--r-pill);background:var(--ks);flex:none;display:grid;place-items:center}
.wa-input .wa-send .ico{width:12px;height:12px;color:#fff;stroke-width:2.2}

/* ===== PRICE COMPARISON ROW =====
   The three ways to buy carry two numbers each, and the .tier .price slot only
   holds one. This is the second line, kept in the same visual family. */
/* The only inline text link inside a tier. a{color:inherit} would leave it the
   same muted grey as the sentence around it. */
.tier .note a{color:var(--brand-strong);font-weight:600;text-decoration:underline;text-underline-offset:2px}
.tier .price-alt{font-size:21px;font-weight:800;letter-spacing:-0.03em;line-height:1.2;margin:9px 0 4px}
.tier .price-alt small{font-size:13.5px;font-weight:600;color:var(--ink-400);letter-spacing:0}
.tier .price-alt .waive{color:var(--good)}

/* Section 3's handover mock sits beside its copy. Every other .split-media on
   the site holds a full width .frame, so the column has never needed to centre
   anything; a 288px phone in a 528px column does, or it hangs off the left. */
.wa-split .split-media{display:flex;justify-content:center}

/* ===== HERO, THE CENTRED LAYOUT =====
   This block was written as an experiment alongside the old two column hero and
   has since become the homepage, so index.html uses all of it. index-hero-a.html
   is the previous layout, kept for comparison and using none of these classes.

   The two column hero put the headline in half the width, which cost it two
   extra line breaks at the exact place the page is meant to feel confident.
   One centred column gives the sentence the whole measure, and the live widget
   moves up underneath it as the proof. */
.hero-b{padding:104px 0 52px;position:relative;isolation:isolate}
/* The same scatter the blue bands wear, in a grey light enough to read as paper
   grain rather than as dots. Reusing the band tile verbatim, recoloured: one
   texture across the page beats two that nearly match. Masked to fade out before
   the section edge so it never ends on a hard line. */
.hero-b,.layout-c #whatsapp-teaser{--dots-grey:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22240%22%20height%3D%22240%22%20viewBox%3D%220%200%20240%20240%22%20fill%3D%22%23a8adbb%22%3E%3Ccircle%20cx%3D%22108.6%22%20cy%3D%22134.3%22%20r%3D%221.28%22%20opacity%3D%220.85%22%2F%3E%3Ccircle%20cx%3D%22221.8%22%20cy%3D%22111.8%22%20r%3D%221.11%22%20opacity%3D%220.58%22%2F%3E%3Ccircle%20cx%3D%2244.3%22%20cy%3D%22122.9%22%20r%3D%221.89%22%20opacity%3D%220.92%22%2F%3E%3Ccircle%20cx%3D%22151.2%22%20cy%3D%22190.3%22%20r%3D%221.98%22%20opacity%3D%220.6%22%2F%3E%3Ccircle%20cx%3D%2222.6%22%20cy%3D%2272.8%22%20r%3D%222.47%22%20opacity%3D%220.56%22%2F%3E%3Ccircle%20cx%3D%2221.8%22%20cy%3D%22194.3%22%20r%3D%221.03%22%20opacity%3D%220.6%22%2F%3E%3Ccircle%20cx%3D%22166.4%22%20cy%3D%2210.1%22%20r%3D%221.71%22%20opacity%3D%220.48%22%2F%3E%3Ccircle%20cx%3D%22235.7%22%20cy%3D%22231.5%22%20r%3D%221.28%22%20opacity%3D%220.65%22%2F%3E%3Ccircle%20cx%3D%22156.9%22%20cy%3D%22147.7%22%20r%3D%221.92%22%20opacity%3D%220.52%22%2F%3E%3Ccircle%20cx%3D%2237.8%22%20cy%3D%223.6%22%20r%3D%221.58%22%20opacity%3D%220.94%22%2F%3E%3Ccircle%20cx%3D%22126.8%22%20cy%3D%2214.3%22%20r%3D%222.57%22%20opacity%3D%220.81%22%2F%3E%3Ccircle%20cx%3D%2245.6%22%20cy%3D%2258.1%22%20r%3D%222.11%22%20opacity%3D%220.77%22%2F%3E%3Ccircle%20cx%3D%227.2%22%20cy%3D%22111.3%22%20r%3D%221.22%22%20opacity%3D%220.47%22%2F%3E%3Ccircle%20cx%3D%22105.7%22%20cy%3D%22202.2%22%20r%3D%221.03%22%20opacity%3D%220.95%22%2F%3E%3Ccircle%20cx%3D%22124.6%22%20cy%3D%22153.7%22%20r%3D%222.12%22%20opacity%3D%220.98%22%2F%3E%3Ccircle%20cx%3D%22109.8%22%20cy%3D%2266.8%22%20r%3D%221.03%22%20opacity%3D%220.8%22%2F%3E%3Ccircle%20cx%3D%22201.7%22%20cy%3D%22169.9%22%20r%3D%221.77%22%20opacity%3D%220.85%22%2F%3E%3Ccircle%20cx%3D%2275.7%22%20cy%3D%2255.1%22%20r%3D%221.51%22%20opacity%3D%221.0%22%2F%3E%3Ccircle%20cx%3D%2269.4%22%20cy%3D%2216.9%22%20r%3D%221.12%22%20opacity%3D%220.75%22%2F%3E%3Ccircle%20cx%3D%22183.9%22%20cy%3D%2296.1%22%20r%3D%222.18%22%20opacity%3D%220.95%22%2F%3E%3Ccircle%20cx%3D%22229.9%22%20cy%3D%22203.4%22%20r%3D%222.18%22%20opacity%3D%220.84%22%2F%3E%3Ccircle%20cx%3D%220.1%22%20cy%3D%2250.3%22%20r%3D%222.27%22%20opacity%3D%220.95%22%2F%3E%3Ccircle%20cx%3D%22235.3%22%20cy%3D%2295.4%22%20r%3D%221.56%22%20opacity%3D%220.83%22%2F%3E%3Ccircle%20cx%3D%2217.5%22%20cy%3D%22151.1%22%20r%3D%222.44%22%20opacity%3D%220.93%22%2F%3E%3Ccircle%20cx%3D%22186.8%22%20cy%3D%2264.7%22%20r%3D%221.67%22%20opacity%3D%220.88%22%2F%3E%3Ccircle%20cx%3D%22231.4%22%20cy%3D%22181.9%22%20r%3D%222.38%22%20opacity%3D%220.77%22%2F%3E%3Ccircle%20cx%3D%22191.3%22%20cy%3D%2242.6%22%20r%3D%222.0%22%20opacity%3D%220.66%22%2F%3E%3Ccircle%20cx%3D%22134.2%22%20cy%3D%22107.4%22%20r%3D%221.93%22%20opacity%3D%220.78%22%2F%3E%3Ccircle%20cx%3D%2245.8%22%20cy%3D%22175.7%22%20r%3D%221.13%22%20opacity%3D%220.8%22%2F%3E%3Ccircle%20cx%3D%2228.0%22%20cy%3D%22101.0%22%20r%3D%222.59%22%20opacity%3D%220.93%22%2F%3E%3Ccircle%20cx%3D%2273.0%22%20cy%3D%22212.4%22%20r%3D%222.17%22%20opacity%3D%220.66%22%2F%3E%3Ccircle%20cx%3D%2250.6%22%20cy%3D%2294.6%22%20r%3D%222.18%22%20opacity%3D%220.77%22%2F%3E%3Ccircle%20cx%3D%2224.1%22%20cy%3D%22237.4%22%20r%3D%221.7%22%20opacity%3D%220.91%22%2F%3E%3Ccircle%20cx%3D%2258.3%22%20cy%3D%22144.3%22%20r%3D%221.13%22%20opacity%3D%220.86%22%2F%3E%3Ccircle%20cx%3D%2289.2%22%20cy%3D%22108.8%22%20r%3D%221.05%22%20opacity%3D%220.78%22%2F%3E%3Ccircle%20cx%3D%22137.9%22%20cy%3D%22208.0%22%20r%3D%221.77%22%20opacity%3D%220.58%22%2F%3E%3Ccircle%20cx%3D%2243.9%22%20cy%3D%2237.0%22%20r%3D%222.12%22%20opacity%3D%220.72%22%2F%3E%3Ccircle%20cx%3D%22177.5%22%20cy%3D%22225.7%22%20r%3D%221.98%22%20opacity%3D%220.96%22%2F%3E%3Ccircle%20cx%3D%2247.2%22%20cy%3D%22228.0%22%20r%3D%221.41%22%20opacity%3D%220.46%22%2F%3E%3Ccircle%20cx%3D%22211.7%22%20cy%3D%22144.8%22%20r%3D%221.48%22%20opacity%3D%220.82%22%2F%3E%3Ccircle%20cx%3D%22101.1%22%20cy%3D%2224.9%22%20r%3D%221.32%22%20opacity%3D%220.54%22%2F%3E%3Ccircle%20cx%3D%22143.2%22%20cy%3D%2270.4%22%20r%3D%222.45%22%20opacity%3D%220.81%22%2F%3E%3C%2Fsvg%3E")}
.hero-b::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:var(--dots-grey);background-size:240px 240px;
  opacity:.5;
  -webkit-mask-image:radial-gradient(120% 100% at 50% 40%, #000 55%, transparent 96%);
  mask-image:radial-gradient(120% 100% at 50% 40%, #000 55%, transparent 96%);
}
.hero-b-in{text-align:center;max-width:1080px;margin:0 auto;position:relative}
/* The headline takes the full column. The lede does not: past about 62
   characters a centred paragraph stops being readable as a block and starts
   being read line by line, so it keeps a measure and centres inside the wider
   headline above it. */
.hero-b-in h1{margin-bottom:22px}
.hero-b-in .lede{max-width:62ch;margin:0 auto 30px}
/* The kicker is a plain block and takes text-align from the wrapper. Only the
   notes row needs telling, because it is a flex row. */
.hero-b-in .hero-notes{justify-content:center}

/* Keyword highlights in the hero lede. This reverses an earlier decision, which
   was that emphasis here is a step up in darkness and never a colour. That held
   while the lede sat in a half width column beside a mock; centred across the
   full measure it is a wider block of grey, and near black on grey is too small
   a step to survive at that size. Brand violet on the four phrases gives the
   sentence something to land on. Weight carries it if colour cannot. */
.hero-b-in .lede strong{color:var(--brand-strong);font-weight:650}

/* The strapline. A statement of who the page is for, not an offer and not a
   link, so it carries no hover and no arrow: there is nowhere for a click to
   go. It is a <p>, hence the explicit margin, or the browser default would add
   space above it that the flex layout above cannot see. */
.hero-flag{
  display:inline-flex;align-items:center;gap:10px;margin:0 0 24px;
  padding:6px 16px 6px 6px;border-radius:var(--r-pill);
  background:#fff;border:1px solid var(--line);box-shadow:var(--sh-sm);
  font-size:13.5px;font-weight:500;color:var(--ink-500)}
.hero-flag-tag{
  background:var(--brand);color:#fff;border-radius:var(--r-pill);
  padding:4px 10px;font-size:11px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;white-space:nowrap}

/* The ticker. Two identical runs side by side, translated by exactly half the
   track, so the second arrives where the first started and there is no jump.
   Duration scales with content: four items at this length take about 46s, which
   is slow enough to read a whole item without it feeling like it has stalled. */
.ticker{background:var(--band-2);border-bottom:1px solid var(--line-soft);overflow:hidden}
.ticker-track{display:flex;width:max-content;animation:ticker 46s linear infinite}
.ticker:hover .ticker-track{animation-play-state:paused}
.ticker-run{display:flex;flex:none}
.ticker-run a{
  display:inline-flex;align-items:center;gap:9px;white-space:nowrap;
  padding:9px 26px;font-size:13px;color:var(--ink-500);text-decoration:none}
.ticker-run a:hover{color:var(--ink-900)}
.ticker-run b{
  background:var(--brand-tint);color:var(--brand-strong);
  padding:3px 9px;border-radius:var(--r-pill);
  font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase}
@keyframes ticker{from{transform:translateX(0)}to{transform:translateX(-50%)}}
/* A strip that moves on its own is exactly what this setting is for. Stopped, it
   is still a readable row of links, just not a scrolling one. */
@media (prefers-reduced-motion:reduce){
  .ticker-track{animation:none}
  .ticker{overflow-x:auto}
}

/* The only thing left where the buttons were. It is a cue, not a call to
   action: the widget it points at is the next thing on the page, so this says
   keep going rather than asking for a click that a scroll already does. */
.try-cue{display:inline-flex;align-items:center;gap:9px;margin-top:32px;
  padding:11px 20px;border-radius:var(--r-pill);
  background:var(--brand-tint);color:var(--brand-strong);
  font-size:14.5px;font-weight:650;text-decoration:none;
  border:1px solid var(--brand-ring);
  transition:background .16s ease,transform .16s ease}
.try-cue:hover{background:#e7e0fd;transform:translateY(-1px)}
.try-cue .ico{width:16px;height:16px;stroke-width:2.4;animation:cue-bob 2.4s ease-in-out infinite}
@keyframes cue-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(3px)}}

/* The same cue again above the walkthrough, one size down. It is a label rather
   than a link here: the section it points at starts immediately below it, so
   there is nothing to navigate to. Sitting above the h2 it also gives the
   headline back its job of saying what the thing shows. */
.cue-lead{margin:0 0 18px;line-height:1}
.try-cue-sm{margin-top:0;padding:8px 16px;font-size:13.5px;cursor:default}
.try-cue-sm:hover{background:var(--brand-tint);transform:none}
.try-cue-sm .ico{width:14px;height:14px}

/* The live card's standfirst runs the full card, not the 56ch measure every
   other lede on the site keeps. It was wrapping at 687px inside a 1074px holder,
   which left a third of the card empty beside three short lines and made the
   card look mis-set rather than airy. The measure exists to stop long reading
   paragraphs sprawling; this is three sentences directly above the thing they
   describe, so it can have the width. */
#live .lede{max-width:none}

/* ===== HERO LAYOUT C, the peeping demo =====
   Used only by index-hero-c.html. Every rule is a new class or is scoped to that
   page's ids, so index.html cannot be affected.

   The hero is AS TALL AS ITS COPY, and nothing else. It used to claim a share of
   the viewport (72svh) so the demo's top edge would land inside the last sixth of
   the first screen. That share is a hole with a fixed measure of copy in it, so
   every extra pixel of screen height fell into the one gap between the buttons
   and the demo: 120px at 945px tall, 339px at 1250px. Centring the copy only
   moved half of that hole above the headline. Sizing to the copy makes the gap a
   constant on every screen, and the peep then takes whatever height is left,
   which is the right way round: a taller screen should show MORE product, not
   more white.

   So there is no vh, no svh and no phone/desktop split to keep in step here. */
.hero-c{padding:22px 0 0}
.hero-c > .container{width:100%}
/* The one gap between the buttons and the demo, and the only number that sets
   it. Small enough that the demo reads as the next breath after the button
   naming it, not as a separate section. The shared .hero-ctas 22px bottom margin
   is zeroed below, or it escapes the hero (no bottom padding to stop it) and
   silently adds itself to whatever is written here. */
.hero-c + #demo{padding-top:52px}
.hero-ctas-c{display:flex;gap:12px;flex-wrap:wrap;justify-content:center;margin-top:32px;margin-bottom:0}
.hero-ctas-c .ico{width:16px;height:16px}
/* Phones: the hero needs air under the bar that a desktop nav does not, and the
   demo follows immediately because the peep is already lost to the fold. */
@media (max-width:860px){
  .hero-c{padding:72px 0 44px}
  .hero-c + #demo{padding-top:8px}
}

/* The live card on layout C. Heading and standfirst sit on the band above the
   card, so they need the band's ink, and the glow needs something to sit behind.
   White rather than violet: the band is already violet, so a violet bloom on it
   is invisible, and white is the only light in this palette that reads on it. */
.layout-c #live .live-intro{max-width:880px;margin:0 auto 34px;text-align:center;position:relative}
/* h1 to h4 are margin:0 site wide, so the standfirst sat hard against the
   heading with nothing between them. */
.layout-c #live .live-intro h2{font-size:clamp(26px,2.6vw,34px);color:#fff;margin-bottom:16px}
/* A measure, and NOT the 880px the block allows. Centred text filling every
   line to the same width stops reading as a paragraph and starts reading as a
   justified rectangle, and it also makes the first line look indented when it
   happens to fall a character shorter than the two under it. A tighter measure
   gives the rag somewhere to vary. */
.layout-c #live .live-intro .lede{color:rgba(255,255,255,.84);max-width:54ch;margin:0 auto;text-wrap:pretty}
.layout-c #live .live-intro::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  inset:-56px -120px;border-radius:50%;
  background:radial-gradient(closest-side,rgba(255,255,255,.30),transparent 74%)}
/* The card gets the same light behind it, wider and softer, plus a hairline so
   its edge does not dissolve into the bloom. Two shadow layers do the bloom
   rather than one: a tight bright ring reads as an edge, and a wide faint one
   reads as light, and the pair is what stops it looking like a white border. */
.layout-c #live .live{
  position:relative;
  box-shadow:0 2px 8px rgba(5,7,63,.18),0 30px 70px -30px rgba(5,7,63,.45),
    0 0 0 1px rgba(255,255,255,.6),
    0 0 44px 2px rgba(255,255,255,.30),
    0 0 130px 26px rgba(255,255,255,.22)}

/* The WhatsApp teaser sits on the blue band, where the shared .split copy is
   inked for a light background. Only the colours are restated; the layout is
   the same .split .wa-split the WhatsApp page uses. */
#whatsapp-teaser .lede{color:rgba(255,255,255,.82);max-width:52ch}

/* Layout C runs this section light, so the white ink written for the blue band
   has to come back to normal. Kept as an override rather than by rewriting the
   rules above, because the other two homepages still run it blue. */
.layout-c #whatsapp-teaser{position:relative;isolation:isolate;background:var(--band)}
.layout-c #whatsapp-teaser h2{color:var(--ink-900)}
.layout-c #whatsapp-teaser .lede{color:var(--ink-500)}
.layout-c #whatsapp-teaser .ph-caption{color:var(--ink-400)}
/* The hero's grey scatter again, fainter still. This section sits between two
   blue bands and its job is to be the quiet one, so the texture is present but
   only just: .32 against the hero's .5. */
.layout-c #whatsapp-teaser::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:var(--dots-grey);background-size:240px 240px;
  opacity:.32;
  -webkit-mask-image:radial-gradient(120% 100% at 50% 45%, #000 58%, transparent 97%);
  mask-image:radial-gradient(120% 100% at 50% 45%, #000 58%, transparent 97%);
}
#whatsapp-teaser .btn{margin-top:26px}
/* .wa-split .split-media is a flex ROW, which is invisible on the WhatsApp page
   because its phone is an only child. Here there is a caption too, and it landed
   alongside the phone instead of under it. Scoped, not fixed in the shared rule,
   so that page is untouched. */
#whatsapp-teaser .split-media{flex-direction:column;align-items:center}
#whatsapp-teaser .ph-caption{color:rgba(255,255,255,.62)}
.wa-eyebrow{margin:0 0 14px;line-height:1}
@media (max-width:940px){
  /* Copy above the phone rather than beside it, and the phone centres under it. */
  #whatsapp-teaser .split{grid-template-columns:1fr;gap:34px}
}

@media (prefers-reduced-motion:reduce){
  .try-cue .ico{animation:none}
}
@media (max-width:640px){
  .hero-b{padding:72px 0 44px}
  .try-cue{margin-top:26px}
  /* The pill is a flex row, and at this width the tag leaves the sentence about
     200px to wrap in. Tightened, and the arrow goes: the whole pill is the link,
     so the arrow was decoration taking room the words needed. */
  .hero-flag{font-size:12.5px;padding:5px 13px 5px 5px;gap:8px;margin-bottom:22px}
  .hero-flag-tag{font-size:10px;padding:3px 8px}
  .hero-flag .ico{display:none}
  .ticker-run a{padding:8px 18px;font-size:12.5px}
}

/* ===== HERO, SPLIT (the live homepage) =====
   Concept 1 from homepage-concepts.html. Copy on the left, a copy of the live
   Kingswell assistant on the right, so the first screen shows the product
   rather than only describing it. Replaces the centred .hero-b, which is kept
   above for the comparison pages. Generous top and bottom space so it reads as
   a homepage opening rather than the top of an article. */
.hero-split{padding:132px 0 136px;isolation:isolate;overflow:hidden;
  background:
    radial-gradient(900px 520px at 88% 30%,var(--brand-tint),transparent 70%),
    radial-gradient(640px 420px at 0% 100%,#f6f3ff,transparent 70%),
    var(--page)}
.hs-grid{display:grid;grid-template-columns:1.08fr 1fr;gap:56px;align-items:center}
/* Grid items default to min-width:auto, so the card's one-line input would
   otherwise hold the column wider than a phone screen. */
.hs-grid > *{min-width:0}
.hs-copy h1{font-size:clamp(40px,5.2vw,68px);line-height:1.02;letter-spacing:-.04em;margin:0 0 24px}
.hs-accent{background:linear-gradient(90deg,var(--brand),var(--feat));
  -webkit-background-clip:text;background-clip:text;color:transparent}
.hs-copy .hero-flag{margin-bottom:30px}
.hs-copy .lede{margin-bottom:34px}
.hs-copy .hero-ctas{margin-bottom:30px}
.hs-copy .hero-ctas .ico{width:16px;height:16px}

/* The strapline pill, as a link this time: it carries the WhatsApp news. */
.hero-flag-link{text-decoration:none;transition:border-color .16s ease,box-shadow .16s ease}
.hero-flag-link:hover{border-color:var(--brand-ring);box-shadow:var(--sh)}
.hero-flag-link .ico{width:14px;height:14px;color:var(--brand)}

/* The stage leaves room above and below the card for the three tags, so none
   of them ever covers the conversation itself. It also carries the Kingswell
   tokens: the settings the live widget reads for that organisation (teal
   secondary colour, navy robot screen) plus the widget's own greys. */
.hs-stage{position:relative;margin:0;padding:54px 0 58px;
  --kw:#00a38f;
  --kw-ink:#1e293b;
  --kw-line:#e2e8f0;
  --kw-bot:url("data:image/svg+xml,%3Csvg viewBox='0 0 80 92' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='36' y='0' width='8' height='16' rx='4' fill='white'/%3E%3Ccircle cx='40' cy='0' r='7' fill='white'/%3E%3Crect x='6' y='32' width='11' height='20' rx='5.5' fill='white'/%3E%3Crect x='63' y='32' width='11' height='20' rx='5.5' fill='white'/%3E%3Cpath d='M40 14 C18 14 14 30 14 44 L14 68 C14 82 26 90 40 90 C54 90 66 82 66 68 L66 44 C66 30 62 14 40 14Z' fill='white'/%3E%3Crect x='23' y='28' width='34' height='34' rx='9' fill='%231e3a5f'/%3E%3Cellipse cx='33' cy='42' rx='5' ry='6.5' fill='white'/%3E%3Cellipse cx='47' cy='42' rx='5' ry='6.5' fill='white'/%3E%3Cpath d='M31 54 Q40 61 49 54' stroke='white' stroke-width='2.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}

/* The assistant card. A faithful copy of the live floating widget (widget.html,
   #verity-window): coloured header with the robot and the assistant's name,
   the "You're welcome here" access strip, white conversation, input row, and
   the grey "Powered by" footer carrying the Veaivo mark. The header uses
   Kingswell's teal rather than its navy primary, which read as murky here. */
.hc{max-width:440px;margin:0 auto;background:#f8fafc;border:2px solid var(--kw);border-radius:16px;
  overflow:hidden;box-shadow:0 16px 56px rgba(30,58,95,.22);font-size:13.6px;line-height:1.55;color:var(--kw-ink);text-align:left}
.hc-head{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--kw)}
.hc-avatar{width:40px;height:40px;flex:none;border-radius:50%;
  background:rgba(255,255,255,.18) var(--kw-bot) center/70% no-repeat}
.hc-title{flex:1;line-height:1.25}
.hc-title b{display:block;color:#fff;font-size:14.4px;font-weight:700}
.hc-title small{color:rgba(255,255,255,.85);font-size:11.5px}
.hc-head svg{width:18px;height:18px;fill:none;stroke:rgba(255,255,255,.75);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.hc-notice{display:flex;align-items:center;gap:6px;padding:7px 12px;background:#f1f5f9;border-bottom:1px solid var(--kw-line);
  font-size:11.2px;color:#94a3b8}
.hc-notice span{flex:1;text-align:center}
.hc-notice svg{width:14px;height:14px;fill:none;stroke:#94a3b8;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.hc-body{display:flex;flex-direction:column;justify-content:flex-end;gap:12px;
  padding:14px 16px 18px;background:#fff;min-height:340px}
.hc-sender{font-size:11.2px;font-weight:600;color:#64748b;margin:0 0 -8px 34px}
.hc-msg{max-width:82%;padding:10px 14px}
.hc-q{align-self:flex-end;background:var(--kw);color:#fff;border-radius:16px 16px 5px 16px}
/* Bot answers carry the small robot avatar at their bottom left, as live. */
.hc-a{position:relative;align-self:flex-start;margin-left:34px;background:#fff;border:1px solid var(--kw-line);
  border-radius:16px 16px 16px 5px;box-shadow:0 1px 3px rgba(0,0,0,.06)}
.hc-a::before{content:"";position:absolute;left:-34px;bottom:0;width:26px;height:26px;border-radius:50%;
  background:var(--kw) var(--kw-bot) center/70% no-repeat}
/* The not-yet-typed part of the answer is laid out but hidden (app.js), so the bubble
   is its finished size from the start and the page never shifts while it types. */
.hc-a-live{width:78%}
.hc-rest{visibility:hidden}
.hc-pills{display:flex;flex-wrap:wrap;gap:6px}
.hc-pills span{font-size:12px;background:#f6f7f9;border:1px solid #e3e6ec;color:#4e5666;border-radius:999px;padding:5px 11px}
.hc-bar{display:flex;align-items:center;gap:8px;padding:12px;background:#f8fafc;border-top:1px solid #cbd5e1}
.hc-input{flex:1;min-width:0;border:1.5px solid #cbd5e1;border-radius:10px;padding:9px 13px;background:#fff;color:#94a3b8;
  font-size:13.6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hc-send{width:38px;height:38px;flex:none;border-radius:10px;background:var(--kw);display:grid;place-items:center}
.hc-send svg{width:16px;height:16px;fill:#fff}
.hc-foot{display:flex;align-items:center;justify-content:center;min-height:28px;background:#f8fafc;
  border-top:1px solid #cbd5e1;font-size:10.4px;color:#94a3b8}
.hc-foot svg{width:18px;height:18px;margin:0 4.8px 0 4px}
.hc-foot b{font-weight:800;letter-spacing:-.01em;color:#1e3a5f}
.hc-foot .hc-ask{color:var(--brand);margin-left:.22em}

.hs-tag{position:absolute;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;
  background:#fff;border-radius:12px;padding:9px 13px;box-shadow:var(--sh-card);
  font-size:12.5px;font-weight:600;color:var(--ink-700)}
.hs-tag i{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  font-style:normal;font-size:11px;font-weight:700;color:#fff}
.hs-tag i .ico{width:13px;height:13px;stroke-width:2.6}
.hs-tag-1{top:0;left:6%}.hs-tag-1 i{background:var(--good)}
.hs-tag-2{bottom:0;left:2%}.hs-tag-2 i{background:var(--ink-700)}
.hs-tag-3{bottom:0;right:2%}.hs-tag-3 i{background:var(--brand)}

/* ===== THE ASK BAR SECTION =====
   Concept 3 from homepage-concepts.html, on the blue band with the real inline
   assistant inside a white card. */
.ask{padding:96px 0 84px}
.ask-in{max-width:880px;margin:0 auto;text-align:center}
.ask-in h2{margin-bottom:14px}
#live.ask .ask-in > .lede{margin:0 auto 34px;max-width:54ch}
.ask-card{text-align:left}
.ask-try{display:flex;justify-content:center;align-items:center;gap:8px;margin:0 auto 14px;
  max-width:none;font-size:14px;color:var(--ink-400);min-height:24px}
.ask-typed{color:var(--ink-900);font-weight:500}
.ask-typed::after{content:"";display:inline-block;width:2px;height:1em;margin-left:2px;
  vertical-align:-2px;background:var(--brand);animation:ask-blink 1s steps(1) infinite}
@keyframes ask-blink{50%{opacity:0}}
.ask-lang{font-size:10.5px;font-weight:700;letter-spacing:.08em;color:var(--brand-strong);
  background:var(--brand-tint);border-radius:var(--r-pill);padding:2px 8px}
/* Holds the embed's height before it loads, so the card does not jump. */
.ask-shell{min-height:68px}
.ask .chips{justify-content:center;margin-top:20px}
.ask-stats{display:flex;justify-content:center;flex-wrap:wrap;gap:20px 64px;margin-top:40px;
  font-size:13.5px;color:rgba(255,255,255,.76)}
.ask-stats strong{display:block;font-size:30px;letter-spacing:-.03em;color:#fff;line-height:1.2}

@media (max-width:940px){
  .hero-split{padding:72px 0 80px}
  .hs-grid{grid-template-columns:1fr;gap:12px}
  .ask{padding:72px 0 64px}
}
@media (max-width:560px){
  /* No room beside the card at this width, so the tags go rather than cover it. */
  .hs-tag{display:none}
  .hs-stage{padding:28px 0 0}
  .hc-body{min-height:0}
  .hs-copy .hero-ctas .btn{flex:1 1 100%;justify-content:center}
  .ask-stats{gap:18px 32px}
}
@media (prefers-reduced-motion:reduce){
  .ask-typed::after{animation:none}
}
