/* ============================================================
 * PRODUCT PAGE — shared, colour-agnostic template (design system v2)
 * ------------------------------------------------------------
 * One stylesheet drives every product page (One, Classroom, Sync).
 * The OnSite page keeps its own onsite-v2.css (it was built and
 * signed off first); this sheet is the template for its siblings.
 *
 * Each page sets its identity palette on <body class="pp pp--one">
 * (etc). Everything below reads those five variables, so a new
 * product page is just a colour block + copy — never a CSS rewrite.
 *
 * Structure mirrors OnSite: UI-led hero tile · feature grid ·
 * alternating media rows · accent colour band · pricing board.
 * Loads AFTER home-v2.css (uses its --hv2-ease, .rv reveals,
 * .crests, nav, footer, contact band).
 * ============================================================ */

/* ---------- palette: default = OnSite violet, overridden per page ---------- */
.pp {
  --pp-1: #F6F4FF;                     /* tint wash (hero, chips-on-light) */
  --pp-2: #E8E4F9;                     /* tint 2 (chip bg, borders) */
  --pp-3: #8572DA;                     /* mid (highlights on dark) */
  --pp-4: #614DBA;                     /* accent — the true brand identity colour (logo, decoration) */
  --pp-ink: #614DBA;                   /* text-safe shade: white text sits on it, and it sits on tints — WCAG AA */
  --pp-dark: #4B3B9C;                  /* darker (button hover) */
  --pp-glow: rgba(97, 77, 186, 0.42);  /* badge / accent shadow */
}
/* --pp-ink is a deep, AA-passing shade of each identity colour used for every
   text-bearing surface (buttons, chips, accent band, coloured text on tints,
   icons). --pp-4 stays the bright brand colour for the hero logo. For OnSite
   violet and Classroom blue the accent is already dark enough, so ink == accent. */
/* 3 Aug 2026: One and the Parent & Carer app SWAPPED palettes — "the parent
   app colour should change to the teal used in one product and the one product
   should be blue". One now leads with the deep sky; the app takes the teal.
   Classroom keeps royal blue, so "blue" here means the deep sky, not Classroom's.
   --pp-ink still carries every text-bearing surface: deep sky #1B88C8 fails AA
   behind white text at 3.89:1, #116490 passes at 6.5:1. */
.pp--one {
  --pp-1: #E7F5FD; --pp-2: #CBE8F8; --pp-3: #5BB4E6;
  --pp-4: #1B88C8; --pp-ink: #116490; --pp-dark: #0E5578; --pp-glow: rgba(27, 136, 200, 0.42);
}
.pp--classroom {
  --pp-1: #ECEFFB; --pp-2: #D6DEF7; --pp-3: #6E8AE8;
  --pp-4: #2248C0; --pp-ink: #2248C0; --pp-dark: #1A3A9E; --pp-glow: rgba(34, 72, 192, 0.42);
}
.pp--sync {
  --pp-1: #E7F5FD; --pp-2: #CBE8F8; --pp-3: #5BB4E6;
  --pp-4: #1B88C8; --pp-ink: #116490; --pp-dark: #0E5578; --pp-glow: rgba(27, 136, 200, 0.42);
}
/* Parent & Carer app — trialled the app's own real teal first, but it
   collided with One's identity colour, so switched to the brand palette's
   pink family instead (--ge-pink-3/4 in colors_and_type.css) to keep every
   product visually distinct. (Rebecca, 24 Jul) */
/* Parent app now shares ONE's teal palette exactly (Rebecca, 29 Jul: "revert
   the parent app page and nav tile to the same colour as the one product").
   Values are copied from .pp--one above rather than aliased, so One can still
   be retuned without silently dragging the Parent app with it.
   --pp-ink stays the deep #00736B: teal #00B1A7 is too light to carry white
   text (2.7:1), which is why the template routes every text-bearing surface
   through --pp-ink. Do not "simplify" by pointing those at --pp-4. */
/* Deep sky — the colour Sync used before it was removed. Rebecca, 3 Aug:
   unify Parent & Carer on it, which also ends the old collision where this
   page led with One's teal. Values are Sync's own, so already AA-checked. */
.pp--parent {
  --pp-1: #E7F8F6; --pp-2: #C9F0EC; --pp-3: #2FC7BD;
  --pp-4: #00B1A7; --pp-ink: #00736B; --pp-dark: #005F58; --pp-glow: rgba(0, 177, 167, 0.42);
}

/* ============================================================
 * HERO — rounded identity-tint tile, copy left, UI peeking in
 * ============================================================ */
