/* ============================================================
 * ONSITE — v2 product page (design system v2)
 * First use of the UI-led product hero template (July 2026):
 * violet-1 wash · centred copy · big kiosk screenshot with a
 * phone overlapping, straddling into the proof band below.
 * Then: centre-phone feature spread · four-module bento ·
 * testimonial · Martyn's Law band · pricing note.
 * OnSite identity violet #614DBA leads throughout.
 * (Not to be confused with onsite.css, which belongs to the
 * protected v1 OnSite landing page.)
 * ============================================================ */

/* ---------- hero: rounded violet tile, copy left, kiosk peeking in ---------- */
.os-hero { padding-top: clamp(10px, 1.4vw, 18px); }
.os-hero__frame {
  position: relative;
  overflow: hidden;                          /* crops the kiosk at the tile edge */
  margin-inline: clamp(10px, 1.6vw, 22px);
  border-radius: clamp(20px, 2.5vw, 34px);
  background: var(--ge-violet-1, #F6F4FF);
  min-height: max(540px, 74svh);
  display: flex;
  align-items: center;
}
.os-hero__copy {
  position: relative;
  z-index: 2;
  max-width: 46%;
  padding: clamp(28px, 4.5vw, 72px);
  padding-bottom: clamp(120px, 15vh, 160px);  /* clears the hanging proof cards */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.os-hero__logo {
  height: clamp(44px, 4.4vw, 64px);
  width: auto;
  display: block;
  margin-bottom: 22px;
}
.os-eyebrow {
  display: inline-block;
  margin-bottom: 16px;
  padding: 8px 18px;
  border-radius: 999px;
  background: var(--ge-violet-2, #E8E4F9);
  color: var(--ge-violet-4, #614DBA);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.os-hero__copy h1 {
  margin: 0 0 18px;
  font-size: clamp(34px, 3.6vw, 60px);
  line-height: 1.28; /* opens the gap so stacked highlight lines never touch */
}
/* site-signature pill, not OnSite violet (Rebecca, 4 Aug — every highlight
   pill on the site matches the home hero's pale-sky/blue pair) */
.os-hero__copy h1 .mark {
  background: var(--ge-blue-3, #D9F4FF);
  color: var(--ge-blue, #1B367E);
  padding: 0 0.16em;
  border-radius: 0.2em;
  /* each wrapped line gets its own rounded box, kept short so they sit apart */
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.os-hero__lede {
  margin: 0 0 28px;
  max-width: 48ch;
  font-size: clamp(15.5px, 1.3vw, 18px);
  line-height: 1.6;
  color: #4A5876;
}
.os-hero__actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* violet primary button (identity colour leads on product pages) */
.os-btn {
  background: var(--ge-violet-4, #614DBA);
  color: #fff;
  border: none;
}
.os-btn:hover { background: #4B3B9C; color: #fff; }
.os-btn .btn__arrow { background: rgba(255, 255, 255, 0.16); color: #fff; }

/* the kiosk cluster — anchored to the tile's bottom-right, cropped by its edge */
.os-hero__shot {
  position: absolute;
  right: clamp(-40px, -2vw, -20px);
  bottom: clamp(-90px, -6vw, -50px);
  width: min(56%, 900px);
  z-index: 1;
}
.os-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: os-in 620ms var(--hv2-ease) 150ms forwards;
}
.os-hero__screen img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: clamp(9px, 1vw, 14px);
}
.os-hero__phone {
  position: absolute;
  left: clamp(-56px, -3.5vw, -30px);
  bottom: clamp(24px, 3vw, 56px);
  width: clamp(110px, 12vw, 170px);
  height: auto;
  border-radius: 20px;
  box-shadow: 0 24px 56px rgba(15, 20, 56, 0.35);
  opacity: 0;
  transform: translateY(60px) rotate(4deg);
  animation: os-in 620ms var(--hv2-ease) 330ms forwards;
}
@keyframes os-in { to { opacity: 1; transform: translateY(0) rotate(0deg); } }
@media (prefers-reduced-motion: reduce) {
  .os-hero__screen, .os-hero__phone { animation: none; opacity: 1; transform: none; }
}

/* ---------- everything included: phone centre, features around ---------- */
.os-incl { background: var(--ge-bg-light, #F3F7FA); padding: clamp(80px, 9vw, 140px) 0 clamp(72px, 9vw, 120px); }
.os-incl .bandhead { padding-top: 0; }
.os-incl__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(220px, 0.9fr) minmax(0, 1fr);
  gap: clamp(24px, 3vw, 56px);
  align-items: center;
}
.os-incl__col { display: flex; flex-direction: column; gap: clamp(24px, 3vw, 44px); }
.os-incl__phone { display: flex; justify-content: center; }
/* the mockup video is landscape with the phone centred — crop to a tall
   window so the phone fills the column */
.os-incl__vid {
  width: min(100%, 320px);
  aspect-ratio: 10 / 19;
  border-radius: 28px;
  overflow: hidden;
  box-shadow: 0 30px 70px rgba(15, 20, 56, 0.22);
}
.os-incl__vid video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
.os-feat { position: relative; }
/* the six features animate in around the phone — left column slides in from
   the left, right column from the right, each one a beat after the last */
.os-incl__col .os-feat.rv { transform: translate(-20px, 14px); }
.os-incl__col:last-child .os-feat.rv { transform: translate(20px, 14px); }
.os-incl__col .os-feat.rv.in { transform: none; opacity: 1; }
.os-incl__col .os-feat.rv:nth-child(1) { transition-delay: 0ms; }
.os-incl__col .os-feat.rv:nth-child(2) { transition-delay: 140ms; }
.os-incl__col .os-feat.rv:nth-child(3) { transition-delay: 280ms; }
.os-incl__col:last-child .os-feat.rv:nth-child(1) { transition-delay: 70ms; }
.os-incl__col:last-child .os-feat.rv:nth-child(2) { transition-delay: 210ms; }
.os-incl__col:last-child .os-feat.rv:nth-child(3) { transition-delay: 350ms; }
@media (prefers-reduced-motion: reduce) {
  .os-incl__col .os-feat.rv { transform: none; opacity: 1; transition: none; }
}
.os-feat__ico {
  width: 46px; height: 46px; border-radius: 13px;
  display: grid; place-items: center;
  background: var(--ge-violet-1, #F6F4FF);
  color: var(--ge-violet-4, #614DBA);
  margin-bottom: 12px;
}
.os-feat__ico svg { width: 21px; height: 21px; }
.os-feat h3 { margin: 0 0 6px; font-size: 18px; color: var(--ge-navy, #0F1438); }
.os-feat p { margin: 0; font-size: 14.5px; line-height: 1.55; color: #4A5876; max-width: 34ch; }
.os-feat__badge {
  position: absolute;
  top: 0; left: 56px;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--ge-violet-4, #614DBA);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}

/* ---------- four ways: alternating rows, photo + screenshot pairs ---------- */
/* bottom was clamp(96px, 10vw, 150px) — 144px at 1440, over the 140 standard.
   The price-card band below does not straddle up into this one, so the extra had
   nothing to clear. Both sides on the rhythm now. */
.os-mods { background: #fff; padding: clamp(80px, 9vw, 140px) 0; }
.os-mods .bandhead { padding-top: 0; }

/* ---------- module tab-switcher (TRIAL, 29 Jul 2026) ----------
 * Starling-style icon pills — click one, the matching .os-way
 * below crossfades in. Wraps to a second row rather than
 * scrolling sideways (no horizontal-scroll pattern on this site). */
.os-tabbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0 0 clamp(40px, 5vw, 64px);
}
.os-tab {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 24px;
  border-radius: 999px;
  border: 1px solid var(--ge-neutral-lt3, #E6ECF4);
  background: #fff;
  color: var(--ge-text-secondary, #4A5876);
  font-family: var(--font-sans);
  font-size: 15.5px;
  font-weight: 400;
  transition: background 200ms var(--hv2-ease), border-color 200ms var(--hv2-ease), color 200ms var(--hv2-ease);
}
.os-tab svg { width: 18px; height: 18px; opacity: 0.55; transition: opacity 200ms var(--hv2-ease); }
.os-tab:hover { border-color: var(--ge-violet-3, #8572DA); color: var(--ge-navy, #0F1438); }
.os-tab:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(97, 77, 186, 0.35); }
.os-tab.is-active {
  border-color: var(--ge-violet-4, #614DBA);
  background: var(--ge-violet-4, #614DBA);
  color: #fff;
}
.os-tab.is-active svg { opacity: 1; }

/* .os-way sets display:grid below, which beats the UA stylesheet's
 * `[hidden] { display: none }` on specificity — without this the `hidden`
 * attribute is ignored and all four panels render at once. */
.os-way[hidden] { display: none; }

/* panel crossfade — plays each time a hidden panel is revealed */
@keyframes os-way-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.os-way.is-active { animation: os-way-in 320ms var(--hv2-ease) both; }
@media (prefers-reduced-motion: reduce) {
  .os-way.is-active { animation: none; }
}

/* Two rules that only apply while the tab bar is driving the section. Scoped
 * with :has() so removing .os-tabbar restores the original stacked-rows
 * behaviour on its own, with no CSS to unpick.
 * 1. The tab pill already names the module — the in-panel chip would say
 *    "Reception" twice, one directly under the other.
 * 2. The rows alternated copy/media sides when all four were stacked. With one
 *    panel at a time that alternation makes the layout jump left-right as you
 *    switch tabs, so every panel is pinned to the copy-left arrangement. */
.os-mods:has(.os-tabbar) .os-way__chip { display: none; }
.os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__copy { order: 1; }
.os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__media { order: 2; }
.os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__photo { margin-left: 0; }
.os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__shot { right: 0; left: auto; }
.os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__badge { right: 46%; left: auto; }

.os-ways { display: flex; flex-direction: column; gap: clamp(56px, 7vw, 110px); }
.os-way {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(28px, 4vw, 80px);
  align-items: center;
}
/* rows alternate: even rows put the media on the left */
.os-way:nth-child(even) .os-way__copy { order: 2; }
.os-way:nth-child(even) .os-way__media { order: 1; }

.os-way__chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 11px 22px;
  border-radius: 999px;
  background: var(--ge-violet-4, #614DBA);
  color: #fff;
  font-size: 15.5px;
  font-weight: 700;
  margin-bottom: 16px;
}
.os-way__chip svg { width: 18px; height: 18px; }
.os-way__copy h3 {
  margin: 0 0 16px;
  font-size: clamp(24px, 2.3vw, 34px);
  letter-spacing: -0.01em;
  color: var(--ge-navy, #0F1438);
}
/* the tick-list itself was only ever styled under .pp-way__copy (product-page.css,
   used by One/Classroom/Sync) — OnSite's own .os-way__copy never got the base
   rules, so the bare SVGs rendered at browser-default size (fix: 24 Jul 2026) */
.os-way__copy .psl__points { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 12px; }
/* The li indents with padding + an absolutely-positioned tick rather than
   flex + gap. As a flex container the li turned each of its own text nodes
   into an anonymous flex item, so the Lockdown line's inline link rendered as
   "Built for | Martyn's Law | — auditable" with a 12px gap either side. */
.os-way__copy .psl__points li { position: relative; padding-left: 34px; font-size: 16px; line-height: 1.5; color: #2A3352; }
.os-way__copy .psl__points a { color: var(--ge-violet-4, #614DBA); font-weight: 700; }
.os-way__copy .psl__points a:hover { color: var(--ge-navy, #0F1438); }
.os-way__copy .psl__tick {
  position: absolute;
  left: 0; top: 2px;
  width: 22px; height: 22px;
  border-radius: 999px;
  display: grid; place-items: center;
  /* Navy disc, white glyph — the site standard (Rebecca, 5 Aug: "i noticed the
     navy bullet points with white ticks are consitent across site. ive seen some
     blue ones that need changing"). This was a violet-tint disc with a violet
     glyph. Product colour leads this page, but tick discs are one colour
     site-wide, the same way highlight pills are. */
  background: var(--ge-navy, #0F1438);
  color: #fff;
}
.os-way__copy .psl__tick svg { width: 12px; height: 12px; }

/* media cluster: big photo, screenshot card overlapping, badge at the joint */
.os-way__media { position: relative; padding-bottom: clamp(48px, 5vw, 72px); }
.os-way__photo {
  width: 92%;
  /* 4 Aug photo-ratio standard: 1:1 / 4:3 / 16:9 (see the note in home-v2.css) */
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 24px;
  display: block;
  box-shadow: 0 22px 52px rgba(15, 20, 56, 0.16);
}
.os-way:nth-child(even) .os-way__photo { margin-left: 8%; }
.os-way__shot {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 52%;
  background: #fff;
  border-radius: 18px;
  padding: 8px;                                /* white bezel */
  box-shadow: 0 26px 56px rgba(15, 20, 56, 0.28);
}
.os-way:nth-child(even) .os-way__shot { right: auto; left: 0; }
.os-way__shot img {
  width: 100%;
  aspect-ratio: 16 / 10.5;
  object-fit: cover;
  object-position: top center;
  border-radius: 12px;
  display: block;
}
/* Portrait (mobile) app screenshots — a phone-shaped frame so the WHOLE
   screen shows instead of a cropped landscape band. */
.os-way__shot--phone {
  width: clamp(160px, 27%, 232px);
  padding: 7px;
  border-radius: 30px;
}
.os-way__shot--phone img {
  aspect-ratio: 46 / 100;   /* matches the source phone screens — full screen, no crop */
  object-position: center;
  border-radius: 24px;
}
.os-way__media:has(.os-way__shot--phone) .os-way__badge { display: none; }
.os-way__badge {
  position: absolute;
  right: 46%;
  bottom: clamp(88px, 10vw, 150px);
  width: 56px; height: 56px;
  border-radius: 16px;
  display: grid;
  place-items: center;
  background: var(--ge-violet-4, #614DBA);
  color: #fff;
  box-shadow: 0 14px 34px rgba(97, 77, 186, 0.45);
  z-index: 2;
}
.os-way:nth-child(even) .os-way__badge { right: auto; left: 46%; }
.os-way__badge svg { width: 26px; height: 26px; }

/* entrance: photo slides in from its side, screenshot rotates on, badge pops */
.os-way.rv .os-way__photo { opacity: 0; transform: translateX(-30px); transition: opacity 460ms var(--hv2-ease), transform 460ms var(--hv2-ease); }
.os-way:nth-child(even).rv .os-way__photo { transform: translateX(30px); }
.os-way.rv .os-way__shot { opacity: 0; transform: translateY(28px) rotate(-4deg); transition: opacity 460ms var(--hv2-ease) 160ms, transform 460ms var(--hv2-ease) 160ms; }
.os-way:nth-child(even).rv .os-way__shot { transform: translateY(28px) rotate(4deg); }
.os-way.rv .os-way__badge { opacity: 0; transform: scale(0.5); transition: opacity 300ms var(--hv2-ease) 340ms, transform 300ms var(--hv2-ease) 340ms; }
.os-way.rv.in .os-way__photo,
.os-way.rv.in .os-way__shot { opacity: 1; transform: none; }
.os-way.rv.in .os-way__badge { opacity: 1; transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
  .os-way.rv .os-way__photo, .os-way.rv .os-way__shot, .os-way.rv .os-way__badge {
    opacity: 1; transform: none; transition: none;
  }
}

@media (max-width: 900px) {
  .os-way { grid-template-columns: 1fr; }
  .os-way:nth-child(even) .os-way__copy { order: 1; }
  .os-way:nth-child(even) .os-way__media { order: 2; }
}

/* ---------- testimonial — straddles into the violet band below ---------- */
.os-quote-section { background: var(--ge-violet-1, #F6F4FF); }
.os-quote {
  position: relative;
  z-index: 3;
  overflow: hidden;
  margin: clamp(-64px, -5vw, -40px) 0 clamp(-72px, -5vw, -44px);
  background: var(--ge-navy, #0F1438);
  color: #fff;
  border-radius: var(--tile-radius);   /* was 28px — unified 4 Aug review */
  padding: clamp(36px, 4.5vw, 64px);
  box-shadow: 0 24px 56px rgba(15, 20, 56, 0.2);
}
.os-quote blockquote {
  margin: 0;
  max-width: 46ch;
  font-size: clamp(20px, 2vw, 29px);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.4;
}
.os-quote .q-hl { color: var(--ge-violet-3, #8572DA); }
.os-quote figcaption { margin-top: 20px; display: flex; align-items: center; gap: 14px; }
.os-quote figcaption img { width: 46px; height: 46px; border-radius: 12px; background: #fff; object-fit: contain; padding: 4px; }
.os-quote__name { display: block; font-weight: 700; font-size: 15.5px; }
.os-quote__role { display: block; font-size: 13.5px; opacity: 0.75; }
.os-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; }
.os-quote__wm img { width: 100%; height: auto; }
.os-quote > *:not(.os-quote__wm) { position: relative; z-index: 1; }
/* per-card colour variety — the second testimonial rides on OnSite violet */
.os-quote--violet { background: var(--ge-violet-4, #614DBA); }
.os-quote--violet .q-hl,
.os-quote--violet .os-quote__stats strong { color: #E4DBFF; }
.os-says .os-quote--violet .os-quote__stats strong { color: var(--ge-violet-4, #614DBA); }
/* inline "read more" link used in the lockdown row copy */
.os-way__more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 22px;
  font-weight: 700;
  font-size: 15px;
  color: var(--ge-violet-4, #614DBA);
}
.os-way__more:hover { color: var(--ge-navy, #0F1438); }
.os-way__more svg { width: 18px; height: 18px; }

/* ---------- Martyn's Law band ---------- */
.os-martyn {
  background: var(--ge-violet-4, #614DBA);
  color: #fff;
  padding: clamp(120px, 11vw, 170px) 0 clamp(80px, 9vw, 140px); /* top receives quote straddle */
}
.os-martyn__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: clamp(20px, 3vw, 40px);
}
.os-martyn h2 { margin: 0 0 10px; color: #fff; }
.os-martyn p { margin: 0; max-width: 56ch; font-size: 16px; line-height: 1.6; color: rgba(255, 255, 255, 0.85); }

/* ---------- pricing note / final ---------- */
.os-final {
  background: #fff;
  padding: clamp(80px, 9vw, 140px) 0 clamp(280px, 22vw, 380px); /* room for footer contact card */
}
.os-price {
  max-width: 760px;
  margin: 0 auto;
  text-align: center;
}
.os-price__eyebrow {
  display: inline-block;
  margin-bottom: 14px;
  padding: 8px 18px;
  border-radius: 999px;
  background: var(--ge-violet-1, #F6F4FF);
  color: var(--ge-violet-4, #614DBA);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
/* ---------- pricing: pick your school type, see ONE price ----------
   Replaces the old two-tile row (Rebecca, 24 Jul: "cleaner and easier to
   understand"). A segmented pill — the same switcher pattern as the nav —
   swaps a single large price, so there's never any doubt which one applies. */
.os-toggle {
  display: inline-flex;
  gap: 2px;
  padding: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
}
.os-toggle__seg {
  appearance: none;
  border: none;
  cursor: pointer;
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.88);
  background: transparent;
  border-radius: 999px;
  padding: 9px 22px;
  /* min-height rather than more padding, so the pill can't fall under the 44px
     touch floor whatever the font metrics do (iPad pass, 29 Jul) */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  transition: background 200ms var(--hv2-ease), color 200ms var(--hv2-ease);
}
.os-toggle__seg:hover:not(.is-active) { background: rgba(255, 255, 255, 0.12); }
.os-toggle__seg.is-active {
  background: #fff;
  color: var(--ge-violet-4, #614DBA);
  font-weight: 700;
  box-shadow: 0 2px 8px rgba(15, 20, 56, 0.16);
}
.os-toggle__seg:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(47, 183, 241, 0.55); }
.os-price__big {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: clamp(18px, 2vw, 26px) 0 0;
  font-size: clamp(52px, 5.6vw, 76px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  color: #fff;
}
.os-price__vat { font-size: 0.26em; font-weight: 700; color: rgba(255, 255, 255, 0.72); }
.os-price__per { margin: 12px 0 0; font-size: 15.5px; line-height: 1.5; color: rgba(255, 255, 255, 0.9); }

/* included features, grouped into scannable sets instead of one long wall */
.os-inc { display: flex; flex-direction: column; gap: clamp(18px, 2.1vw, 26px); }
.os-inc__label {
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ge-violet-4, #614DBA);
  opacity: 0.72;
}
.os-inc__list {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px clamp(16px, 2vw, 28px);
}
.os-inc__list li { display: flex; align-items: flex-start; gap: 10px; font-size: 14.5px; line-height: 1.45; color: #2A3352; }
.os-inc__note {
  margin: clamp(20px, 2.4vw, 28px) 0 0;
  padding-top: clamp(18px, 2vw, 24px);
  border-top: 1px solid var(--ge-violet-2, #E8E4F9);
  font-size: 14px;
  line-height: 1.55;
  color: #4A5876;
}
@media (max-width: 620px) { .os-inc__list { grid-template-columns: 1fr; } }
.os-price h2 { margin: 0 0 14px; color: var(--ge-navy, #0F1438); }
.os-price p { margin: 0 0 26px; font-size: 16.5px; line-height: 1.65; color: #4A5876; }
.os-price p a { color: var(--ge-blue, #1B367E); }
.os-price p a:hover { color: var(--ge-navy, #0F1438); }

/* ---------- responsive ---------- */
@media (max-width: 1020px) {
  .os-incl__grid { grid-template-columns: 1fr 1fr; }
  .os-incl__phone { grid-column: 1 / 3; order: -1; }
  .os-mods__grid { grid-template-columns: 1fr; }
  .os-mods__shot { min-height: 280px; }
}
@media (max-width: 640px) {
  .os-incl__grid { grid-template-columns: 1fr; }
  .os-incl__phone { grid-column: auto; }
  .os-mods__bento { grid-template-columns: 1fr; }
  .os-stage__phone { width: 130px; right: 4px; }
}

/* ============================================================
 * Sections re-ordered to match on-site.org.uk (July 2026)
 * ============================================================ */


/* ---------- "better with GroupEd One" band ----------
   this band is specifically about GroupEd One, so it takes One's own teal
   identity colour rather than OnSite's violet (Rebecca, 24 Jul) — higher
   specificity than the shared .pp-band { background: var(--pp-ink) } rule
   in product-page.css, so it overrides regardless of load order. */
/* 5 Aug: NAVY, at Rebecca's request ("make this navy").
   ⚠ This band was deliberately One's deep sky #116490, not OnSite's violet,
   because its subject is pairing OnSite WITH GroupEd One — the colour was
   pointing at the product being talked about. Navy is her call and overrides
   that; noting the reason so it is not "corrected" back by accident. */
.pp--onsite .pp-band { background: var(--ge-navy, #0F1438); }
.pp--onsite .pp-band .pp-btn--onband,
.pp--onsite .pp-band .pp-btn--onband:hover { color: var(--ge-navy, #0F1438); }
.pp--onsite .pp-band .pp-btn--onband .btn__arrow { background: var(--ge-navy, #0F1438); }

/* ---------- MIS band ---------- */
/* top only shortened, matching .pv3-benefits on the other 3 product pages
   (Rebecca, 28 Jul: "the gap below the hero beofre the next section starts
   is too big") */
.os-mis { background: #fff; padding: clamp(48px, 5.4vw, 84px) 0 clamp(80px, 9vw, 140px); }
.os-mis__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: center;
}
.os-mis h2 { margin: 0 0 14px; color: var(--ge-navy, #0F1438); }
.os-mis p { margin: 0; font-size: 16.5px; line-height: 1.65; color: #4A5876; max-width: 56ch; }
.os-mis__logos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(12px, 1.4vw, 20px);
}
.os-mis__logo {
  /* plain white card (standard site card treatment) so each vendor's own
     brand colour reads cleanly, instead of a violet wash fighting with
     Arbor/Bromcom/SIMS' own colours (Rebecca, 24 Jul) */
  position: relative;
  display: grid;
  place-items: center;
  background: #fff;
  /* stroke -> soft shadow, 4 Aug brand review (one tile treatment sitewide) */
  box-shadow: var(--tile-shadow);
  border-radius: var(--tile-radius);
  padding: clamp(20px, 2.2vw, 32px);
  min-height: 116px;
}
.os-mis__logo img { max-height: 54px; max-width: 78%; width: auto; }
/* Bromcom's lockup is very wide (3.8:1) so the 78% width cap made it render
   noticeably smaller than the others — let it use the full card width so it
   sits at a comparable visual size (Rebecca, 24 Jul) */
.os-mis__logo img[alt="Bromcom"] { max-width: 100%; }
/* One sits on the white card as its own colour (teal) logo — no teal tile
   behind it (Rebecca, 24 Jul); sizing comes from the shared rule above. */
/* 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).
   */
.os-mis__tick {
  position: absolute;
  top: 10px; right: 10px;
  width: 22px; height: 22px;
  border-radius: 999px;
  display: grid; place-items: center;
  background: var(--ge-navy, #0F1438);
  color: #fff;
}
.os-mis__tick svg { width: 12px; height: 12px; }

/* square source photo — keep the teacher's head and feet inside the 16/11 crop */
.os-way__photo--staff { object-position: 50% 72%; }

/* ---------- testimonials grid ---------- */
/* violet tint -> the home page's warm off-white (3 Aug), same reasoning as the
   other product pages; OnSite's violet stays on its cards, chips and CTAs */
.os-says { background: var(--ge-bg-warm, #F7F6F3); padding: clamp(80px, 9vw, 140px) 0; }
.os-says .bandhead { padding-top: 0; }
.os-says__grid {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: clamp(16px, 1.8vw, 26px);
  align-items: stretch;
}
.os-quote--grid { margin: 0; }
.os-quote--grid blockquote { font-size: clamp(18px, 1.7vw, 24px); }
.os-quote__stats { display: flex; gap: 14px; margin-top: 20px; position: relative; z-index: 1; }
.os-quote__stats > div {
  background: rgba(255, 255, 255, 0.08);
  border-radius: 16px;
  padding: 14px 18px;
  font-size: 13.5px;
  color: rgba(255, 255, 255, 0.78);
}
.os-quote__stats strong {
  display: block;
  font-size: clamp(22px, 2vw, 30px);
  font-weight: 800;
  color: var(--ge-violet-3, #8572DA);
  line-height: 1.1;
}

/* ---------- now used in ---------- */
.os-used { background: #fff; padding: clamp(80px, 9vw, 140px) 0; }
.os-used__inner { text-align: center; max-width: 760px; margin: 0 auto; }
.os-used__eyebrow {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ge-violet-4, #614DBA);
}
.os-used__big {
  margin: 0 0 10px;
  font-size: clamp(44px, 5.5vw, 82px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--ge-navy, #0F1438);
}
/* the big heading uses negative letter-spacing; the odometer digits clip with
   overflow:hidden, so that tracking shaved the right edge off the last "0".
   Reset tracking on the number (tabular-nums keeps it aligned). */
.os-used__big .odo { color: var(--ge-violet-4, #614DBA); letter-spacing: normal; }
.os-used__word { font-size: 0.55em; font-weight: 700; }
.os-used__sub { margin: 0; font-size: 16.5px; color: #4A5876; }

/* module cards now carry the live site's headline + bullet list */
.os-mod__head { margin: 0 0 10px !important; font-size: 15px !important; color: var(--ge-navy, #0F1438) !important; font-weight: 700; }
.os-mod__list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
.os-mod__list li { font-size: 14px; line-height: 1.5; color: #4A5876; padding-left: 18px; position: relative; }
.os-mod__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 8px;
  width: 7px; height: 7px;
  border-radius: 999px;
  background: var(--ge-violet-3, #8572DA);
}
.os-mod__list a { color: var(--ge-violet-4, #614DBA); font-weight: 700; }
.os-mod__list a:hover { color: var(--ge-navy, #0F1438); }

/* ---------- trusted-by crest strip ----------
   Background is WHITE, not the off-white #F3F7FA it used to be. The band
   directly above it is the Martyn's Law violet tint #F6F4FF, and the two
   pale values are visually indistinguishable — so the seam between them
   disappeared and the ~216px of stacked padding read as one dead void with
   the heading stranded at the bottom of it (Rebecca, 28 Jul: "the trusted by
   schools section looks quite low down after the martyns law tile"). White
   restores the colour break the design system requires ("no two adjacent
   sections sharing a background"), so the strip reads as its own band. */
/* 5 Aug: was clamp(56px, 6vw, 96px) — one of four one-off band paddings on this
   page. Nothing straddles this band in either direction, so there was nothing
   for the tighter value to clear; it is on the site rhythm now (Rebecca:
   "Double check spacing of content in sections"). */
.os-trust { background: #fff; padding: clamp(80px, 9vw, 140px) 0; }
.os-trust .crests { margin-top: 0; }


@media (max-width: 900px) {
  .os-mis__grid { grid-template-columns: 1fr; }
  .os-says__grid { grid-template-columns: 1fr; }
}

@media (max-width: 1020px) {
  .os-hero__frame { flex-direction: column; align-items: stretch; min-height: 0; }
  .os-hero__copy { max-width: 100%; padding-bottom: clamp(24px, 4vw, 40px); }
  .os-hero__shot {
    position: static;
    width: min(92%, 640px);
    margin: 0 auto clamp(-60px, -6vw, -30px);
  }
  .os-hero__phone { display: none; }
}

/* ============================================================
 * MARTYN'S LAW BAND — the shared .pcband photo-card layout (same as the
 * home page's "Your data's in safe hands" tile), retinted to OnSite's
 * violet so the section belongs to this page. Scoped to .os-ml so the
 * default sky eyebrow is untouched everywhere else.
 * ============================================================ */
/* The Martyn's Law band's wash follows the same 3 Aug change as .os-says:
   violet tint -> the home page's warm off-white. The section's own violet stays
   on its eyebrow, card and CTA, so the product colour is still doing the work. */
.os-ml { background: var(--ge-bg-warm, #F7F6F3); }
.os-ml .pcband__eyebrow {
  background: #fff;
  color: var(--ge-violet-4, #614DBA);
}
/* The teacher — the subject of the photo — sits at roughly 56-80% across, so
   the card is held below the default min(560px, 60%), which would cover her at
   a ~1024px viewport. At 50% its right edge lands at 49.6% (1440px) and 53%
   (1024px), both clear of her. The frame also gets more height, because the
   photo is 1.34:1 and the default 2.17:1 frame would throw most of it away
   (and clip the top of her head) on a centred vertical crop.
   min-width guard matters: .pcband's own mobile rule sets the card to
   width:auto, and an unscoped .os-ml override outranks it — which squashed the
   card to 46% of a phone screen. */
@media (min-width: 821px) {
  .os-ml .pcband__card { width: min(560px, 50%); }
  .os-ml .pcband__frame { min-height: clamp(440px, 42vw, 620px); }
}

/* Reception row: the new photo (Rebecca, 27 Jul) has the wall-mounted kiosk on
   the RIGHT, which is exactly where an odd row's screenshot card lands — it
   covered the kiosk by 182x57px. Flip this row's card to the left, over the
   desk front, so the actual kiosk stays visible. */
.os-way:first-child .os-way__shot { right: auto; left: 0; }
.os-way:first-child .os-way__badge { right: auto; left: 46%; }

/* The Primary/Secondary price toggle showed both states in the same violet, so
   switching school type read as "nothing changed" (Rebecca, 27 Jul: "different
   purple from brand colours for secondary pricing"). Secondary now takes the
   deeper violet already used on this page for OnSite button hovers — clearly a
   different purple, still the same family, and 8.73:1 on white vs violet-4's
   6.4:1. The brand's own violet-3 (#8572DA) was the obvious candidate but only
   manages 3.88:1, which fails AA at this size. */
/* The price itself is WHITE on the violet lead panel, so recolouring the number
   would have made it unreadable — the panel changes instead. */
/* Driven by .is-secondary, set by the toggle in product-v3.js — see the note
   there on why :has() could not do this. Scoped through the body + card classes
   because product-v3.css loads AFTER this file and sets
   .pp-card--split .pp-card__lead { background: var(--pp-ink) }. */
.pp--onsite .pp-card--split .pp-card__lead.is-secondary { background: #4B3B9C; }
/* keep the white pill's label matching whichever panel colour is showing */
.pp-card__lead.is-secondary .os-toggle__seg.is-active { color: #4B3B9C; }
.pp-card__lead { transition: background 260ms var(--hv2-ease); }

/* ============================================================
 * "FOUR WAYS YOUR SCHOOL WILL USE ONSITE" — restyled to the home
 * page's product board (Rebecca, 5 Aug: "can we make this section
 * styled like how we show the products on the home page").
 *
 * Deliberately CSS-only. The markup, the ARIA tablist wiring and the
 * hidden/.is-active state that onsite-v2.js drives are all untouched —
 * the home board uses a different set of JS hooks (data-pshow /
 * .is-on), so swapping the classes over would have meant rewriting
 * working tab logic for a purely visual change.
 *
 * ⚠ AMENDED SAME DAY. The tab TILES are still the home page's .psmenu treatment
 * (pale #EDF1F6 at rest, violet + white + lifted when active) and stay that way.
 * Everything below the tabs was then rebuilt to follow the ONE page's product
 * breakdown instead — "change the attached to follow how we style the one
 * product breakdown. change shape of the tile to be the size of a mobile phone."
 * So the violet board, the white photo tile and the white copy card are gone;
 * see the two blocks below for what replaced them.
 * ============================================================ */
.os-mods .os-tabbar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: clamp(12px, 1.4vw, 20px);
  margin: 0 0 clamp(22px, 2.6vw, 36px);
  flex-wrap: initial;
}
.os-mods .os-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: clamp(18px, 2vw, 30px) clamp(12px, 1.4vw, 20px);
  border: none;
  border-radius: 20px;
  font-size: clamp(15px, 1.3vw, 17px);
  font-weight: 600;
  text-align: center;
  transition: background 200ms var(--hv2-ease), color 200ms var(--hv2-ease),
              transform 200ms var(--hv2-ease), box-shadow 200ms var(--hv2-ease);
}
.os-mods .os-tab svg { width: 26px; height: 26px; opacity: 1; }
/* resting: the home page's pale tile, at the same 3:1-clear grey */
.os-mods .os-tab:not(.is-active) {
  background: #EDF1F6;
  box-shadow: inset 0 0 0 1px rgba(15, 20, 56, 0.06);
  color: #5A6478;
}
.os-mods .os-tab:not(.is-active):hover {
  background: #E1E7F0;
  border-color: transparent;
  color: var(--ge-navy, #0F1438);
  transform: translateY(-2px);
}
.os-mods .os-tab.is-active {
  background: var(--ge-violet-4, #614DBA);
  color: #fff;
  transform: translateY(-3px);
  box-shadow: 0 14px 30px rgba(15, 20, 56, 0.18);
}

/* ---------- the row ----------
 * NO outer coloured board. That was the home-page product board, where the
 * violet frame surrounded a white photo tile and a white copy card. Following
 * the One breakdown instead, the ONLY coloured thing is the tile itself — the
 * section stays white, the copy sits plainly on it, exactly as One's accordion
 * column does. Left as it was, the board's violet frame wrapped a violet tile:
 * violet on violet.
 * ---------------------------------------------------------------- */
.os-mods .os-ways { display: block; gap: 0; }
.os-mods .os-way {
  background: none;
  border-radius: 0;
  overflow: visible;
  padding: 0;
  /* near-even split, the copy a touch narrower — One uses 0.86/1.24 because its
     screenshot is a wide desktop UI; a portrait phone does not need that much */
  grid-template-columns: minmax(0, 0.94fr) minmax(0, 1.06fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: center;
}
/* Copy LEFT, tile RIGHT — the One breakdown's arrangement (its feature list sits
   left of the coloured tile), and the SAME on every panel so nothing jumps
   sideways as you change tab. It was media-left when this matched the home
   board; following One flips it.
   The :has(.os-tabbar) selector is needed to outrank the older
   `.os-mods:has(.os-tabbar) .os-way:nth-child(even)` pair further up this file.
   Without it those rules won on the even panels and Staff/Lockdown rendered
   mirrored — measured, not assumed. */
.os-mods:has(.os-tabbar) .os-way .os-way__copy  { order: 1; }
.os-mods:has(.os-tabbar) .os-way .os-way__media { order: 2; }
.os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__copy  { order: 1; }
.os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__media { order: 2; }

/* ---------- the tile: One's "Everything in One" treatment ----------
 * Rebecca, 5 Aug: "change the attached to follow how we style the one product
 * breakdown. change shape of the tile to be the size of a mobile phone."
 * So the tile is no longer a framed school photo with a screenshot overhanging
 * it — it is the One page's tile: a solid product-colour block carrying the
 * hexagon mark clipped to a left column, the caption watermark bottom-right,
 * and the screenshot in a chunky white frame. All of that comes free from
 * .pv3-acc__media--mark in product-v3.css (which OnSite already loads), so the
 * markup wears those classes and there is ONE implementation of the look, not a
 * copy. Only the phone frame's width and the tile's own radius are set here.
 * The four school photos came off this section as a result — that is inherent
 * to the One style, and she chose it knowing that.
 * ---------------------------------------------------------------- */
.os-mods .os-way__media {
  position: relative;
  border-radius: clamp(20px, 2.2vw, 28px);
  overflow: hidden;
}
/* A little narrower than One's 300px cap: the phone sits beside a copy card
   rather than a four-row accordion, so a slimmer device keeps the violet
   showing around it and the board from growing too tall. */
.os-mods .pv3-acc__frames--phone { max-width: clamp(190px, 17vw, 250px); }

/* the copy column: plain on the white section, like One's accordion column —
   no card, no padding of its own */
.os-mods .os-way__copy {
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2vw, 24px);
}
.os-mods .os-way__copy h3 { margin: 0; }
.os-mods .os-way__copy .psl__points { gap: 14px; }

/* One column at the same width One's own tile stacks at (860px), and the tile
   goes ABOVE the copy there — matching `.pv3-acc__grid > .pv3-acc__media
   { order: -1 }` on that page, so the screenshot is what you meet first. */
@media (max-width: 860px) {
  .os-mods .os-way { grid-template-columns: 1fr; gap: clamp(24px, 5vw, 40px); }
  .os-mods:has(.os-tabbar) .os-way .os-way__media,
  .os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__media { order: 1; }
  .os-mods:has(.os-tabbar) .os-way .os-way__copy,
  .os-mods:has(.os-tabbar) .os-way:nth-child(even) .os-way__copy { order: 2; }
}

/* The per-element reveal (photo sliding in from the side, screenshot rotating up)
   was built for the old free-standing photo rows, whose elements are gone. The
   .rv on the tile is neutralised too: on a tab-switched panel there is no
   guarantee .in is ever added, which would leave the tile at opacity 0 forever.
   The panel's own crossfade (@keyframes os-way-in) is the whole entrance now. */
.os-mods .os-way.rv .os-way__media,
.os-mods .os-way.rv.in .os-way__media { opacity: 1; transform: none; transition: none; }

/* ============================================================
 * FOUR WAYS BOARD — per-card purple, no phone frame, mark all round
 * 5 Aug 2026. Three asks in one pass, all scoped to .os-mods so nothing
 * outside this board on OnSite moves, and no other product page is touched.
 * ============================================================ */

/* ---- 1. NO WHITE FRAME ON THE PHONES ----
 * "the onsite phone mockups dont need the white framing".
 * ⚠ SPECIFICITY: the first attempt put this on .pv3-acc__frames--phone up at
 * line 1411 of product-v3.css. The base .pv3-acc__frames rule that paints the
 * white frame is at line 1828 of the same file — equal specificity (0,1,0), so
 * the LATER rule won and nothing changed. Scoping to .os-mods makes it (0,2,0)
 * and puts it in a file that loads after product-v3.css besides.
 * Why it is right here and not a rule change: these are full-bleed phone screens
 * that already carry their own status bar, home indicator and pale app
 * background, so the white border read as a second bezel around something that
 * is already a device screen. Every other image tile on the site keeps the
 * frame — this is a narrow, deliberate exception. */
.os-mods .pv3-acc__frames--phone {
  border: none;
  background: transparent;
}

/* ---- 2. A DIFFERENT PURPLE PER CARD ----
 * "could we use different shades of purple for each card."
 * One family, four steps, light to dark in reading order — so the four panels
 * feel like a set rather than four unrelated colours, and moving through the
 * tabs reads as travelling somewhere. Deliberately ordered by escalation too:
 * Reception is the everyday one and Lockdown the most serious, so the colour
 * deepens as the stakes do.
 * All four are measured for white type: 4.9, 6.1, 7.5 and 9.2 to 1, so every
 * one clears AA for body text, not just for headings. */
/* ⚠ nth-of-type on the TILE itself. These used to hang off .os-way:nth-of-type,
   and .os-way stopped existing when the board was split into a copy column and a
   tile track — which silently dropped all four colours. */
.os-mods .os-ways > [data-os-media]:nth-of-type(1) { background: #6E5BD0; }  /* Reception  */
.os-mods .os-ways > [data-os-media]:nth-of-type(2) { background: #5B49BE; }  /* Staff      */
.os-mods .os-ways > [data-os-media]:nth-of-type(3) { background: #4C3BA6; }  /* Evacuation */
.os-mods .os-ways > [data-os-media]:nth-of-type(4) { background: #3E2F8C; }  /* Lockdown   */

/* the active tab takes its own panel's shade, so the pill and the card it opens
   are visibly the same thing rather than two different purples on screen */
.os-tabbar .os-tab:nth-of-type(1).is-active { background: #6E5BD0; border-color: #6E5BD0; }
.os-tabbar .os-tab:nth-of-type(2).is-active { background: #5B49BE; border-color: #5B49BE; }
.os-tabbar .os-tab:nth-of-type(3).is-active { background: #4C3BA6; border-color: #4C3BA6; }
.os-tabbar .os-tab:nth-of-type(4).is-active { background: #3E2F8C; border-color: #3E2F8C; }

/* ---- 3. NO WATERMARK BEHIND THE PHONES  (5 Aug) ----
 * "can we get rid of the watermark behind the phone screenshots."
 *
 * Short history so this is not re-litigated: it started clipped to a 34%-wide
 * left column with a gradient mask, which was built for the empty diagonal
 * beside a 16:9 desktop screenshot. Against a narrow portrait phone that left it
 * stranded down one side, so she asked for it "bigger so it peaks all the way
 * around the screenshot" and it went full-tile at 150%. Seen at that size she
 * dropped it altogether — a hexagon big enough to surround the phone stops being
 * texture and starts being a second graphic behind the UI.
 * The tile keeps its colour and its corner caption; only the mark goes.
 * display:none rather than opacity:0 so it costs no paint at all. The markup and
 * the base rules in product-v3.css are untouched, so One and Classroom keep
 * their left-column marks and this is one line to undo. */
.os-mods .pv3-acc__media--mark .pv3-acc__mark { display: none; }

/* ---- 4. THE BOARD IS A SIDE SCROLL  (5 Aug) ----
 * "can we make this a side scroll to navigate. add arrow like you did on the
 * home page too."
 * Same mechanism as the home page's product board: native CSS scroll-snap, not
 * a JS carousel, so trackpad, touch, shift-wheel and keyboard all work without
 * us writing any of it. The icon pills above stay as the indicator, exactly as
 * the logo tabs do on the home page, and the arrows are the same .pstnav
 * component — not a lookalike.
 * ⚠ .os-ways was `flex-direction: column` with a big row gap; both have to go or
 * the panels stack inside the track. The old tab system hid three of the four
 * panels with the `hidden` attribute — those are removed from the markup, and
 * .os-way[hidden]{display:none} in this file is now dead but harmless. */
.os-mods .os-ways {
  /* ⚠ display MUST be re-declared. .os-ways is `display: flex` at line 258 of
     this file, but something later resets it to block — setting only
     flex-direction gave a row direction on a block box, so the four panels
     stacked vertically, the track's scrollWidth equalled its clientWidth, and
     nothing could scroll while every other symptom looked correct. */
  display: flex;
  flex-direction: row;
  gap: clamp(14px, 1.5vw, 24px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-inline: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding-bottom: 2px;
}
.os-mods .os-ways::-webkit-scrollbar { display: none; }

/* ---- 5. NO TILE SHADOW INSIDE THE TRACK  (5 Aug) ----
 * "i dont like the grey shadow i can see by the bullets."
 * .pv3-acc__media carries `0 26px 60px rgba(15,20,56,0.14)` — a big soft drop
 * shadow, which is right for a single tile sitting alone on a white band. In a
 * scroll track it is not: the four panels sit 21px apart, so the NEXT panel's
 * purple tile is only just off-screen and its shadow reaches across the gap and
 * falls over the copy column of the panel you are reading — which is why it
 * showed up beside the bullets and nowhere else.
 * Removed rather than reduced. The tile is a large saturated colour block
 * against white; it has all the separation it needs from the colour itself. */
.os-mods .os-way__media { box-shadow: none; }
@media (prefers-reduced-motion: reduce) { .os-mods .os-ways { scroll-behavior: auto; } }

.os-mods .os-ways > [data-os-media] {
  /* 0 0 100% so a tile never shrinks to fit — the track scrolls instead, and one
     tile fills the track exactly so it aligns on both sides */
  flex: 0 0 100%;
  scroll-snap-align: start;
  /* a stray gesture can only ever land on a tile, never between two */
  scroll-snap-stop: always;
}
/* the entry animation was for a crossfading tab panel; with all four in a row it
   would fire on whichever happened to be marked, mid-scroll */
.os-mods .os-way.is-active { animation: none; }
.os-mods .os-ways:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(97, 77, 186, 0.35); border-radius: 24px; }

/* ---- 6. PHONE IN A DEVICE FRAME, ON A SHORTER TILE  (5 Aug) ----
 * "with phone screen shots can we show them like this. we dont need the tile
 * were using to be so big" — with a Monzo mockup: a real handset with a dark
 * bezel, standing on a compact coloured tile and running off the bottom edge of
 * it rather than floating in the middle of a tall one.
 *
 * Three moves:
 *   · the tile is now a 5:4 box instead of matching the copy column's height,
 *     so it stops being the tallest thing on the page
 *   · the screenshot gets a dark bezel, which turns a bare rounded rectangle
 *     into a handset
 *   · the handset is taller than the tile and top-anchored, so it bleeds off the
 *     bottom and the tile clips it — the crop is what sells it as a photograph
 *     of a device rather than an image pasted on
 *
 * ⚠ THE BEZEL IS A BORDER, NOT PADDING. .pv3-acc__shot is absolutely positioned
 * with inset:0, and an abspos child's containing block is the PADDING box — so
 * padding would not inset it at all and the screenshot would cover the bezel.
 * A border shrinks the padding box, so it does. The same trap is documented on
 * the white frame this replaces.
 * The screenshots already draw their own status bar and Dynamic Island, so the
 * bezel deliberately adds neither — a second island would sit under the drawn one. */
.os-mods .os-way__media {
  /* ONE token for the handset's width. The caption's max-width is derived from
     it below, so the two can never disagree — enlarging the phone used to leave
     the caption at a fixed 25% and it ran straight under the device. */
  --os-phone-w: 56%;
  aspect-ratio: 5 / 4;
  display: flex;
  align-items: flex-start;      /* the overflow has to fall off the BOTTOM */
  justify-content: center;
  padding: clamp(24px, 2.4vw, 38px) clamp(16px, 1.7vw, 28px) 0;
  overflow: hidden;
}
.os-mods .pv3-acc__frames--phone {
  /* the bezel */
  border: clamp(7px, 0.7vw, 10px) solid #10131F;
  background: #10131F;
  border-radius: clamp(34px, 3vw, 44px);
  box-shadow: 0 26px 54px rgba(8, 10, 25, 0.38), 0 0 0 1px rgba(255, 255, 255, 0.07) inset;
  /* taller than the tile's content box, so it runs off the bottom and is clipped */
  /* MEASURED off her Monzo reference: their handset is ~740px across a ~1105px
     tile — 67% of its width — and roughly the top 60% of the phone is visible
     before the tile crops it. Ours was 39% and read as a small phone in a big
     box ("can we make the screenshots bigger so they fill the tile like monzo").
     Driven by WIDTH now, not height: width is the proportion the eye actually
     judges, and at 9:19.5 the height follows and simply crops deeper. 56% on our
     5:4 tile — a little under Monzo's 67% because our tile is landscape and
     theirs is square, so the same percentage would leave no tile either side. */
  width: var(--os-phone-w, 56%);
  height: auto;
  max-width: none;
  aspect-ratio: 9 / 19.5;
  flex: none;
  margin: 0;
}
.os-mods .pv3-acc__shot { border-radius: clamp(27px, 2.4vw, 35px); }

/* ⚠ HIDDEN 5 Aug: "can we also get rid of the water mark text on the '4 ways
   your school will use onsite'". The rules below are kept, not deleted, because
   they hold the positioning work — if the caption is ever wanted back it is one
   line. One & Classroom still show theirs; this is scoped to .os-mods.

   (historic) the caption sat in an 89px band under the phone; the handset now
   runs to the tile's bottom edge so there is no band left.
   ⚠ Moved to the top LEFT, not the top right. The right is where the phone's own
   top corner lands once it is centred and this size — the first attempt put the
   caption there and the device covered half of it. Left of a centred handset is
   the only corner with clear tile in it at every width. */
.os-mods .pv3-acc__media--mark .pv3-acc__wmtext {
  top: clamp(14px, 1.5vw, 22px);
  bottom: auto;
  left: clamp(16px, 1.7vw, 26px);
  right: auto;
  height: auto;
  justify-content: flex-start;
  /* DERIVED from the phone, not guessed. The handset is centred at --os-phone-w
     of the tile's content box, so the clear column each side is
     (100% - --os-phone-w) / 2; the 14px is a gutter so the caption never quite
     touches the bezel. Fixed values were wrong twice — 34% then 25% — because
     each time the phone grew the clear column shrank underneath them. */
  max-width: calc((100% - var(--os-phone-w, 56%)) / 2 - 14px);
  text-align: left;
  line-height: 1.2;
}


/* ---- 7. COPY LEFT, ONLY THE TILE SCROLLS  (5 Aug) ----
 * The board is now two halves: a fixed copy column and a scrolling tile track.
 * .os-board replaces the old per-panel grid — the columns are the same 1fr/1.1fr
 * split the .os-way grid used, so nothing moves horizontally. */
.os-mods .os-board {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: clamp(28px, 4vw, 72px);
  align-items: center;
}

/* the four copies share one grid cell. They stay in FLOW rather than being
   absolutely positioned, so the cell is as tall as the longest of them and the
   tile beside it never changes height as you scroll between modules — an
   absolutely positioned stack would collapse the cell to nothing. */
.os-mods .os-board__copies { display: grid; }
.os-mods .os-board__copies > [data-os-copy] {
  grid-area: 1 / 1;
  transition: opacity 260ms var(--hv2-ease), transform 260ms var(--hv2-ease);
}
.os-mods .os-board__copies > [data-os-copy]:not(.is-active) {
  opacity: 0;
  transform: translateY(8px);
  /* not display:none — that would drop it out of the grid sizing above */
  pointer-events: none;
  visibility: hidden;
}
.os-mods .os-board__copies > [data-os-copy].is-active { opacity: 1; transform: none; visibility: visible; }
@media (prefers-reduced-motion: reduce) {
  .os-mods .os-board__copies > [data-os-copy] { transition: none; }
}

@media (max-width: 860px) {
  /* stacked: copy above, tile below, still swipeable */
  .os-mods .os-board { grid-template-columns: 1fr; }
}

/* ============================================================
 * TESTIMONIALS — CAROUSEL, NO MODULE, BIG TYPE  (5 Aug 2026)
 * "can we make the onsite testimonal a carousel and have one large module for
 * it" → built → "how do you think monzo would present testimonials" → "ok" to
 * the answer. So: the carousel stays and the module goes.
 *
 * Why the module went: with one quote in it the card was mostly empty — the
 * quote finished a third of the way down and the rest was nothing. Monzo either
 * fills that space with a large photograph of the person or has no card at all.
 * Having no photographs of the people quoted, the honest version is the second.
 *
 * This now matches the HOME page testimonial exactly — tile-free, oversized
 * navy type, crest beside the school name in the caption — which is the most
 * Monzo-like block on the site and was settled after five surfaces were tried
 * and rejected there. Same sizes: clamp(30px, 3.9vw, 54px) at a 25ch measure.
 * See .qplain in home-v2.css; do not let the two drift apart.
 * ============================================================ */
.os-says .os-says__grid {
  display: flex;
  gap: clamp(20px, 2.5vw, 40px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-inline: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.os-says .os-says__grid::-webkit-scrollbar { display: none; }
@media (prefers-reduced-motion: reduce) { .os-says .os-says__grid { scroll-behavior: auto; } }
.os-says .os-says__grid > [data-quote] {
  flex: 0 0 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  margin: 0;
}
.os-says .os-says__grid:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(97,77,186,0.35); border-radius: 24px; }

/* the quote loses its own card: the module around it is the surface now, and a
   card inside a card is the thing the modular rewrite set out to remove */
.os-says .os-quote--grid {
  background: transparent;
  box-shadow: none;
  border: none;
  padding-inline: 0;
}
/* the violet variant coloured the second CARD; with no card it would tint
   nothing, so it is dropped rather than left as a dead class */
.os-says .os-quote--violet { background: transparent; }

/* ⚠ THE TYPE HAS TO FLIP WITH THE SURFACE — this is what "you cant read the
   quote" was. Both quotes lived on DARK cards (navy, and violet for the second),
   so every piece of type in them was white. Taking the cards away left white on
   the module's #F3F7FA: measured 1.08:1, which is not faint, it is invisible.
   Everything below is the same hierarchy the cards had, inverted for a pale
   ground — quote and name in navy, role and stat labels in secondary grey.
   Scoped to .os-says so .os-quote is untouched anywhere else it is used. */
.os-says .os-quote blockquote,
.os-says .os-quote__name { color: var(--ge-navy, #0F1438); }
.os-says .os-quote__role { color: #4A5876; }
/* the stat chips were built for a dark card too, and needed more than a colour
   on the parent: their own rules set a white-wash background (rgba(255,255,255,
   0.08), invisible on a pale ground) and label text at rgba(255,255,255,0.78),
   which is white on near-white. Both are inverted here.
   ⚠ My first contrast sweep MISSED these: it only tested leaf elements, and the
   chip is a div with a <strong> inside, so it was skipped while reading as
   completely blank on screen. Test elements that have their own text nodes, not
   just leaves. */
.os-says .os-quote__stats > div {
  background: rgba(15, 20, 56, 0.05);
  color: #4A5876;
}
.os-says .os-quote__stats strong { color: var(--ge-violet-4, #614DBA); }

/* the two highlights disagreed as well — the first was violet-3 #8572DA and the
   second a pale lilac #E4DBFF that was only ever legible on a violet card. One
   colour for both now, OnSite's own violet, which measures 5.9:1 on the module. */
.os-says .os-quote .q-hl { color: var(--ge-violet-4, #614DBA); }

/* dots left, arrows right — one row under the quote */
.os-quotenav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: clamp(20px, 2.4vw, 32px);
}
.os-quotenav .pstnav { margin-top: 0; }
.os-dots { display: flex; gap: 10px; }
.os-dot {
  appearance: none;
  /* 10px dot in a 44px hit area — the site's touch-target floor. The padding is
     transparent, so it stays a small dot to look at and a big target to hit. */
  width: 44px; height: 44px;
  padding: 17px;
  border: none;
  background: transparent;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.os-dot::before {
  content: "";
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #C6CFDB;
  transition: background 200ms var(--hv2-ease), transform 200ms var(--hv2-ease);
}
.os-dot.is-on::before { background: var(--ge-violet-4, #614DBA); transform: scale(1.15); }
.os-dot:focus-visible { outline: none; border-radius: 999px; box-shadow: 0 0 0 3px rgba(97,77,186,0.35); }
@media (prefers-reduced-motion: reduce) { .os-dot::before { transition: none; } }


/* ---- the quote itself: home-page scale, no surface ---- */
.os-says .os-quote {
  background: transparent;
  box-shadow: none;
  border: none;
  padding: 0;
  overflow: visible;
  /* ⚠ NO max-width here. The figure is a scroll item at flex: 0 0 100%; capping
     it at 1040px made it narrower than the track, which left ~240px of the next
     quote showing at the right edge — two quotes on screen at once, the second
     one sliced down the middle. The measure lives on the blockquote instead
     (25ch), which is where the home page puts it too. */
}
.os-says .os-quote blockquote {
  /* the home page's exact numbers — 25ch at up to 54px. It was 46ch at up to
     29px, which is body copy with quote marks round it. */
  max-width: 25ch;
  font-size: clamp(30px, 3.9vw, 54px);
  line-height: 1.18;
  letter-spacing: -0.02em;
  font-weight: 600;
  color: var(--ge-navy, #0F1438);
}
.os-says .os-quote figcaption {
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.2vw, 18px);
  margin-top: clamp(22px, 2.4vw, 32px);
}
.os-says .os-quote__name { font-size: clamp(15px, 1.2vw, 17px); }
.os-says .os-quote__role { font-size: clamp(13px, 1.05vw, 14.5px); opacity: 1; }

/* the stats stop being chips. They are kept — they are real numbers and worth
   having — but as a quiet line under the attribution rather than two filled
   tiles competing with 54px type for attention. Monzo would run the quote alone;
   this keeps the facts without giving them a surface of their own. */
.os-says .os-quote__stats {
  gap: clamp(20px, 2.4vw, 36px);
  margin-top: clamp(18px, 2vw, 26px);
}
.os-says .os-quote__stats > div {
  background: transparent;
  padding: 0;
  font-size: 13.5px;
  color: #4A5876;
}
.os-says .os-quote__stats strong {
  font-size: clamp(19px, 1.6vw, 24px);
  color: var(--ge-violet-4, #614DBA);
}


/* the screenshot caption, off (5 Aug) — see the note on .pv3-acc__wmtext above */
.os-mods .pv3-acc__media--mark .pv3-acc__wmtext { display: none; }


/* ---- the section heading steps down  (5 Aug) ----
 * "i dont like how the title is the same size and weight as the testimonial."
 * She was right — "What schools say about OnSite." and the quote were both
 * 54px at weight 600 navy, so the eye had two statements of equal rank and no
 * idea which was the content.
 * The quote is the content; the heading is a label for it. So the heading
 * becomes exactly that — 17px, and secondary grey rather than navy, the same
 * treatment the crest strip's "Trusted by 100+ schools" line uses further down
 * this page. Ratio is now about 3:1 between them instead of 1:1.
 * The quote is untouched: it stays at the home page's size so the two pages'
 * testimonials still match.
 * ⚠ Scoped to .os-says. Every other .bandhead h2 on the site keeps its size. */
.os-says .bandhead h2 {
  font-size: clamp(15px, 1.3vw, 17px);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0;
  color: #4A5876;
}
/* the gap under it closes to match — 72px of air under a 17px label reads as a
   mistake, where it was right under a 54px heading */
.os-says .bandhead { margin-bottom: clamp(18px, 2vw, 28px); }