.pp-hero { padding-top: clamp(10px, 1.4vw, 18px); }
.pp-hero__frame {
  position: relative;
  overflow: hidden;                          /* crops the screenshot at the tile edge */
  margin-inline: clamp(10px, 1.6vw, 22px);
  border-radius: clamp(20px, 2.5vw, 34px);
  background:
    radial-gradient(100% 115% at 88% 4%, var(--pp-2) 0%, rgba(255, 255, 255, 0) 58%),       /* colour pools behind the UI */
    linear-gradient(155deg, var(--pp-1) 0%, #FCFEFE 82%);                                    /* soft wash, lighter behind copy */
  min-height: max(520px, 70svh);
  display: flex;
  align-items: center;
}

.pp-hero__copy {
  position: relative;
  z-index: 2;
  max-width: 48%;
  padding: clamp(28px, 4.5vw, 72px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.pp-hero__logo {
  height: clamp(42px, 4.2vw, 60px);
  width: auto;
  display: block;
  margin-bottom: 22px;
}
.pp-eyebrow {
  display: inline-block;
  margin-bottom: 16px;
  padding: 8px 18px;
  border-radius: 999px;
  background: var(--pp-2);
  color: var(--pp-ink);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.pp-hero__copy h1 {
  margin: 0 0 18px;
  font-size: clamp(34px, 3.6vw, 58px);
  line-height: 1.28;                         /* opens the gap so stacked highlight lines never touch */
}
/* site-signature pill, not the product tint (Rebecca, 4 Aug — every highlight
   pill matches the home hero's). Product colour still leads everything else. */
.pp-hero__copy h1 .mark {
  background: var(--ge-blue-3, #D9F4FF);
  color: var(--ge-blue, #1B367E);
  padding: 0 0.16em;
  border-radius: 0.2em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.pp-hero__lede {
  margin: 0 0 28px;
  max-width: 48ch;
  font-size: clamp(15.5px, 1.3vw, 18px);
  line-height: 1.6;
  color: #4A5876;
}
.pp-hero__actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* identity-colour primary button (product colour leads on product pages) */
.pp-btn {
  background: var(--pp-ink);
  color: #fff;
  border: none;
}
.pp-btn:hover { background: var(--pp-dark); color: #fff; }
.pp-btn .btn__arrow { background: rgba(255, 255, 255, 0.16); color: #fff; }

/* the UI screenshot cluster — anchored bottom-right, cropped by the tile edge */
.pp-hero__shot {
  position: absolute;
  right: clamp(-40px, -2vw, -20px);
  bottom: clamp(-20px, -1vw, 18px);          /* sits higher in the tile — more of the UI on show */
  width: min(56%, 900px);
  z-index: 1;
}
.pp-hero__screen {
  background: #fff;
  border-radius: clamp(16px, 1.8vw, 26px);
  padding: clamp(9px, 1vw, 14px);            /* white bezel */
  box-shadow: 0 30px 70px rgba(15, 20, 56, 0.25);
  opacity: 0;
  transform: translateY(60px) rotate(-2deg);
  animation: pp-in 620ms var(--hv2-ease) 150ms forwards;
}
.pp-hero__screen > img,
.pp-hero__screen > .pp-slot {
  width: 100%;
  height: auto;
  display: block;
  border-radius: clamp(9px, 1vw, 14px);
}

/* feature tabs — label each screen and let visitors click to jump */
.pp-hero__tabs {
  display: flex;
  flex-wrap: wrap;                 /* wide cards keep one row; narrow cards wrap, so no tab hides */
  gap: clamp(4px, 0.5vw, 7px);
  margin-bottom: clamp(8px, 0.9vw, 12px);
}
.pp-hero__tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 7px 13px;
  border: 1px solid var(--pp-2);
  border-radius: 999px;
  background: #fff;
  color: var(--pp-ink);
  font: inherit;
  font-size: clamp(11px, 0.86vw, 13px);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background 200ms var(--hv2-ease), color 200ms var(--hv2-ease),
    border-color 200ms var(--hv2-ease);
}
.pp-hero__tab svg { width: 14px; height: 14px; flex: 0 0 auto; }
.pp-hero__tab:hover { border-color: var(--pp-ink); background: var(--pp-1); }
.pp-hero__tab.is-on {
  background: var(--pp-ink);
  border-color: var(--pp-ink);
  color: #fff;
}
.pp-hero__tab:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(47, 183, 241, 0.45);
}

/* floating variant — tabs sit above the card as standalone nav chips
   (on the tint, not on the white bezel), so they read as "our" navigation */
.pp-hero__tabs--float {
  margin-bottom: clamp(11px, 1.3vw, 16px);
  opacity: 0;
  animation: pp-fade 500ms var(--hv2-ease) 260ms forwards;
}
.pp-hero__tabs--float .pp-hero__tab {
  border-color: transparent;
  box-shadow: 0 6px 18px rgba(15, 20, 56, 0.12);
}
.pp-hero__tabs--float .pp-hero__tab:hover {
  border-color: transparent;
  background: #fff;
  box-shadow: 0 10px 24px rgba(15, 20, 56, 0.18);
}
.pp-hero__tabs--float .pp-hero__tab.is-on { box-shadow: 0 8px 22px var(--pp-glow); }
@keyframes pp-fade { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .pp-hero__tabs--float { animation: none; opacity: 1; }
}

/* crossfade slideshow — several screens flick through inside the bezel */
.pp-hero__frames {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: clamp(9px, 1vw, 14px);
  overflow: hidden;
}
.pp-hero__frames .pp-hero__slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  opacity: 0;
  transition: opacity 800ms var(--hv2-ease);
}
.pp-hero__frames .pp-hero__slide.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .pp-hero__frames .pp-hero__slide { transition: none; }   /* JS also holds on the first slide */
}
@keyframes pp-in { to { opacity: 1; transform: translateY(0) rotate(0deg); } }
@media (prefers-reduced-motion: reduce) {
  .pp-hero__screen { animation: none; opacity: 1; transform: none; }
}

/* ============================================================
 * HERO VARIANT — text-first stack (trial, July 2026)
 * Copy sits centred across the full tile width so the words lead;
 * the screenshot drops below and straddles out of the tile into
 * the next band (the site's signature seam-breaker).
 * ============================================================ */
.pp { --pp-hang: clamp(48px, 7vw, 110px); }   /* on the page root: the hero AND the next band both read it */
.pp-hero--stack .pp-hero__frame {
  flex-direction: column;
  align-items: center;
  min-height: 0;
  overflow: visible;                          /* lets the screenshot hang out of the tile */
  background:
    radial-gradient(90% 62% at 50% 100%, var(--pp-2) 0%, rgba(255, 255, 255, 0) 62%),  /* colour pools behind the device */
    linear-gradient(180deg, var(--pp-1) 0%, #FCFEFE 78%);                               /* calm and light behind the words */
}
.pp-hero--stack .pp-hero__copy {
  max-width: min(92%, 880px);
  align-items: center;
  text-align: center;
  padding: clamp(40px, 5.5vw, 84px) clamp(20px, 3vw, 40px) 0;
}
.pp-hero--stack .pp-hero__logo { margin-inline: auto; }
.pp-hero--stack .pp-hero__copy h1 { font-size: clamp(38px, 4.6vw, 72px); }  /* full width now — the headline can breathe */
.pp-hero--stack .pp-hero__copy h1 .mark { white-space: nowrap; }            /* keep the highlighted phrase on one line */
.pp-hero--stack .pp-hero__lede { margin-inline: auto; }
.pp-hero--stack .pp-hero__actions { justify-content: center; }
.pp-hero--stack .pp-hero__shot {
  position: static;                           /* flows under the copy instead of pinning right */
  width: min(88%, 1080px);
  margin: clamp(30px, 4vw, 52px) auto calc(-1 * var(--pp-hang));
}
.pp-hero--stack .pp-hero__tabs { justify-content: center; }
.pp-hero--stack + .pp-incl { padding-top: calc(clamp(56px, 7vw, 100px) + var(--pp-hang)); }  /* clears the hanging device */

/* ---------- image placeholder (used until real screenshots/photos land) ---------- */
.pp-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  aspect-ratio: 16 / 10;
  background:
    repeating-linear-gradient(-45deg, transparent 0 22px, rgba(255,255,255,0.5) 22px 44px),
    var(--pp-1);
  border: 1px dashed var(--pp-3);
  border-radius: 16px;
  color: var(--pp-ink);
  text-align: center;
  padding: 24px;
}
.pp-slot svg { width: 34px; height: 34px; opacity: 0.9; }
.pp-slot span { font-size: 13px; font-weight: 700; letter-spacing: 0.04em; opacity: 0.85; }

/* ============================================================
 * FEATURE GRID — "Everything in [product]." icon tiles
 * ============================================================ */
.pp-incl { background: var(--ge-bg-warm, #F7F6F3); padding: clamp(56px, 7vw, 100px) 0; }
.pp-incl .bandhead { padding-top: 0; }
.pp-incl__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 1.8vw, 26px);
  margin-top: clamp(32px, 3.5vw, 52px);
}
.pp-feat {
  background: #fff;
  border: 1px solid #E6ECF4;
  border-radius: 24px;
  padding: clamp(24px, 2.4vw, 34px);
  transition: transform 220ms var(--hv2-ease), box-shadow 220ms var(--hv2-ease);
}
.pp-feat:hover { transform: translateY(-6px); box-shadow: 0 22px 48px rgba(15, 20, 56, 0.12); }
.pp-feat__ico {
  width: 48px; height: 48px; border-radius: 13px;
  display: grid; place-items: center;
  background: var(--pp-1);
  color: var(--pp-ink);
  margin-bottom: 14px;
  transition: transform 220ms var(--hv2-ease);
}
.pp-feat:hover .pp-feat__ico { transform: rotate(-8deg); }   /* the site "handshake" micro-tilt */
.pp-feat__ico svg { width: 22px; height: 22px; }
.pp-feat h3 { margin: 0 0 8px; font-size: 18px; color: var(--ge-navy, #0F1438); }
.pp-feat p { margin: 0; font-size: 14.5px; line-height: 1.55; color: #4A5876; }

/* ============================================================
 * ALTERNATING ROWS — chip + headline + points | media
 * ============================================================ */
.pp-rows { background: #fff; padding: clamp(56px, 7vw, 100px) 0 clamp(72px, 9vw, 120px); overflow-x: hidden; } /* contains the media slide-in reveal on narrow screens */
.pp-rows .bandhead { padding-top: 0; }
.pp-ways { display: flex; flex-direction: column; gap: clamp(48px, 6vw, 96px); }
.pp-way {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: center;
}
.pp-way:nth-child(even) .pp-way__copy { order: 2; }
.pp-way:nth-child(even) .pp-way__media { order: 1; }
.pp-way__chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 11px 22px;
  border-radius: 999px;
  background: var(--pp-ink);
  color: #fff;
  font-size: 15.5px;
  font-weight: 700;
  margin-bottom: 16px;
}
.pp-way__chip svg { width: 18px; height: 18px; }
.pp-way__copy h3 {
  margin: 0 0 16px;
  font-size: clamp(24px, 2.3vw, 34px);
  letter-spacing: -0.01em;
  color: var(--ge-navy, #0F1438);
}
.pp-way__copy .psl__points { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 12px; }
.pp-way__copy .psl__points li { display: flex; gap: 12px; font-size: 16px; line-height: 1.5; color: #2A3352; }
.pp-way__copy .psl__points a { color: var(--pp-ink); font-weight: 700; }
.pp-way__copy .psl__points a:hover { color: var(--ge-navy, #0F1438); }
.pp-way__copy .psl__tick {
  flex: none;
  width: 22px; height: 22px; margin-top: 1px;
  border-radius: 999px;
  display: grid; place-items: center;
  background: var(--ge-navy, #0F1438);
  color: #fff;
}
.pp-way__copy .psl__tick svg { width: 12px; height: 12px; }

/* media: real photo+screenshot when they land; slot placeholder until then */
.pp-way__media { position: relative; }
.pp-way__photo {
  width: 100%;
  aspect-ratio: 16 / 11;
  object-fit: cover;
  border-radius: 24px;
  display: block;
  box-shadow: 0 22px 52px rgba(15, 20, 56, 0.16);
}
.pp-way__media .pp-slot { aspect-ratio: 16 / 11; border-radius: 24px; }

/* entrance: media slides in from its side */
.pp-way.rv .pp-way__media { opacity: 0; transform: translateX(30px); transition: opacity 460ms var(--hv2-ease), transform 460ms var(--hv2-ease); }
.pp-way:nth-child(even).rv .pp-way__media { transform: translateX(-30px); }
.pp-way.rv.in .pp-way__media { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .pp-way.rv .pp-way__media { opacity: 1; transform: none; transition: none; }
}
@media (max-width: 900px) {
  .pp-way { grid-template-columns: 1fr; }
  .pp-way:nth-child(even) .pp-way__copy { order: 1; }
  .pp-way:nth-child(even) .pp-way__media { order: 2; }
}

/* ============================================================
 * ACCENT BAND — full-width identity colour-block statement
 * ============================================================ */
.pp-band {
  position: relative;
  overflow: hidden;
  background: var(--pp-ink);
  color: #fff;
  /* 5 Aug: was clamp(64px, 8vw, 120px) — 115px at 1440 against the site's 140.
     Shared by all four product pages so they move together, which is the point:
     this was one of the last bands sitting off the standard rhythm. */
  padding: clamp(80px, 9vw, 140px) 0;
}
.pp-band__inner {
  display: flex;
  align-items: center;
  justify-content: center;   /* button removed — copy now centres */
  flex-wrap: wrap;
  gap: clamp(20px, 3vw, 44px);
  position: relative;
  z-index: 1;
}
.pp-band__copy { max-width: 62ch; text-align: center; }
/* ⚠ NAVY ON EVERY PRODUCT PAGE (5 Aug: "can you make sure that all the product
   page tree diagrams look like this tile"). It used to take --pp-ink, so the
   band was a different colour on each page — deep sky on One, violet on OnSite,
   royal blue on Classroom, teal on Parent & Carer.
   OnSite went navy first and she asked for the rest to match it. It reads
   better as one colour too: the diagram inside shows the OTHER products, so
   painting the tile in the current product's colour was claiming the whole
   family for whichever page you happened to be on.
   The per-product colour survives where it belongs — the logo chip at the top of
   the tree, and the button. The OnSite-specific override in onsite-v2.css is now
   redundant but harmless; it sets the same value. */
.pp-band { background: var(--ge-navy, #0F1438); }
.pp-band h2 { margin: 0 0 12px; color: #fff; }
.pp-band p { margin: 0; font-size: clamp(16px, 1.3vw, 19px); line-height: 1.6; color: rgba(255, 255, 255, 0.9); }
.pp-band .btn { flex: none; }
/* ⚠ REMOVED 5 Aug: "remove the watermark". It went 0.08 → 0.05 earlier the same
   day when watermarks were softened across the product pages, then off entirely.
   display:none rather than deleting the rules, so it is one line to bring back;
   the positioning is preserved below. */
.pp-band__wm { display: none; position: absolute; right: -3%; bottom: -34%; width: 30%; opacity: 0.05; pointer-events: none; }
.pp-band__wm img { width: 100%; height: auto; }
/* white ghost button on the colour block */
.pp-band .pp-btn--onband { background: #fff; color: var(--pp-ink); }
.pp-band .pp-btn--onband:hover { background: #EAF1F8; color: var(--pp-ink); }
.pp-band .pp-btn--onband .btn__arrow { background: var(--pp-ink); color: #fff; }

/* ============================================================
 * TESTIMONIAL — navy card (quote lands here when supplied)
 * ============================================================ */
/* section wash -> the home page's off-white; product colour stays on the
   quote card, chips and marks inside it (3 Aug) */
.pp-says { background: var(--ge-bg-warm, #F7F6F3); padding: clamp(64px, 8vw, 110px) 0; }
.pp-quote {
  position: relative;
  overflow: hidden;
  max-width: 900px;
  margin: 0 auto;
  background: var(--ge-navy, #0F1438);
  color: #fff;
  border-radius: 28px;
  padding: clamp(36px, 4.5vw, 64px);
  box-shadow: 0 24px 56px rgba(15, 20, 56, 0.2);
}
.pp-quote blockquote {
  margin: 0;
  max-width: 46ch;
  font-size: clamp(20px, 2vw, 29px);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.4;
}
.pp-quote .q-hl { color: var(--pp-3); }
.pp-quote figcaption { margin-top: 20px; font-size: 14px; opacity: 0.75; }
.pp-quote__wm { position: absolute; right: -5%; bottom: -30%; width: 32%; opacity: 0.04;  /* 5 Aug: watermark opacities cut ~40% ("can we make the watermarks in the product and school type pages fainter"). Was 0.06. */; pointer-events: none; }
.pp-quote__wm img { width: 100%; height: auto; }
.pp-quote > *:not(.pp-quote__wm) { position: relative; z-index: 1; }

/* ============================================================
 * PRICING / FINAL — leaves room for the footer contact card
 * ============================================================ */
.pp-final {
  background: #fff;
  padding: clamp(56px, 7vw, 96px) 0 clamp(280px, 22vw, 380px);
}
.pp-price { max-width: 720px; margin: 0 auto; text-align: center; }
.pp-price__eyebrow {
  display: inline-block;
  margin-bottom: 14px;
  padding: 8px 18px;
  border-radius: 999px;
  background: var(--pp-1);
  color: var(--pp-ink);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.pp-price h2 { margin: 0 0 14px; color: var(--ge-navy, #0F1438); }
.pp-price > p { margin: 0 0 26px; font-size: 16.5px; line-height: 1.65; color: #4A5876; }
.pp-price > p a { color: var(--pp-ink); font-weight: 700; }
.pp-price > p a:hover { color: var(--ge-navy, #0F1438); }
.pp-price__eyebrow-sm { display: block; font-size: 12.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--pp-ink); margin-bottom: 8px; }
.pp-price__amount {
  margin: 0;
  font-size: clamp(42px, 4.4vw, 62px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--pp-ink);
}
.pp-price__amount span { font-size: 0.36em; font-weight: 700; color: #4A5876; }
.pp-price__per { margin: 10px 0 0; font-size: 15.5px; color: #4A5876; }
.pp-price__then { margin: 16px 0 0; font-size: 14px; color: #6B7689; }


/* ---------- all-in-one pricing card: price · divider · included · CTA ---------- */
.pp-card {
  max-width: 680px;
  margin: clamp(28px, 3vw, 40px) auto 0;
  background: var(--pp-1);
  /* stroke removed 3 Aug, same reason as .pv3-ben. This one keeps no shadow:
     unlike the white benefit tiles, its --pp-1 tint fill is visibly different
     from the band behind it, so it still reads as a card on its own. */
  border-radius: 24px;
  padding: clamp(28px, 3vw, 44px);
  text-align: center;
}
.pp-card__inc {
  margin-top: clamp(24px, 2.6vw, 34px);
  padding-top: clamp(24px, 2.6vw, 34px);
  border-top: 1px solid var(--pp-2);
}
.pp-card__inc-title {
  margin: 0 0 clamp(16px, 1.8vw, 22px);
  font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--pp-ink);
}
.pp-card__list {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 11px clamp(20px, 3vw, 40px);
  text-align: left;
}
.pp-card__list li { display: flex; align-items: flex-start; gap: 10px; font-size: 15px; line-height: 1.45; color: #2A3352; }
/* BULLET RULE (3 Aug 2026): "can we change all site bullet points to be navy
   with white ticks. if they are on a navy section make them white with a navy
   tick." Every list bullet below follows it. Excluded on purpose: the comparison
   matrix's Included/Not-included marks (a data cell, not a bullet) and the ticks
   drawn inside the fake app screenshots (they're product UI, not page furniture).
   */
.pp-included__tick {
  flex: none; width: 21px; height: 21px; margin-top: 1px;
  border-radius: 999px;
  display: grid; place-items: center;
  background: var(--ge-navy, #0F1438);
  color: #fff;
}
.pp-included__tick svg { width: 12px; height: 12px; }
.pp-card__cta { margin-top: clamp(24px, 2.6vw, 34px); width: 100%; justify-content: center; }
@media (max-width: 560px) { .pp-card__list { grid-template-columns: 1fr; } }

/* ============================================================
 * RESPONSIVE
 * ============================================================ */
@media (max-width: 1020px) {
  .pp-hero__frame { flex-direction: column; align-items: stretch; min-height: 0; }
  .pp-hero__copy { max-width: 100%; padding-bottom: clamp(24px, 4vw, 40px); }
  .pp-hero__shot {
    position: static;
    width: min(92%, 640px);
    margin: 0 auto clamp(-50px, -5vw, -24px);
  }
  .pp-incl__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  .pp-incl__grid { grid-template-columns: 1fr; }
  .pp-band__inner { flex-direction: column; align-items: flex-start; }
}

/* ============================================================
 * CONNECTED PRODUCTS — visual for the accent band (Rebecca,
 * 29 Jul: "include a visual that shows the connected products",
 * then "I dont need the 'youre here' or the product
 * descriptions. pehaps the one logo tile should go above the 4
 * other tiles").
 *
 * Hub-and-spokes: the product whose page you're on sits alone on
 * top as a solid white tile, joined by a stem to a rule that
 * spans the other three (four before Sync was retired, 3 Aug
 * 2026). Logos only — no labels, no captions.
 * Reuses the existing product wordmark SVGs; the hub uses the
 * identity-colour version because its tile is white.
 * ============================================================ */
.pp-net {
  position: relative;
  z-index: 1;
  margin: clamp(36px, 4.5vw, 60px) auto 0;
  max-width: 860px;
}

/* --- the hub: current product, centred, on its own row --- */
.pp-net__hub {
  display: flex;
  justify-content: center;
  position: relative;
  padding-bottom: clamp(26px, 3vw, 38px);   /* room for the stem */
}
/* stem dropping from the hub to the rule below */
.pp-net__hub::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 2px;
  height: clamp(26px, 3vw, 38px);
  transform: translateX(-1px);
  background: rgba(255, 255, 255, 0.28);
}

/* --- the spokes: the other three, equal columns --- */
.pp-net__row {
  position: relative;
  display: grid;
  /* THREE columns since Sync was retired (3 Aug 2026). This was still 4 while
     every page carried only 3 tiles, so the empty fourth column pushed the row
     left of centre and the rule below overshot to where Sync used to sit
     (Rebecca: "you need to fix these as weve gotten rid of sync"). If a fourth
     product ever arrives, this number AND the divisor in the ::before formula
     must change together. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* gap is a token because the connecting rule's inset is derived from it
     below — the two MUST agree or the rule stops short of the outer ticks. */
  --pp-net-gap: clamp(10px, 1.4vw, 18px);
  gap: var(--pp-net-gap);
  list-style: none;
  margin: 0;
  /* padding-inline: 0 is load-bearing. This is a <ul>, and the UA stylesheet's
     default padding-inline-start: 40px was never reset — it pushed all four
     tiles 40px right INSIDE the row while the rule below, being absolutely
     positioned, measured from the row's padding box. That mismatch made the
     rule overhang on the left and fall ~12px short on the right, which read as
     the line being broken at the Parent & Carer tile (Rebecca, 29 Jul). */
  padding: clamp(18px, 2vw, 26px) 0 0;      /* top = room for the ticks */
}
/* The rule the three hang from, spanning the first tile's centre to the last.
   With N equal columns of width C and gap g in content width W:
   W = 3C + 2g, so the first centre — and therefore the inset — is
   C/2 = (W - 2g) / 6. Derived, not eyeballed, so it stays exact at any width.
   (Was /8 with 3g, for four columns.) */
.pp-net__row::before {
  content: "";
  position: absolute;
  left: calc((100% - 2 * var(--pp-net-gap)) / 6);
  right: calc((100% - 2 * var(--pp-net-gap)) / 6);
  top: 0;
  height: 2px;
  background: rgba(255, 255, 255, 0.28);
}
.pp-net__item { position: relative; }
/* tick joining each tile up to the rule */
.pp-net__item::before {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(-1 * clamp(18px, 2vw, 26px));
  width: 2px;
  height: clamp(18px, 2vw, 26px);
  transform: translateX(-1px);
  background: rgba(255, 255, 255, 0.28);
}

/* --- tiles --- */
.pp-net__chip {
  display: grid;
  place-items: center;
  height: 100%;
  min-height: clamp(58px, 6vw, 76px);
  padding: clamp(14px, 1.6vw, 20px) clamp(12px, 1.6vw, 20px);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.22);
  transition: background 200ms var(--hv2-ease), border-color 200ms var(--hv2-ease), transform 200ms var(--hv2-ease);
}
a.pp-net__chip:hover {
  background: rgba(255, 255, 255, 0.2);
  border-color: rgba(255, 255, 255, 0.45);
  transform: translateY(-3px);
}
a.pp-net__chip:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.55); }
.pp-net__chip img {
  height: clamp(19px, 1.6vw, 25px);
  width: auto;
  max-width: 100%;   /* Parent & Carer's lockup is ~6.5:1 — cap it so a
                        narrow column scales it down instead of overflowing */
  display: block;
}

/* the hub tile: solid white, a touch larger, identity-colour wordmark */
.pp-net__chip--hub {
  background: #fff;
  border-color: #fff;
  padding-inline: clamp(24px, 3vw, 40px);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.16);
}
.pp-net__chip--hub img { height: clamp(24px, 2.1vw, 32px); }

/* staggered entrance, once */
.pp-net__hub, .pp-net__item { animation: pp-net-in 420ms var(--hv2-ease) both; }
.pp-net__item:nth-child(1) { animation-delay: 120ms; }
.pp-net__item:nth-child(2) { animation-delay: 190ms; }
.pp-net__item:nth-child(3) { animation-delay: 260ms; }
@keyframes pp-net-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

@media (max-width: 720px) {
  /* two columns on phones — the connecting rule/ticks would cut through the
     wrapped tiles, so the hub-on-top arrangement carries the idea alone */
  .pp-net__row { grid-template-columns: repeat(2, minmax(0, 1fr)); padding-top: 0; }
  /* Three tiles in two columns leaves an orphan sitting bottom-LEFT, which
     reads as a mistake. Span it and centre it so the group is a tidy 2-over-1
     pyramid, kept the same width as its siblings. */
  .pp-net__item:last-child:nth-child(odd) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc(50% - var(--pp-net-gap) / 2);
  }
  .pp-net__row::before, .pp-net__item::before { display: none; }
  .pp-net__hub { padding-bottom: clamp(14px, 3vw, 20px); }
  .pp-net__hub::after { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .pp-net__hub, .pp-net__item { animation: none; opacity: 1; transform: none; }
  a.pp-net__chip:hover { transform: none; }
}

/* ============================================================
 * PRICE CARD — ONE WHITE CARD, ALL FOUR PRODUCT PAGES  (5 Aug 2026)
 * "i am not really enjoying these product price tiles" → measured all four →
 * trialled on Parent & Carer → "yes apply to all product pages".
 *
 * WHAT WAS WRONG, measured, in the order it mattered:
 *   1. A card inside a card — a 1216px pale panel holding a 463px saturated one.
 *      The same pattern already stripped from the OnSite testimonial and the
 *      "everything in" tiles today.
 *   2. Both surfaces the SAME HUE on every page — pale sky/sky, pale violet/
 *      violet, pale royal/royal, pale teal/teal. One thing split in half, not
 *      two related things.
 *   3. The pale panel was a section tint in all but name, against the rule that
 *      product colour goes on components only. The home page's pricing is the
 *      proof: three WHITE cards on a WHITE section.
 *   4. Dead space — the right column ended at 286px in a 454px card.
 *   5. Tick discs in two colours inside one tile, and app-store buttons that
 *      were a 7% white wash on the conversion action.
 *
 * ⚠ EVERY SELECTOR CARRIES body.pp, and it is load-bearing. product-v3.css
 * loads AFTER this file on all four pages and holds
 * `.pp-card--split .pp-card__lead { background: var(--pp-ink) }` and
 * `.pp-card--split .pp-card__cta { background: #fff }` at the SAME specificity
 * (0,2,0) — so unprefixed rules here lost on source order and nothing changed.
 * The trial version worked only because `.pp--parent` happened to prefix it.
 * Symptom if this is ever undone: the saturated panel returns and the CTA goes
 * white-on-white at 1:1.
 * ============================================================ */

/* 1 + 2 + 3 — one surface, white, with the site's standard card shadow */
body.pp .pp-final .pp-card--split {
  background: #fff;
  box-shadow: 0 18px 44px rgba(15, 20, 56, 0.10);
  border-radius: var(--tile-radius, 24px);
  padding: clamp(24px, 2.6vw, 40px);
  align-items: stretch;
  gap: clamp(28px, 3.2vw, 56px);
}

/* the price column loses its panel. It is type on the card now, which is what
   lets the price be the biggest thing here instead of the heading above it. */
body.pp .pp-card--split .pp-card__lead {
  background: transparent;
  color: var(--ge-navy, #0F1438);
  border-radius: 0;
  padding: 0;
  /* a hairline instead of a filled block — it separates the two columns without
     making one of them an object */
  border-right: 1px solid #E6ECF4;
  padding-right: clamp(24px, 2.8vw, 48px);
}
/* #8A94A8 measured 3.05:1 on white — fine for a 78px figure, not for 13px
   label text. #6B7689 is 4.6:1 and still clearly secondary. */
body.pp .pp-card--split .pp-card__price .pp-price__eyebrow-sm { color: #6B7689; }
body.pp .pp-card--split .pp-card__price .pp-price__amount {
  /* the one place the product colour appears, and now the largest figure in the
     section — 78px against the section heading's 54 */
  color: var(--pp-ink);
  font-size: clamp(56px, 5.6vw, 78px);
}
body.pp .pp-card--split .pp-card__price .pp-price__amount span { color: #6B7689; }
body.pp .pp-card--split .pp-card__price .pp-price__per { color: #4A5876; }
body.pp .pp-card--split .pp-card__price .pp-price__then { color: #6B7689; }
body.pp .pp-card__assure li { color: #2A3352; }
/* 5 — navy discs, the site-wide rule, on BOTH columns */
body.pp .pp-card__assure svg { color: var(--ge-navy, #0F1438); }

body.pp .pp-card--split .pp-card__inc { padding: 0; }

/* 4 — THE DEAD SPACE. Releasing the columns from a shared height did not fix it,
   because the LEFT column is the taller one: price, assurances and buttons run
   past eleven short list items, so the empty corner simply moved under the list.
   The fix is to let the right column FILL the height the left one sets — the
   list spaces itself out instead of bunching at the top. justify-content on the
   list, not extra padding, so it adapts to however many features a page has. */
body.pp .pp-card--split .pp-card__inc { display: flex; flex-direction: column; }
body.pp .pp-card--split .pp-card__list {
  flex: 1;
  display: grid;
  align-content: space-between;
  gap: clamp(12px, 1.4vw, 20px);
}

/* the CTA button on One, OnSite and Classroom was white-on-ink, which is
   invisible now the panel behind it is white. Filled navy, like every other
   primary button on a pale surface. Parent & Carer has store buttons instead —
   they had a 7% white wash, and get the same treatment. */
body.pp .pp-card--split .pp-card__cta,
body.pp .pp-card__stores .fxb__store {
  background: var(--ge-navy, #0F1438);
  color: #fff;
}
body.pp .pp-card--split .pp-card__cta:hover,
body.pp .pp-card__stores .fxb__store:hover { background: #1B2352; color: #fff; }
body.pp .pp-card--split .pp-card__cta .btn__arrow { background: #fff; color: var(--ge-navy, #0F1438); }

@media (max-width: 860px) {
  /* stacked: the vertical rule becomes a horizontal one */
  body.pp .pp-card--split .pp-card__lead {
    border-right: none;
    border-bottom: 1px solid #E6ECF4;
    padding-right: 0;
    padding-bottom: clamp(24px, 4vw, 32px);
  }
  body.pp .pp-card--split .pp-card__list { align-content: start; }
}


/* ---- OnSite's price block  (5 Aug) ----
 * ⚠ OnSite does not use the shared .pp-price__* markup — it has its own toggle
 * and figure (.os-toggle / .os-price__big), and every part of it was styled
 * white for the ink panel. On the new white card the WHOLE price was invisible:
 * "£379", "+VAT", "per year — your whole school" and the Primary/Secondary
 * toggle all measured 1:1. This is the same trap as the OnSite testimonial —
 * when a panel loses its dark background, every colour inside it has to be
 * re-derived, not just the ones the shared component knows about.
 * These carry body.pp for the same load-order reason as the block above. */
body.pp .pp-card--split .os-toggle {
  /* was a 16% white wash — invisible on white. A pale grey track instead. */
  background: #EDF1F6;
}
body.pp .pp-card--split .os-toggle__seg { color: #4A5876; }
body.pp .pp-card--split .os-toggle__seg:hover:not(.is-active) { background: rgba(15, 20, 56, 0.06); }
body.pp .pp-card--split .os-toggle__seg.is-active {
  background: var(--ge-navy, #0F1438);
  color: #fff;
}
body.pp .pp-card--split .os-price__big { color: var(--pp-ink); }
body.pp .pp-card--split .os-price__vat { color: #6B7689; }
body.pp .pp-card--split .os-price__per { color: #4A5876; }


/* ---- the Secondary toggle brought the panel back  (5 Aug) ----
 * onsite-v2.css has
 *   `.pp--onsite .pp-card--split .pp-card__lead.is-secondary { background: #4B3B9C }`
 * which product-v3.js switches on when you pick Secondary. It exists because the
 * price column used to be a solid ink panel that changed shade per phase.
 * At (0,4,0) it outranks the (0,3,1) rule that made the column transparent, so
 * clicking Secondary repainted the violet panel underneath type that had just
 * been recoloured for white — the price went violet-on-violet and the
 * assurances dark-grey-on-violet. The card only looked right on Primary.
 * Neutralised at (0,4,1). The phase toggle still works; it just no longer
 * repaints a panel that no longer exists. */
body.pp .pp-card--split .pp-card__lead.is-secondary { background: transparent; }
/* and its companion: the active pill's label was forced to #4B3B9C to read on
   that panel. The pill is navy now, so the label is white like Primary's. */
body.pp .pp-card__lead.is-secondary .os-toggle__seg.is-active { color: #fff; }

/* ---- BIGGER HERO PHOTO, PRODUCT PAGES  (5 Aug 2026) ----
 * "i like the image sizes now - can you reflect this on the product pages too."
 * The product heroes measured identically to what the school-type heroes were
 * before the change — 39% of the frame's width, 69% of its height — so the same
 * treatment applies: 86% tall, and a very slightly portrait 0.98:1 aspect, which
 * is what buys the height without the width running into the copy.
 *
 * There is more room here than on the school-type pages: the product copy column
 * is 46% against their 53%, so nothing needs narrowing to make space.
 *
 * ⚠ Percentage height on a FLEX ITEM. .pv3g__photowrap is a flex child of
 * .pv3g__frame--photo (the school-type one was absolutely positioned), so this
 * only resolves because the frame has a definite height from --hero-h. If that
 * ever becomes content-driven the height silently collapses — measure, don't
 * assume.
 * ⚠ The floating stat/pill/chart cards are kept, as on the school-type pages.
 * product-v3.js derives their margins from the photo's height, so they follow it
 * up automatically. */
/* ⚠ MEASURED, NOT ASSUMED — the first attempt used `height: 86%; aspect-ratio:
   0.98/1` exactly as on the school-type pages and it blew the photo out to 86%
   of the frame's WIDTH and 100% of its height, overflowing the card (115% wide
   on Parent & Carer). The school-type wrap is absolutely positioned, so a
   percentage height resolves against the frame; this one is a FLEX ITEM that
   stretches, so the percentage did not resolve and the forced aspect then drove
   the width off the stretched height. Same-looking markup, different layout
   mode — the rule does not port.
   Scaled the wrap's existing svh formula instead, which is what it was already
   using: 50svh → 62svh, and the 340px floor → 420px. That lands the photo at
   about 86% of the frame's height, the same proportion the school-type heroes
   now have, without touching aspect at all — .pv3g__photo already pins its own
   ratio so every product's photo stays the same shape. */
body.pp .pv3g__frame--photo .pv3g__photowrap {
  height: max(420px, 62svh);
}
