/* ============================================================
   Melita. — Online Tutoring · cinematic storybook
   Warm cream, lavender purple, classic serif, handwritten notes
   ============================================================ */

:root {
  --cream: #f4efe7;
  --cream-2: #efe8dc;
  --ink: #26242e;
  --ink-soft: #55505e;
  --purple: #7c5fc4;
  --purple-deep: #5f43ae;
  --purple-soft: #a58bd8;
  --lavender: #cabcec;
  --lavender-bg: #ece6f7;
  --gold: #c9a24d;
  --paper: #faf6ee;
  --shadow: 0 18px 45px rgba(72, 52, 130, 0.16);

  --serif: "Playfair Display", Georgia, serif;
  --sans: "Poppins", "Segoe UI", sans-serif;
  --script: "Caveat", cursive;

  --header-h: 96px;

  /* scene image ratios */
  --r-wide: 1.6953;   /* 1536 / 906 */
  --r-door: 1.1435;   /* 1036 / 906 */
  --r-desk: 1.2318;   /* 1116 / 906 */
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Every scene is exactly one viewport. The document is never taller than the
   window, so there is nothing to scroll — the scrollbar is absent because the
   layout fits, not because it has been hidden. */
html, body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}
html { scroll-behavior: auto; }

body {
  font-family: var(--sans);
  color: var(--ink);
  background: var(--cream);
  line-height: 1.6;
  overflow-x: hidden;
}

button { font-family: inherit; cursor: pointer; background: none; border: none; color: inherit; }

.heart { color: var(--purple-soft); font-family: var(--serif); font-weight: 400; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* ============ BOOT VEIL ============ */

.boot-veil {
  position: fixed; inset: 0; z-index: 100;
  background: var(--cream);
  display: grid; place-content: center; text-align: center; gap: 6px;
  transition: opacity 0.9s ease, visibility 0.9s;
}
/* pointer-events released immediately: during the 0.9s fade the veil would
   otherwise still swallow the first click on the hero. */
.boot-veil.is-done { opacity: 0; visibility: hidden; pointer-events: none; }
.boot-logo { font-family: var(--serif); font-weight: 600; font-size: 44px; color: var(--purple-deep); }
.boot-sub { font-family: var(--script); font-size: 22px; color: var(--purple-soft); animation: bootPulse 1.6s ease-in-out infinite; }
@keyframes bootPulse { 0%,100% { opacity: 0.45; } 50% { opacity: 1; } }

/* ============ CUSTOM CURSOR ============ */

.cursor { position: fixed; top: 0; left: 0; z-index: 99; pointer-events: none; }
.cursor-dot, .cursor-ring {
  position: absolute; top: 0; left: 0;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.cursor-dot { width: 7px; height: 7px; background: var(--purple); }
.cursor-ring {
  width: 34px; height: 34px;
  border: 1.5px solid rgba(124, 95, 196, 0.55);
  transition: width 0.3s ease, height 0.3s ease, background 0.3s ease, border-color 0.3s ease;
}
.cursor.is-hover .cursor-ring { width: 56px; height: 56px; background: rgba(165, 139, 216, 0.14); }
.cursor.is-door .cursor-ring { width: 74px; height: 74px; background: rgba(255, 214, 150, 0.18); border-color: rgba(201, 162, 77, 0.7); }
body.has-cursor, body.has-cursor a, body.has-cursor button { cursor: none; }
@media (hover: none), (pointer: coarse) { .cursor { display: none; } }

/* ============ HEADER ============ */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 0 40px;
  z-index: 60;
  /* No bar and no gradient: the controls float directly over the artwork, as
     they always did. A background here reads as a block covering the page; a
     gradient reads as a blurry fade. Neither is wanted. */
  background: none;
  pointer-events: none;
}
.site-header > * { pointer-events: auto; }

.header-left { position: relative; min-width: 190px; }
.brand { text-decoration: none; color: var(--ink); display: flex; flex-direction: column; line-height: 1.1; transition: opacity 0.4s ease, transform 0.4s ease; }
.brand-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 34px;
  color: var(--purple-deep);
  display: inline-flex;
  align-items: flex-start;
  gap: 2px;
}
.sparkle { width: 18px; height: 18px; color: var(--purple-soft); margin-top: 2px; }
.brand-sub { font-size: 11px; letter-spacing: 0.28em; text-transform: uppercase; color: var(--ink); margin-top: 4px; }

.goback-pill {
  position: absolute; top: 50%; left: 0;
  transform: translateY(-50%) translateX(-12px);
  display: inline-flex; align-items: center; gap: 12px;
  background: rgba(250, 246, 238, 0.85);
  backdrop-filter: blur(6px);
  border-radius: 999px;
  padding: 9px 24px 9px 10px;
  font-size: 15px;
  box-shadow: 0 10px 26px rgba(72, 52, 130, 0.14);
  opacity: 0; visibility: hidden;
  transition: opacity 0.4s ease, transform 0.4s ease, visibility 0.4s;
}
.pill-circle {
  width: 34px; height: 34px; border-radius: 50%;
  background: #fff; display: inline-grid; place-items: center;
  box-shadow: 0 4px 12px rgba(38, 36, 46, 0.14);
}
body.show-goback .goback-pill { opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0); }
body.show-goback .brand { opacity: 0; transform: translateY(-6px); pointer-events: none; }

/* Stepper */
.stepper { display: flex; align-items: flex-start; }
.step { display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: 76px; }
.step-dot {
  width: 38px; height: 38px;
  border-radius: 50%;
  background: rgba(238, 232, 221, 0.92);
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 600;
  display: grid;
  place-items: center;
  transition: all 0.35s ease;
  box-shadow: inset 0 0 0 1px rgba(38, 36, 46, 0.05);
}
.step-label { font-size: 12px; color: var(--ink-soft); white-space: nowrap; transition: color 0.35s ease; }
.step.is-active .step-dot { background: var(--purple); color: #fff; box-shadow: 0 6px 16px rgba(124, 95, 196, 0.4); }
.step.is-active .step-label { color: var(--purple); font-weight: 600; }
.step:hover .step-dot { background: var(--lavender); color: var(--purple-deep); }
.step.is-active:hover .step-dot { background: var(--purple); color: #fff; }
.step-line { width: 56px; border-top: 2px dashed #cfc7ba; margin-top: 18px; }

/* Hamburger */
.menu-btn {
  width: 46px; height: 46px;
  border-radius: 50%;
  background: var(--purple-soft);
  display: grid; place-items: center;
  box-shadow: 0 8px 20px rgba(124, 95, 196, 0.35);
  transition: transform 0.25s ease, background 0.25s ease;
}
.menu-btn span { display: block; width: 18px; height: 2px; border-radius: 2px; background: #fff; margin: 2.5px 0; }
.menu-btn:hover { background: var(--purple); }

.menu-overlay {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(244, 239, 231, 0.97);
  backdrop-filter: blur(6px);
  display: grid; place-items: center;
  opacity: 0; visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s;
}
.menu-overlay.is-open { opacity: 1; visibility: visible; }
/* ============================================================
   THE JOURNEY MAP — navigation overlay
   The same cream and purple as the rest of the house, with the six steps read
   as a route rather than a list. Applies at every width; the laptop's own
   type scale is restored underneath.
   ============================================================ */

.menu-overlay {
  display: grid;
  place-items: center;
  padding: max(14px, env(safe-area-inset-top)) 14px max(14px, env(safe-area-inset-bottom));
  overscroll-behavior: contain;
  /* a very faint warm glow, so it reads as a lit room rather than a blank page */
  background:
    radial-gradient(80% 55% at 50% 0%, rgba(202, 188, 236, 0.28), transparent 70%),
    radial-gradient(70% 45% at 50% 100%, rgba(201, 162, 77, 0.12), transparent 70%),
    rgba(244, 239, 231, 0.985);
}

.menu-sheet {
  display: flex;
  flex-direction: column;
  width: min(460px, 100%);
  max-height: 100%;
  padding: 4px 2px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.menu-sheet::-webkit-scrollbar { width: 0; }

/* ---- the sheet's own header, with the close control ---- */
.menu-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 6px 14px;
}
.menu-brand-name {
  display: block;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(20px, 5.6vw, 26px);
  line-height: 1.1;
  color: var(--purple-deep);
}
.menu-star { color: var(--purple-soft); font-size: 0.6em; vertical-align: super; margin-left: 2px; }
.menu-brand-sub {
  display: block;
  margin-top: 5px;
  font-family: var(--script);
  font-size: clamp(15px, 4.4vw, 19px);
  color: var(--ink-soft);
}

/* an unmistakable X — the hamburger is behind the overlay, so this is the
   only way out and it has to look like one */
.menu-close {
  flex: none;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  color: var(--purple-deep);
  background: #fff;
  box-shadow: 0 4px 16px rgba(72, 52, 130, 0.18);
  transition: background 0.2s ease, transform 0.2s ease;
}
.menu-close svg { width: 22px; height: 22px; }
.menu-close:hover { background: var(--lavender-bg); }
.menu-close:active { transform: scale(0.94); }
.menu-close:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 3px; }

/* ---- the six steps ---- */
.menu-overlay nav {
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
}
.menu-overlay a,
.menu-overlay .menu-extra {
  display: grid;
  grid-template-columns: 2.4em 1fr auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 54px;
  padding: 8px 14px;
  border-radius: 14px;
  font-family: var(--serif);
  font-size: clamp(18px, 5vw, 23px);
  font-weight: 500;
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  transition: background 0.2s ease, color 0.2s ease;
}
.menu-overlay a em,
.menu-overlay .menu-extra em {
  font-family: var(--sans);
  font-style: normal;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--purple-soft);
  text-align: right;
  margin: 0;
  vertical-align: baseline;
}
.mi-label { min-width: 0; }
.mi-mark { opacity: 0; color: var(--purple-soft); font-size: 0.8em; transition: opacity 0.2s ease; }

.menu-overlay a:hover,
.menu-overlay .menu-extra:hover { background: rgba(255, 255, 255, 0.7); color: var(--purple-deep); }

/* where you are now */
.menu-overlay a.is-here {
  background: #fff;
  color: var(--purple-deep);
  font-weight: 600;
  box-shadow: 0 4px 16px rgba(72, 52, 130, 0.12);
}
.menu-overlay a.is-here em { color: var(--purple); }
.menu-overlay a.is-here .mi-mark { opacity: 1; }

/* the aside sits a little quieter than the numbered steps */
.menu-overlay .menu-extra {
  font-size: clamp(15px, 4.1vw, 18px);
  color: var(--ink-soft);
}
.menu-overlay .menu-extra em { color: var(--gold); font-size: 14px; }

.menu-overlay a.is-locked { opacity: 0.4; pointer-events: none; }

.menu-foot {
  margin: 16px 6px 4px;
  font-family: var(--script);
  font-size: clamp(14px, 4vw, 17px);
  color: var(--ink-soft);
  text-align: center;
}
.menu-foot span { color: var(--purple-soft); }

/* the sheet arrives with the overlay rather than simply being there */
.menu-overlay .menu-sheet {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.28s ease, transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}
.menu-overlay.is-open .menu-sheet { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .menu-overlay .menu-sheet { transition-duration: 0.01ms; transform: none; }
}

/* ============ STAGE & SCENES ============ */

.stage {
  position: fixed;
  inset: 0;
  /* `hidden` still creates a programmatically scrollable box. Focusing a
     control near the foot could move the whole stage upward and expose a
     cream strip underneath it. `clip` keeps the camera viewport sealed. */
  overflow: clip;
}

/* Keep pointer clicks from leaving a black browser rectangle around a whole
   journey step; keyboard users retain a clear focus ring on the step circle. */
.site-header .step:focus { outline: none; }
.site-header .step:focus-visible .step-dot {
  outline: 2px solid var(--purple-soft);
  outline-offset: 3px;
}
.scroll-space { display: none; }

.light-veil {
  position: absolute; inset: 0; z-index: 40;
  background: radial-gradient(circle at 55% 45%, #fff3dd 0%, #ffe9c4 35%, rgba(255, 233, 196, 0.85) 100%);
  opacity: 0; pointer-events: none;
}
.particles { position: absolute; inset: 0; z-index: 30; pointer-events: none; }

.scene {
  position: absolute; inset: 0;
  visibility: hidden; opacity: 0;
  pointer-events: none;
}
.scene.is-current { pointer-events: auto; }
.scene .kb, .scene .par { position: absolute; inset: 0; }
.scene .kb { will-change: transform; }

/* Fixed-aspect cover canvas — keeps hotspots pixel-aligned with the art */
.scene-canvas {
  position: absolute; top: 50%; left: 50%;
  width: max(100vw, calc(100vh * var(--r-wide)));
  height: max(100vh, calc(100vw / var(--r-wide)));
  transform: translate(-50%, -50%);
}
.scene-canvas .photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; }

/* Right-anchored photo frames for scenes 1–2 */
.photo-frame { position: absolute; top: 0; bottom: 0; right: 0; }
.frame-door { width: calc(100vh * var(--r-door)); max-width: 74vw; }
.frame-desk { width: calc(100vh * var(--r-desk)); max-width: 84vw; }
.photo-frame .photo {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: right center;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 20%);
          mask-image: linear-gradient(to right, transparent, #000 20%);
}
/* Entrance only: a longer fade gives the wider hero copy clean air before the
   doorway begins — without it the photograph runs under the headline and the
   writing is hard to read. This is the fade the prototype has. */
.frame-door .photo {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 34%);
          mask-image: linear-gradient(to right, transparent, #000 34%);
}

.hotspot-layer, .pin-layer, .twinkle-layer { position: absolute; inset: 0; }
.pin-layer, .twinkle-layer { pointer-events: none; }
/* The layer itself is a full-canvas transparent div sitting above the laptop
   screen; only its children should catch the pointer. Without this the entire
   booking calendar is unclickable. */
.hotspot-layer { pointer-events: none; }
.hotspot-layer > * { pointer-events: auto; }

/* copy columns */
.scene-copy {
  position: absolute;
  top: 50%; transform: translateY(-50%);
  left: clamp(24px, 5.5vw, 84px);
  z-index: 3;
  max-width: 520px;
}

.kicker { font-size: 19px; color: var(--ink); margin-bottom: 14px; }
.kicker.serif { font-family: var(--serif); font-size: 24px; }
.wave { font-size: 17px; }

.display {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(44px, 5vw, 66px);
  line-height: 1.12;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.display-md { font-size: clamp(36px, 4.2vw, 54px); }
.display .accent, .accent { color: var(--purple); }

.lede {
  font-size: 17px;
  font-weight: 300;
  color: var(--ink-soft);
  max-width: 420px;
  margin-top: 22px;
}

/* Buttons */
.btn {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: 16px; font-weight: 500;
  border-radius: 999px;
  padding: 16px 34px;
  transition: box-shadow 0.25s ease, background 0.25s ease;
  will-change: transform;
}
.btn-primary { background: var(--purple); color: #fff; box-shadow: 0 14px 30px rgba(124, 95, 196, 0.35); }
.btn-primary:hover { background: var(--purple-deep); box-shadow: 0 18px 36px rgba(95, 67, 174, 0.42); }
.btn-arrow { font-size: 18px; line-height: 1; transition: transform 0.25s ease; }
.btn:hover .btn-arrow { transform: translateX(4px); }

/* Bottom bar (scene 2) */
.panel-bar {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 88px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 44px;
  z-index: 5;
}
.bar-circle {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--purple); color: #fff;
  display: inline-grid; place-items: center;
  font-size: 18px;
  box-shadow: 0 10px 22px rgba(124, 95, 196, 0.35);
  transition: background 0.25s ease;
}
.bar-circle.light { background: rgba(255, 255, 255, 0.9); color: var(--ink); box-shadow: 0 8px 18px rgba(38, 36, 46, 0.12); }
.bar-back, .bar-next { display: inline-flex; align-items: center; gap: 14px; font-size: 15px; color: var(--ink); }
.bar-next:hover .bar-circle { background: var(--purple-deep); }
.bar-down {
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--purple); color: #fff; font-size: 19px;
  box-shadow: 0 10px 22px rgba(124, 95, 196, 0.4);
  animation: bob 2.4s ease-in-out infinite;
}
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }

/* Scroll cues */
.scroll-cue {
  position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%);
  z-index: 6;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  color: var(--purple); font-size: 15px; font-weight: 500;
}
.scroll-cue svg:first-child { width: 20px; height: 32px; }
.cue-arrow { width: 14px; height: 16px; animation: bob 2.4s ease-in-out infinite; }

.scene-cue {
  position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%);
  z-index: 6;
  display: inline-flex; align-items: center; gap: 10px;
  background: rgba(250, 246, 238, 0.88);
  backdrop-filter: blur(5px);
  border-radius: 999px;
  padding: 11px 26px;
  font-size: 14.5px; font-weight: 500; color: var(--ink);
  box-shadow: 0 12px 28px rgba(72, 52, 130, 0.16);
  will-change: transform;
}
.scene-cue svg { width: 15px; height: 25px; color: var(--purple); }

/* ============ SCENE 1 · ENTRANCE ============ */

.scene-entrance {
  background:
    radial-gradient(1000px 600px at 85% 10%, rgba(255, 231, 196, 0.55), transparent 60%),
    radial-gradient(800px 500px at 10% 90%, rgba(202, 188, 236, 0.28), transparent 60%),
    var(--cream);
}
/* --- hero copy column -------------------------------------------------- */
/* Wider than the default .scene-copy so the two display lines never wrap,
   and capped in vw so it never crowds the doorway on ultra-wide screens. */
.entrance-copy { max-width: min(720px, 48vw); }



/* The level line is a small purple eyebrow above the headline, as in the
   prototype — not the focal point. The headline below carries the weight. */
.hero-levels {
  font-family: var(--sans);
  font-weight: 600;
  font-size: clamp(11.5px, min(1.05vw, 2vh), 16px);
  line-height: 1.2;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--purple-deep);
  white-space: nowrap;
  margin-bottom: clamp(14px, 2.6vh, 28px);
}
.hero-levels .lv-sep {
  color: var(--purple-soft);
  font-weight: 600;
  margin: 0 0.3em;
}
.hero-levels .lv-a, .hero-levels .lv-b { display: inline; }

/* The headline: two serif lines, the second in purple. */
.hero-promise {
  max-width: 13.5em;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(26px, min(3.05vw, 5.6vh), 48px);
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.hero-promise span { display: block; }
.hero-promise .accent { color: var(--purple-deep); }

.entrance-copy .lede {
  max-width: 33em;
  margin-top: 18px;
  margin-bottom: 30px;
}

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

/* Secondary action: present for parents who arrive ready, but visually
   subordinate so the primary journey CTA keeps the hierarchy. */
.btn-quiet {
  position: relative;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink-soft);
  padding: 6px 2px;
  transition: color 0.25s ease;
}
.btn-quiet::after {
  content: "";
  position: absolute;
  left: 2px; right: 2px; bottom: 2px;
  height: 1.5px;
  background: currentColor;
  opacity: 0.35;
  transform-origin: left;
  transition: opacity 0.25s ease, transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.btn-quiet:hover { color: var(--purple-deep); }
.btn-quiet:hover::after { opacity: 1; transform: scaleX(1.02); }

/* --- second lede line, quieter than the first -------------------------- */
/* Overrides the margins set above: the promise is now two paragraphs, so the
   spacing below belongs to the quieter one. */
.entrance-copy .lede {
  font-size: clamp(15px, 1.25vw, 19px);
  max-width: 24.5em;
  margin-top: clamp(10px, 1.9vh, 18px);
  margin-bottom: 0;
}
.entrance-copy .lede-quiet {
  font-size: clamp(13px, 1.05vw, 16px);
  max-width: 27em;
  margin-top: clamp(8px, 1.4vh, 14px);
}
.entrance-actions { margin-top: clamp(16px, 2.8vh, 30px); }
/* Rounded rectangles, as drawn — the pill shape belongs to the later pages. */
.entrance-actions .btn-primary {
  border-radius: 12px;
  font-size: clamp(14px, 1.1vw, 16px);
  padding: clamp(13px, 1.9vh, 18px) clamp(20px, 1.9vw, 28px);
}
.entrance-actions .btn-quiet { color: var(--purple-deep); font-size: clamp(13px, 1vw, 15px); }
.entrance-actions .btn-quiet::after { opacity: 0.55; }
.entrance-actions .btn-quiet:hover::after { opacity: 1; }

/* --- four credentials, icon above label, hairline rules between --------- */
.trust-row {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  align-items: start;
  gap: 0;
  max-width: min(480px, 33.5vw);
  margin-top: clamp(14px, 2.6vh, 28px);
  font-size: clamp(11px, 0.95vw, 13.5px);
  line-height: 1.35;
  letter-spacing: 0.01em;
  color: var(--ink-soft);
}
.trust-row li {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(6px, 1.1vh, 11px);
  padding-right: clamp(8px, 1vw, 16px);
}
.trust-row li + li {
  padding-left: clamp(8px, 1vw, 16px);
  border-left: 1px solid rgba(38, 36, 46, 0.13);
}
.trust-row li:not(:last-child)::after { content: none; }
.trust-ic { color: var(--purple); line-height: 0; }
.trust-ic svg {
  width: clamp(20px, 1.85vw, 28px);
  height: clamp(20px, 1.85vw, 28px);
  display: block;
}

/* --- Google rating + the subjects actually taught ----------------------- */
.hero-proof {
  display: flex;
  align-items: stretch;
  gap: clamp(12px, 1.6vw, 26px);
  width: fit-content;
  max-width: min(730px, 51vw);
  margin-top: clamp(14px, 2.4vh, 26px);
  padding: clamp(10px, 1.5vh, 16px) clamp(12px, 1.3vw, 20px);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 10px 30px rgba(72, 52, 130, 0.1);
}
.proof-label {
  font-size: clamp(11.5px, 0.95vw, 14.5px);
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
  white-space: nowrap;
}
.proof-rating {
  display: flex; flex-direction: column; justify-content: center;
  gap: clamp(3px, 0.5vh, 6px);
}
.proof-stars {
  color: var(--gold);
  font-size: clamp(15px, 1.4vw, 21px);
  letter-spacing: 2px;
  line-height: 1;
}
.proof-score {
  display: flex; align-items: center; gap: 6px;
  font-size: clamp(11.5px, 0.95vw, 14px);
  line-height: 1.2;
  color: var(--ink-soft);
}
.proof-score strong { color: var(--ink); font-weight: 600; }
.g-mark { width: 16px; height: 16px; flex: none; }

.proof-subjects {
  display: flex; flex-direction: column;
  gap: clamp(6px, 1vh, 10px);
  padding-left: clamp(12px, 1.6vw, 26px);
  border-left: 1px solid rgba(38, 36, 46, 0.11);
}
.subject-icons {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: clamp(4px, 0.6vw, 12px);
}
.subject-icons li {
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(3px, 0.5vh, 5px);
  text-align: center;
}
.sub-ic {
  width: clamp(34px, 3.2vw, 48px);
  height: clamp(34px, 3.2vw, 48px);
  flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--serif);
  font-size: clamp(16px, 1.55vw, 23px);
  font-style: normal;
  line-height: 1;
}
/* Playfair's italic f overshoots its line box badly; without this the Further
   Maths mark stretched its circle into an oval taller than the other six. */
.sub-glyph {
  display: block;
  line-height: 1;
  white-space: nowrap;
  letter-spacing: 0.01em;
  transform: translateY(-0.02em);
}
.sub-ic i { font-style: italic; padding-right: 0.06em; }
/* the vinculum over the x, as it is drawn */
.sub-rad {
  border-top: 1px solid currentColor;
  padding: 0 0.08em;
  margin-left: 0.02em;
}
.sub-ic svg { width: 56%; height: 56%; }
.sub-name {
  font-size: clamp(9.5px, 0.8vw, 12px);
  line-height: 1.2;
  color: var(--ink-soft);
}
/* Each subject keeps its own tint, as on the prototype. */
.sub-maths     { background: #ece6f7; color: #5f43ae; }
.sub-physics   { background: #e4eefb; color: #2f6bb5; }
.sub-chemistry { background: #e5f4ec; color: #2f7d55; }
.sub-biology   { background: #fbe8ee; color: #b34a72; }
.sub-further   { background: #fdf0dd; color: #a9762a; }
.sub-english   { background: #f5efe6; color: #7a6448; }
.sub-geography { background: #ece6f7; color: #5f43ae; }

/* Short viewports (1280x720, 13" laptops with browser chrome): tighten the
   vertical rhythm, then shed the least essential rows in order, rather than
   let the hero clip. Nothing here ever introduces a scrollbar. */
@media (min-width: 861px) and (max-height: 860px) {
  .hero-levels { margin-bottom: 11px; }
  .hero-proof { padding: 9px 13px; }
}
@media (min-width: 861px) and (max-height: 780px) {
  .entrance-copy .lede { font-size: 16px; }
  .hero-levels { margin-bottom: 9px; }
  .entrance-copy .btn { padding: 13px 28px; }
  .entrance-copy .lede-quiet { display: none; }
}
@media (min-width: 861px) and (max-height: 700px) {
  .hero-proof { display: none; }      /* proof < action */
}
@media (min-width: 861px) and (max-height: 630px) {
  .trust-row { display: none; }
  .scene-entrance .scroll-cue { display: none; }
}

.door-glow {
  position: absolute;
  left: 22%; top: 10%; width: 26%; height: 68%;
  background: radial-gradient(50% 45% at 50% 42%, rgba(255, 214, 150, 0.85), rgba(255, 191, 120, 0.35) 55%, transparent 75%);
  filter: blur(6px);
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
}
.door-hotspot {
  position: absolute;
  left: 23%; top: 11%; width: 23%; height: 66%;
  border-radius: 46% 46% 6% 6%;
}
.door-hotspot:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 4px; }

/* ============ SCENE 2 · MEET YOUR TUTOR ============ */


.tutor-copy {
  max-width: 380px;
  background: linear-gradient(to right, rgba(243, 231, 211, 0.9), rgba(243, 231, 211, 0));
  border-radius: 24px;
  padding-right: 40px;
}
.squiggle { width: 200px; height: 20px; color: var(--purple-soft); margin: 10px 0 4px; display: block; }

.feature-list { list-style: none; margin: 30px 0 34px; display: flex; flex-direction: column; gap: 18px; }
.feature-list li { display: flex; align-items: center; gap: 16px; font-size: 15px; color: var(--ink); }
.feature-icon {
  width: 44px; height: 44px; flex: 0 0 44px;
  border-radius: 50%;
  background: #fff; color: var(--purple);
  display: grid; place-items: center;
  box-shadow: 0 8px 18px rgba(124, 95, 196, 0.18);
}
.feature-icon svg { width: 22px; height: 22px; }

.lamp-glow {
  position: absolute; right: 6%; top: 26%; width: 26%; height: 34%;
  background: radial-gradient(45% 40% at 55% 35%, rgba(255, 220, 160, 0.55), transparent 70%);
  mix-blend-mode: screen;
  pointer-events: none;
}
.candle-glow {
  position: absolute; right: 12.5%; top: 52%; width: 10%; height: 18%;
  background: radial-gradient(50% 45% at 50% 40%, rgba(255, 205, 140, 0.5), transparent 72%);
  mix-blend-mode: screen;
  pointer-events: none;
}
.note-hotspot {
  position: absolute;
  left: 70.5%; top: 31%; width: 12.5%; height: 35%;
  border-radius: 12px;
}
.note-hotspot:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 4px; }

/* ============ HOTSPOTS (scenes 3–7) ============ */

.hotspot {
  position: absolute;
  /* The painted signs are rounded rectangles whose corners run to about 6% of
     their width and 14.5% of their height — measured off the artwork, and the
     same ratio on all three rows. Matching it means the corners of the box are
     not clickable either, so the target is the bubble and not its bounding
     box. */
  border-radius: 6% / 14.5%;
  transition: transform 0.3s ease;
}
.hotspot::before {
  content: "";
  position: absolute; inset: -12%;
  pointer-events: none;   /* decoration only — see the note below */
  border-radius: 20px;
  background: radial-gradient(60% 60% at 50% 50%, rgba(255, 226, 168, 0.55), rgba(202, 188, 236, 0.25) 60%, transparent 78%);
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.35s ease;
}
.hotspot:hover::before, .hotspot:focus-visible::before { opacity: 1; }
.hotspot:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 3px; }

/* ---- the hit area is the button, and nothing else ----
   Every one of these decorations hangs outside the button: the glow by 12% of
   its size, the selected ring by 4px, the tick by 9px past the corner. They
   are children of a button that takes the pointer, so each of them was
   catching clicks as well — on a year sign that is around 21px of desk either
   side that selected the year. They are pictures, so they no longer take the
   pointer, and the sign itself is the target. */
.hotspot .badge {
  pointer-events: none;
  position: absolute; top: -9px; right: -9px;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--purple); color: #fff;
  font-size: 15px;
  display: grid; place-items: center;
  box-shadow: 0 8px 18px rgba(95, 67, 174, 0.45);
  transform: scale(0);
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.hotspot.is-selected .badge { transform: scale(1); }
.hotspot.is-selected::before {
  opacity: 1;
  background: radial-gradient(60% 60% at 50% 50%, rgba(202, 188, 236, 0.6), rgba(124, 95, 196, 0.28) 60%, transparent 80%);
}
.hotspot.is-selected::after {
  content: "";
  position: absolute; inset: -4px;
  pointer-events: none;
  border-radius: 18px;
  border: 2.5px solid rgba(124, 95, 196, 0.85);
  box-shadow: 0 0 22px rgba(124, 95, 196, 0.5);
}

.ghost-hotspot { position: absolute; border-radius: 18px; }
.ghost-hotspot:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 3px; }
.glow-hotspot::before {
  content: "";
  position: absolute; inset: -6%;
  pointer-events: none;
  border-radius: 999px;
  background: radial-gradient(55% 60% at 50% 50%, rgba(255, 231, 180, 0.5), transparent 75%);
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.35s ease;
}
.glow-hotspot:hover::before { opacity: 1; }

/* ============ JOURNEY FLOW (pages 3 → 4 → 5 → 7) ============ */

/* --- the prototype's own books, as independent elements ---
   Each button holds the exact artwork cut from the design prototype and sits
   back on the plate where it was cut from. Every transform is a SCALE about
   the bottom edge — a book grows off the shelf rather than sliding along it,
   so it can never uncover the slot it came from. That keeps the room pixel-
   faithful to the prototype while the books stay fully animatable. */

.book {
  position: absolute;
  padding: 0;
  border: 0;
  background: none;
  transform-origin: 50% 100%;
  transition:
    transform 0.42s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.35s ease;
  /* entrance state; .is-in on the layer settles them onto the shelf */
  opacity: 0;
  transform: scale(0.94) translateY(2%);
}
.hotspot-layer.is-in .book {
  opacity: 1;
  transform: scale(1) translateY(0);
  transition:
    transform 0.62s cubic-bezier(0.22, 1, 0.36, 1) calc(var(--i, 0) * 55ms),
    opacity 0.5s ease calc(var(--i, 0) * 55ms),
    filter 0.35s ease;
}

.book-img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: fill;      /* the crop already matches the slot exactly */
  pointer-events: none;
  user-select: none;
}

/* A book lifts a little under the pointer, and shows the same lift when the
   keyboard reaches it. The pointer half is gated on there being a pointer: a
   touch browser applies `:hover` to whatever was tapped last and leaves it
   there, so without the gate a book that had been unchosen stayed standing
   forward at 1.045 with no tick on it. A laptop reports `hover: hover` and is
   unaffected. */
.hotspot-layer.is-in .book:focus-visible {
  transform: scale(1.045);
  filter: brightness(1.07) drop-shadow(0 16px 26px rgba(38, 22, 8, 0.42));
  z-index: 2;
}
@media (hover: hover) {
  .hotspot-layer.is-in .book:hover {
    transform: scale(1.045);
    filter: brightness(1.07) drop-shadow(0 16px 26px rgba(38, 22, 8, 0.42));
    z-index: 2;
  }
}
.book:focus-visible { outline: none; }
.book:focus-visible::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 5px;
  border: 2.5px solid var(--purple-soft);
}

.hotspot-layer.is-in .book.is-selected {
  transform: scale(1.075);
  filter: brightness(1.1) drop-shadow(0 20px 32px rgba(95, 67, 174, 0.5));
  z-index: 3;
}
.book.is-selected .book-img {
  outline: 2px solid rgba(226, 190, 116, 0.9);
  outline-offset: -2px;
}

.book .badge {
  position: absolute;
  top: -11px; right: -11px;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--purple);
  color: #fff;
  font-size: 15px;
  display: grid;
  place-items: center;
  box-shadow: 0 8px 18px rgba(95, 67, 174, 0.45);
  transform: scale(0);
  transition: transform 0.38s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.book.is-selected .badge { transform: scale(1); }

@media (prefers-reduced-motion: reduce) {
  .book, .hotspot-layer.is-in .book { transition-duration: 0.01ms; opacity: 1; }
}

/* --- continue bar shared by pages 3 and 4 --- */
.flow-bar {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: max-content;
  max-width: min(92vw, 620px);
}
.flow-bar .scene-cue { position: static; transform: none; left: auto; bottom: auto; }

.flow-status {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
  background: rgba(250, 246, 238, 0.9);
  backdrop-filter: blur(5px);
  padding: 7px 17px;
  border-radius: 999px;
  box-shadow: 0 8px 20px rgba(72, 52, 130, 0.12);
  transition: color 0.3s ease, background 0.3s ease;
}
.flow-status.is-on {
  color: var(--purple-deep);
  font-weight: 600;
  background: rgba(236, 230, 247, 0.94);
}
.flow-status.is-warn {
  color: #9d3f3f;
  font-weight: 600;
  background: rgba(250, 235, 235, 0.96);
  box-shadow: 0 8px 20px rgba(157, 63, 63, 0.18);
}

/* Once a choice is made the cue stops being a hint and becomes the next step. */
.cue-go { display: none; font-size: 17px; line-height: 1; }
.scene-cue.is-ready {
  background: var(--purple);
  color: #fff;
  box-shadow: 0 14px 30px rgba(124, 95, 196, 0.4);
}
.scene-cue.is-ready svg:first-child { display: none; }
.scene-cue.is-ready .cue-go { display: inline; }

/* --- page 5: what the visitor already chose, legible outside the laptop --- */
.booking-summary {
  position: absolute;
  left: clamp(20px, 4vw, 56px);
  bottom: clamp(20px, 6vh, 74px);
  z-index: 7;
  width: min(300px, 34vw);
  padding: 20px 22px;
  border-radius: 18px;
  background: rgba(250, 246, 238, 0.94);
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow);
}
.bs-title { font-family: var(--serif); font-size: 17px; font-weight: 600; color: var(--purple-deep); }
.bs-rows { margin-top: 12px; display: flex; flex-direction: column; gap: 9px; }
.bs-rows > div { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.bs-rows dt { font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-soft); }
.bs-rows dd { font-size: 15px; font-weight: 600; color: var(--ink); text-align: right; }
.booking-summary.is-partial .bs-rows dd { font-weight: 400; color: var(--ink-soft); }
.bs-note { margin-top: 12px; font-size: 12.5px; line-height: 1.45; color: var(--ink-soft); }
.bs-change {
  margin-top: 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--purple-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.bs-change:hover { color: var(--purple); }

/* --- page 7: route back to booking, but only when it is still needed --- */
.farewell-panel {
  position: absolute;
  left: 50%;
  bottom: clamp(22px, 6vh, 64px);
  transform: translateX(-50%);
  z-index: 7;
  width: min(460px, 90vw);
  text-align: center;
  padding: 22px 26px 24px;
  border-radius: 20px;
  background: rgba(250, 246, 238, 0.95);
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow);
}
.fp-title { font-family: var(--serif); font-size: clamp(19px, 1.5vw, 23px); font-weight: 600; color: var(--ink); }
.fp-body { margin-top: 7px; font-size: 14px; line-height: 1.5; color: var(--ink-soft); }
.fp-cta { margin-top: 16px; }
.farewell-panel.is-booked .fp-title { color: var(--purple-deep); }
.farewell-panel.is-booked .fp-cta {
  background: transparent;
  color: var(--purple-deep);
  box-shadow: inset 0 0 0 1.5px var(--lavender);
}
.farewell-panel.is-booked .fp-cta:hover { background: var(--lavender-bg); box-shadow: inset 0 0 0 1.5px var(--purple-soft); }

/* ============ PAGE 5 · BOOKING SCREEN ============
   Sized in container-query units against the laptop screen, so the whole app
   scales with the photograph instead of being pinned to px. */

.laptop-screen {
  position: absolute;
  left: 25.78%;
  top: 26.49%;
  width: 46.35%;
  height: 48.57%;
  border-radius: 0.5vw;
  overflow: hidden;
  background: #fdfaf5;
  box-shadow: inset 0 0 14px rgba(60, 40, 20, 0.14);
  container-type: size;
  z-index: 5;
}

.bk {
  display: grid;
  grid-template-columns: 47% 53%;
  width: 100%;
  height: 100%;
  font-size: 3.1cqh;
  color: var(--ink);
}

.bk-col { padding: 4.6cqh 3.4cqw; min-height: 0; }
/* A class-level `display` beats the UA rule for [hidden], which left the
   hidden form still occupying its grid row and pushing the confirmation
   out of the screen. This makes the two genuinely mutually exclusive. */
.bk-col[hidden], .bk-confirm[hidden] { display: none !important; }
.bk-left { border-right: 1px solid rgba(38, 36, 46, 0.09); display: flex; flex-direction: column; }
.bk-right { display: flex; flex-direction: column; }

.bk-step {
  font-family: var(--serif);
  font-size: 4cqh;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 1.6cqh;
}
.bk-step em { font-style: normal; color: var(--purple); margin-right: 0.5em; }
.bk-step span { font-family: var(--sans); font-size: 2.7cqh; font-weight: 400; color: var(--ink-soft); }
.bk-step-time { margin-top: 2.4cqh; }
.bk-sub { font-size: 2.8cqh; color: var(--ink-soft); margin-bottom: 2.2cqh; }

/* ---- calendar ---- */

.cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.4cqh; }
.cal-head strong { font-size: 3.3cqh; font-weight: 600; }
.cal-nav {
  width: 5.6cqh; height: 5.6cqh;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 3.2cqh; color: var(--ink-soft);
  transition: background 0.2s, color 0.2s;
}
.cal-nav:hover { background: var(--lavender-bg); color: var(--purple-deep); }
.cal-nav:disabled { opacity: 0.28; pointer-events: none; }

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.5cqh 0.2cqw; text-align: center; }
.cal-dow { font-size: 2.1cqh; font-weight: 600; letter-spacing: 0.05em; color: var(--ink-soft); padding: 0.5cqh 0; }
.cal-day {
  font-size: 2.7cqh;
  padding: 0.9cqh 0;
  border-radius: 999px;
  color: var(--ink);
  transition: background 0.18s, color 0.18s, transform 0.18s;
}
.cal-day:hover:not(:disabled) { background: var(--lavender-bg); }
.cal-day.is-muted, .cal-day:disabled { color: #cbc4b8; pointer-events: none; }
.cal-day.is-blank { visibility: hidden; }
.cal-day.is-today { box-shadow: inset 0 0 0 1.5px var(--purple-soft); }
.cal-day.is-picked {
  background: var(--purple);
  color: #fff;
  transform: scale(1.06);
  box-shadow: 0 3px 10px rgba(124, 95, 196, 0.4);
}

/* ---- time select ---- */

.bk-selectwrap { position: relative; display: flex; align-items: center; }
.bk-selectwrap > svg {
  position: absolute; left: 2cqw;
  width: 3.4cqh; height: 3.4cqh;
  color: var(--purple);
  pointer-events: none;
}
.bk-selectwrap select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  font-family: var(--sans);
  font-size: 2.9cqh;
  color: var(--ink);
  padding: 1.8cqh 4cqw 1.8cqh 7cqw;
  border: 0.35cqh solid #e6ddcd;
  border-radius: 1.6cqh;
  background: #fff;
  cursor: pointer;
  transition: border-color 0.2s;
}
.bk-selectwrap select:focus { outline: none; border-color: var(--purple-soft); }
.bk-selectwrap select:disabled { opacity: 0.55; cursor: not-allowed; }
.bk-selectwrap::after {
  content: "";
  position: absolute; right: 3cqw;
  width: 1.5cqh; height: 1.5cqh;
  border-right: 0.35cqh solid var(--ink-soft);
  border-bottom: 0.35cqh solid var(--ink-soft);
  transform: rotate(45deg) translateY(-25%);
  pointer-events: none;
}
.bk-note { margin-top: 1.2cqh; font-size: 2.4cqh; color: var(--ink-soft); }

/* ---- details ---- */

.bk-field { position: relative; display: flex; align-items: center; margin-bottom: 1.6cqh; }
.bk-field > svg {
  position: absolute; left: 2cqw;
  width: 3.3cqh; height: 3.3cqh;
  color: var(--ink-soft);
  pointer-events: none;
}
.bk-field input {
  width: 100%;
  font-family: var(--sans);
  font-size: 2.8cqh;
  font-weight: 300;
  color: var(--ink);
  padding: 1.7cqh 2.5cqw 1.7cqh 7cqw;
  border: 0.35cqh solid #e6ddcd;
  border-radius: 1.6cqh;
  background: #fff;
  transition: border-color 0.2s;
}
.bk-field input:focus { outline: none; border-color: var(--purple-soft); }
.bk-field input.is-error { border-color: #cf6d6d; background: #fdf6f6; }

.bk-contact { border: 0; padding: 0; margin: 0 0 1.6cqh; }
.bk-contact legend { font-size: 2.7cqh; font-weight: 500; margin-bottom: 1.1cqh; padding: 0; }
.bk-choices { display: grid; grid-template-columns: 1fr 1fr; gap: 0 2cqw; }
.bk-radio {
  display: flex; align-items: center; gap: 1.4cqw;
  padding: 1.5cqh 2cqw;
  border: 0.35cqh solid #e6ddcd;
  border-radius: 1.6cqh;
  background: #fff;
  font-size: 2.8cqh;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.bk-radio input { accent-color: var(--purple); width: 2.8cqh; height: 2.8cqh; margin: 0; cursor: pointer; }
.bk-radio:has(input:checked) { border-color: var(--purple); background: var(--lavender-bg); font-weight: 500; }
.bk-radio:focus-within { outline: 2px solid var(--purple-soft); outline-offset: 2px; }

.bk-hint { font-size: 2.4cqh; color: var(--ink-soft); margin-bottom: 1.4cqh; line-height: 1.4; }

.bk-submit {
  margin-top: auto;
  width: 100%;
  background: var(--purple);
  color: #fff;
  font-family: var(--sans);
  font-size: 3.1cqh;
  font-weight: 500;
  padding: 2cqh 0;
  border-radius: 1.8cqh;
  box-shadow: 0 6px 18px rgba(124, 95, 196, 0.32);
  transition: background 0.22s ease, opacity 0.22s ease;
  will-change: transform;
}
.bk-submit:hover:not(:disabled) { background: var(--purple-deep); }
.bk-submit:disabled { opacity: 0.42; cursor: not-allowed; box-shadow: none; }
.bk-safe { margin-top: 1.1cqh; font-size: 2.2cqh; color: var(--ink-soft); text-align: center; line-height: 1.4; }

/* ---- confirmation (replaces the form, never overlays it) ---- */

/* [hidden] must win over the class display, or the confirmation keeps a grid
   row and squashes the form underneath it. */
.bk-done[hidden], .bk-col[hidden], .bk-field[hidden] { display: none !important; }

.bk-edit {
  margin-top: 2.4cqh;
  align-self: flex-start;
  font-size: 2.7cqh;
  font-weight: 500;
  color: var(--purple-deep);
  padding: 1.2cqh 0;
  border-bottom: 0.3cqh solid rgba(124, 95, 196, 0.4);
  transition: color 0.2s, border-color 0.2s;
}
.bk-edit:hover { color: var(--purple); border-color: var(--purple); }

/* ============ SCENE 6 · REVIEWS ============
   The review artwork is a finished asset and carries its own text. The only
   live element here is the Google CTA, styled further down. */

/* ============ SCENE 6 · TWINKLES ============ */

.pin { position: absolute; will-change: transform; }
.pin img { width: 100%; height: 100%; display: block; }

.twinkle {
  position: absolute;
  width: 10px; height: 10px;
  color: var(--gold);
  animation: twinkle 2.8s ease-in-out infinite;
}
.twinkle svg { width: 100%; height: 100%; display: block; }
@keyframes twinkle {
  0%, 100% { opacity: 0.15; transform: scale(0.7) rotate(0deg); }
  50% { opacity: 1; transform: scale(1.25) rotate(20deg); }
}

/* ============ FALLBACK CHOICES (mobile / simple mode) ============ */

.fallback-choices { display: none; }

/* ============ BURST PARTICLES ============ */

.burst-star {
  position: fixed;
  z-index: 80;
  pointer-events: none;
  color: var(--gold);
  font-size: 14px;
  line-height: 1;
}
.burst-star.purple { color: var(--purple-soft); }

/* ============ SIMPLE MODE (mobile · reduced motion · no JS libs) ============ */

body.simple { overflow-x: hidden; }
body.simple .boot-veil { display: none; }
body.simple .cursor { display: none; }
body.simple .stage { position: static; overflow: visible; }
body.simple .scroll-space { display: none; }
body.simple .light-veil, body.simple .particles { display: none; }

body.simple .scene {
  position: absolute;
  inset: 0;
  min-height: 0;
  visibility: visible; opacity: 1;
  pointer-events: auto;
  display: flex; flex-direction: column; justify-content: center;
  overflow: hidden;
}
body.simple .scene .kb, body.simple .scene .par { position: absolute; inset: 0; }

/* simple mode shows exactly one scene, like the cinematic stage */
body.simple .stage { position: fixed; inset: 0; overflow: hidden; }
body.simple .scene {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.45s ease, visibility 0.45s;
  overflow: hidden;
}
body.simple .scene.is-current {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

body.simple .line-in, body.simple .pop-in { opacity: 0; transform: translateY(24px); transition: opacity 0.7s ease, transform 0.7s ease; }
body.simple .is-in .line-in, body.simple .is-in .pop-in { opacity: 1; transform: none; }
body.simple .pin { opacity: 1 !important; transform: none !important; }

/* ---- secondary CTA: skip the call, book a lesson ---- */

.bk-alt {
  margin-top: 1.1cqh;
  text-align: center;
  font-size: 2.3cqh;
  color: var(--ink-soft);
  line-height: 1.4;
}
.bk-altlink {
  font-family: var(--sans);
  font-size: 2.3cqh;
  font-weight: 600;
  color: var(--purple-deep);
  padding: 0.4cqh 0.2cqw;
  border-bottom: 0.28cqh solid rgba(124, 95, 196, 0.4);
  transition: color 0.2s, border-color 0.2s;
}
.bk-altlink:hover { color: var(--purple); border-color: var(--purple); }

/* the form goes quiet once the confirmation panel is up */
.bk.is-locked { opacity: 0.42; pointer-events: none; filter: saturate(0.7); }
.bk { transition: opacity 0.4s ease, filter 0.4s ease; }

/* ============ PAGE 5 · CONFIRMATION PANEL ============
   Its own card beside the laptop, sized to the composition rather than
   floating in the middle of the screen. */

/* ---- confirmation: fills the laptop screen, replacing the form ---- */

.bk-confirm {
  /* Pinned to the screen bounds rather than sized by the grid row, which
     tracked the form's height and left the panel hanging past the laptop. */
  position: absolute;
  inset: 0;
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 1cqh;
  padding: 2.8cqh 6cqw;
  background: linear-gradient(168deg, #fdfaf4 0%, #f7f1e6 100%);
  overflow-y: auto;
  animation: bkcIn 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes bkcIn {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

.bkc-tick {
  width: 12cqh; height: 12cqh;
  border-radius: 50%;
  background: var(--purple);
  color: #fff;
  display: grid;
  place-items: center;
  box-shadow: 0 1.6cqh 3cqh rgba(124, 95, 196, 0.4);
  flex: none;
}
.bkc-tick svg { width: 58%; height: 58%; }

.bkc-title {
  font-family: var(--script);
  font-size: 7.6cqh;
  line-height: 1.05;
  color: var(--purple-deep);
}
.bkc-lead { font-size: 2.9cqh; color: var(--ink-soft); line-height: 1.4; max-width: 34em; }

.bkc-when {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1cqh 3cqw;
  width: 100%;
  padding: 1.5cqh 0;
  border-top: 1px solid rgba(38, 36, 46, 0.1);
  border-bottom: 1px solid rgba(38, 36, 46, 0.1);
}
.bkc-chip { display: inline-flex; align-items: center; gap: 1cqw; font-size: 3cqh; font-weight: 600; }
.bkc-chip svg { width: 3.4cqh; height: 3.4cqh; color: var(--purple); flex: none; }
.bkc-chip em { font-style: normal; }

.bkc-rows {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1.1cqh 3cqw;
  width: 100%;
  max-width: 84%;
  font-size: 2.7cqh;
  text-align: left;
}
.bkc-rows > div { display: contents; }
.bkc-rows dt { color: var(--ink-soft); }
.bkc-rows dd { font-weight: 600; text-align: right; overflow-wrap: anywhere; }

.bkc-ref { font-size: 2.3cqh; color: var(--ink-soft); }
.bkc-ref span { font-family: ui-monospace, "SF Mono", Menlo, monospace; color: var(--ink); }

.bkc-home {
  width: 60%;
  font-family: var(--sans);
  font-size: 3cqh;
  font-weight: 600;
  color: var(--purple-deep);
  padding: 2.5cqh 0;
  border-radius: 1.6cqh;
  background: #fff;
  box-shadow: inset 0 0 0 1.5px rgba(124, 95, 196, 0.45);
  transition: background 0.22s, color 0.22s;
}
.bkc-home:hover { background: var(--purple); color: #fff; box-shadow: none; }
/* says where the button goes, so the label does not have to carry it */
.bkc-home-lead {
  margin-top: 1.2cqh;
  font-size: 2.3cqh;
  line-height: 1.45;
  color: var(--ink-soft);
  max-width: 30em;
}

.bkc-edit-lead { font-size: 2.3cqh; color: var(--ink-soft); }
.bkc-edit {
  font-family: var(--sans);
  font-size: 2.7cqh;
  font-weight: 600;
  color: var(--purple-deep);
  border-bottom: 1.5px solid rgba(124, 95, 196, 0.4);
  padding-bottom: 0.4cqh;
  transition: color 0.2s, border-color 0.2s;
}
.bkc-edit:hover { color: var(--purple); border-color: var(--purple); }

@keyframes bkcIn {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}


/* ============ PAGE 6 · GOOGLE REVIEW CTA ============
   The reviews themselves are the artwork; this is the only live element.
   Centred under the review cards, with room to breathe. */

.reviews-layer { position: absolute; inset: 0; pointer-events: none; }

.review-cta {
  position: absolute;
  left: 50%;
  bottom: 7.5%;
  transform: translateX(-50%);
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.75vw;
  white-space: nowrap;
  font-family: var(--sans);
  font-size: clamp(13px, 1.16vw, 20px);
  font-weight: 600;
  color: #fff;
  text-decoration: none;
  padding: 0.95vw 2.6vw;
  border-radius: 999px;
  background: var(--purple);
  box-shadow: 0 1vw 2.2vw rgba(95, 67, 174, 0.42);
  transition: background 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
}
.review-cta:hover {
  background: var(--purple-deep);
  box-shadow: 0 1.3vw 2.8vw rgba(95, 67, 174, 0.5);
  transform: translateX(-50%) translateY(-2px);
}
.review-cta:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }
.review-cta svg { width: 1.25em; height: 1.25em; flex: none; }
.review-cta-ext { font-size: 0.85em; opacity: 0.85; }

/* pull the wall art back a touch so the CTA has breathing room */
.scene-stories .scene-canvas .photo { transform-origin: 50% 42%; }
.scene-stories .scene-canvas { --wall-zoom: 0.94; }

@media (max-width: 1280px) {
  .step { min-width: 64px; }
  .step-line { width: 30px; }
}
@media (max-width: 1080px) {
  .step-label { display: none; }
  .step { min-width: 46px; }
}

/* Small screens: scenes become stacked cards with photo up top and choices below */
@media (max-width: 860px) {
  :root { --header-h: 74px; }
  .site-header { padding: 0 20px; }
  .brand-name { font-size: 28px; }

  body.simple .scene { min-height: 0; padding: 0 0 40px; }
  body.simple .scene .kb { position: relative; inset: auto; }
  body.simple .scene .par { position: relative; inset: auto; }

  body.simple .photo-frame {
    position: relative; right: auto; width: 100%; max-width: none;
    aspect-ratio: var(--r-door);
  }
  body.simple .scene-entrance { padding-top: var(--header-h); }
  body.simple .frame-desk { aspect-ratio: var(--r-desk); }
  body.simple .photo-frame .photo {
    mask-image: linear-gradient(to bottom, #000 78%, transparent);
    -webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent);
    object-position: center;
  }
  body.simple .scene-copy {
    position: relative; top: auto; transform: none; left: auto;
    padding: 12px 24px 0;
    max-width: 560px;
  }
  body.simple .panel-bar { position: relative; height: auto; padding: 26px 24px 0; }
  body.simple .bar-down { display: none; }
  body.simple .scroll-cue { display: none; }
  body.simple .scene-cue { display: none; }

  body.simple .scene-canvas {
    position: relative; top: auto; left: auto; transform: none;
    width: 100%; height: auto; aspect-ratio: var(--r-wide);
  }
  body.simple .scene-canvas .photo { position: absolute; inset: 0; }
  body.simple .hotspot-layer { display: none; }

  body.simple .fallback-choices {
    display: flex; flex-wrap: wrap; gap: 10px;
    justify-content: center;
    padding: 22px 24px 0;
  }

  /* Subject choices on touch: the prototype's own books, as a tappable grid.
     The name is printed on the artwork, so the card needs no extra label. */
  #subjectChoices {
    display: grid;
    /* explicit columns: auto-fit's min track can exceed a narrow viewport */
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    width: 100%;
    max-width: 460px;
    margin: 0 auto;
    padding: 22px 24px 0;
  }
  @media (max-width: 359px) {
    #subjectChoices { grid-template-columns: repeat(3, 1fr); }
  }
  .book-card {
    position: relative;
    padding: 0;
    border: 0;
    background: none;
    aspect-ratio: var(--ratio, 0.33);
    min-height: 132px;
    border-radius: 3px;
    filter: drop-shadow(0 8px 16px rgba(38, 22, 8, 0.28));
    transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), filter 0.3s ease;
  }
  .book-card img { width: 100%; height: 100%; display: block; object-fit: fill; }
  .book-card.is-selected {
    transform: translateY(-6px) scale(1.04);
    filter: drop-shadow(0 14px 24px rgba(95, 67, 174, 0.45));
  }
  .book-card.is-selected img { outline: 2px solid rgba(226, 190, 116, 0.95); outline-offset: -2px; }
  .card-tick {
    position: absolute;
    top: -9px; right: -9px;
    width: 26px; height: 26px;
    border-radius: 50%;
    background: var(--purple);
    color: #fff;
    font-size: 13px;
    display: grid;
    place-items: center;
    box-shadow: 0 6px 14px rgba(95, 67, 174, 0.45);
    transform: scale(0);
    transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  .book-card.is-selected .card-tick { transform: scale(1); }
  .chip {
    font-size: 14px; font-weight: 500;
    padding: 10px 18px;
    border-radius: 999px;
    background: var(--paper);
    box-shadow: 0 8px 18px rgba(72, 52, 130, 0.1);
    border: 2px solid transparent;
    transition: all 0.25s ease;
  }
  .chip.is-selected { background: var(--purple); color: #fff; border-color: var(--purple); }


  /* ---- PAGE 5 on touch: a real stacked form, not a shrunken laptop ----
     The desktop app is sized in cqh against the laptop screen. On a phone that
     container is only ~218px tall, which collapses every unit to a few pixels,
     so the container query is switched off and everything is re-stated in px. */
  body.simple .laptop-screen {
    position: relative;
    left: auto; top: auto;
    width: calc(100% - 40px);
    height: auto;
    aspect-ratio: auto;
    container-type: normal;
    margin: -12vw auto 0;
    border-radius: 20px;
    box-shadow: var(--shadow);
    background: #fdfbf7;
    z-index: 5;
  }

  body.simple .bk {
    grid-template-columns: 1fr;
    height: auto;
    font-size: 15px;
  }
  body.simple .bk-col { padding: 20px 18px; }
  body.simple .bk-left {
    border-right: 0;
    border-bottom: 1px solid rgba(38, 36, 46, 0.1);
  }

  body.simple .bk-step { font-size: 17px; margin-bottom: 10px; }
  body.simple .bk-step span { font-size: 13px; }
  body.simple .bk-step-time { margin-top: 18px; }
  body.simple .bk-sub { font-size: 13.5px; margin-bottom: 14px; }

  body.simple .cal-head { margin-bottom: 10px; }
  body.simple .cal-head strong { font-size: 15.5px; }
  body.simple .cal-nav { width: 40px; height: 40px; font-size: 17px; }
  body.simple .cal-grid { gap: 3px 2px; }
  body.simple .cal-dow { font-size: 10.5px; padding: 4px 0; }
  body.simple .cal-day { font-size: 14px; padding: 9px 0; min-height: 38px; }

  body.simple .bk-selectwrap > svg { left: 14px; width: 18px; height: 18px; }
  body.simple .bk-selectwrap select {
    font-size: 16px;                 /* 16px stops iOS zooming on focus */
    padding: 14px 34px 14px 42px;
    border-width: 2px;
    border-radius: 12px;
    min-height: 50px;
  }
  body.simple .bk-selectwrap::after { right: 16px; width: 8px; height: 8px; border-width: 0 2px 2px 0; }
  body.simple .bk-note { font-size: 12.5px; margin-top: 8px; }

  body.simple .bk-field { margin-bottom: 12px; }
  body.simple .bk-field > svg { left: 14px; width: 18px; height: 18px; }
  body.simple .bk-field input {
    font-size: 16px;
    padding: 14px 14px 14px 42px;
    border-width: 2px;
    border-radius: 12px;
    min-height: 50px;
  }

  body.simple .bk-contact { margin-bottom: 12px; }
  body.simple .bk-contact legend { font-size: 14px; margin-bottom: 8px; }
  body.simple .bk-choices { gap: 0 10px; }
  body.simple .bk-radio {
    font-size: 15px;
    padding: 13px 12px;
    gap: 9px;
    border-width: 2px;
    border-radius: 12px;
    min-height: 50px;
  }
  body.simple .bk-radio input { width: 18px; height: 18px; }
  body.simple .bk-hint { font-size: 12.5px; margin-bottom: 14px; }

  body.simple .bk-submit {
    font-size: 16px;
    padding: 16px 0;
    border-radius: 14px;
    min-height: 52px;
    margin-top: 4px;
  }
  body.simple .bk-safe { font-size: 12px; margin-top: 10px; }

  body.simple .bk-edit { font-size: 14.5px; margin-top: 16px; min-height: 44px; }

  /* ---- PAGE 6 reviews on touch: stacked cards below the artwork ---- */
  body.simple .reviews-layer { position: absolute; inset: 0; }

  /* ---- confirmation on touch: a full-width card under the laptop ----
     Container units are sized for the desktop panel; stacked, it needs
     real px so the type stays readable and targets stay tappable. */
  body.simple .bk-confirm {
    position: relative;
    right: auto;
    top: auto;
    transform: none;
    width: calc(100% - 40px);
    max-width: 420px;
    max-height: none;
    overflow: visible;
    margin: 18px auto 0;
    padding: 22px 20px 20px;
    border-radius: 18px;
    gap: 10px;
    container-type: normal;
    animation: none;
  }
  body.simple .bkc-tick { width: 56px; height: 56px; box-shadow: 0 10px 20px rgba(124, 95, 196, 0.35); }
  body.simple .bkc-title { font-size: 26px; }
  body.simple .bkc-lead { font-size: 14px; }
  body.simple .bkc-when { gap: 8px 18px; padding: 12px 0; }
  body.simple .bkc-chip { font-size: 14.5px; gap: 8px; }
  body.simple .bkc-chip svg { width: 17px; height: 17px; }
  body.simple .bkc-rows { font-size: 14px; gap: 8px 14px; }
  body.simple .bkc-ref { font-size: 12.5px; }
  body.simple .bkc-home {
    font-size: 15.5px;
    padding: 14px 0;
    border-radius: 13px;
    min-height: 48px;
  }
  body.simple .bkc-edit-lead { font-size: 12.5px; }
  body.simple .bkc-edit {
    font-size: 14.5px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding-bottom: 0;
  }
  body.simple .review-cta {
    left: 50%;
    bottom: 5%;
    font-size: 13.5px;
    padding: 12px 20px;
    min-height: 44px;
    gap: 8px;
    box-shadow: 0 10px 22px rgba(95, 67, 174, 0.4);
  }
  body.simple .review-cta:hover { transform: translateX(-50%); }

  body.simple .scene-year, body.simple .scene-subject, body.simple .scene-stories { background: var(--cream); }
  body.simple .scene-call { background: var(--cream-2); }
  body.simple .scene-soon { background: var(--cream); }

  /* ---- JOURNEY FLOW on the phone: panels stack instead of floating ---- */
  body.simple .flow-bar {
    position: relative;
    left: auto; bottom: auto;
    transform: none;
    width: 100%;
    max-width: 560px;
    margin: 18px auto 0;
    padding: 0 24px;
  }
  /* the generic `body.simple .scene-cue { display:none }` must not swallow the
     cue now that it is the primary way forward */
  body.simple .flow-bar .scene-cue {
    display: inline-flex;
    width: 100%;
    justify-content: center;
    min-height: 48px;
  }
  body.simple .flow-status { text-align: center; }

  body.simple .booking-summary,
  body.simple .farewell-panel {
    position: relative;
    left: auto; bottom: auto;
    transform: none;
    width: calc(100% - 48px);
    margin: 20px auto 0;
    backdrop-filter: none;
  }
  body.simple .booking-summary { max-width: 560px; }
  body.simple .farewell-panel { max-width: 560px; }
  .farewell-panel .fp-cta { width: 100%; justify-content: center; min-height: 48px; }
  .bs-change { min-height: 44px; display: inline-flex; align-items: center; }

  /* ---- HERO, composed for the phone (not a shrunk desktop) ----
     Shallower door crop buys ~50px so the headline, CTA and proof line all
     land inside the first screen. */
  body.simple .frame-door {
    aspect-ratio: auto;
    height: min(70vw, 34vh);
  }
  body.simple .frame-door .photo { object-position: 38% 42%; }

  .eyebrow {
    margin-bottom: 13px;
    gap: 0 8px;
    font-size: 11px;
    letter-spacing: 0.16em;
  }
  .eyebrow::before { width: 22px; }

  .hero-levels {
    font-size: clamp(25px, 8.2vw, 38px);
    line-height: 1.04;
    margin-bottom: 10px;
    white-space: normal;
  }
  .hero-levels .lv-a, .hero-levels .lv-b { display: block; white-space: nowrap; }
  .hero-levels .lv-mid { display: none; }
  .hero-promise { font-size: clamp(17px, 4.6vw, 22px); }
  .entrance-copy .lede {
    font-size: 15.5px;
    max-width: 34em;
    margin-top: 12px;
    margin-bottom: 20px;
  }

  /* Thumb-first: full-width primary, secondary centred beneath it. */
  .entrance-actions { flex-direction: column; align-items: stretch; gap: 10px; }
  .entrance-actions .btn-primary {
    width: 100%;
    justify-content: center;
    padding: 16px 24px;
  }
  .btn-quiet {
    align-self: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;          /* WCAG 2.5.8 target size */
    padding: 10px 8px;
  }

  /* A wrapped inline row is ~23px shorter than a stacked list and keeps the
     whole hero — proof line included — inside the first screen. */
  .trust-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 100%;
    margin-top: 16px;
    row-gap: 10px;
    font-size: 12px;
    line-height: 1.35;
  }
  .trust-row li { flex-direction: row; align-items: center; gap: 8px; }
  .trust-ic svg { width: 18px; height: 18px; }
  /* With two columns the rule belongs to the right-hand cell only. */
  .trust-row li + li { padding-left: 0; border-left: 0; }
  .trust-row li:nth-child(2n) {
    padding-left: 14px;
    border-left: 1px solid rgba(38, 36, 46, 0.13);
  }

  .hero-proof {
    flex-direction: column;
    width: 100%;
    max-width: 420px;
    gap: 12px;
    margin-top: 16px;
  }
  .proof-rating { flex-direction: row; align-items: center; gap: 10px; flex-wrap: wrap; }
  .proof-subjects {
    padding-left: 0;
    padding-top: 12px;
    border-left: 0;
    border-top: 1px solid rgba(38, 36, 46, 0.11);
  }
  .subject-icons { gap: 6px; }
  .sub-ic { width: 30px; font-size: 12px; }
  .sub-name { font-size: 8.5px; }
}


/* ---- HERO on small tablets / large phones (600–860px) ----
   At this width the 1.32 door crop is ~570px tall and swallows the screen
   before the headline arrives. Widen the crop, and restore the horizontal
   action row that the extra width can now comfortably carry. */
@media (min-width: 600px) and (max-width: 860px) {
  body.simple .frame-door {
    aspect-ratio: auto;
    height: min(50vw, 34vh);
  }
  /* wide enough for the elegant single line again */
  .hero-levels { font-size: clamp(24px, 4.2vw, 33px); white-space: nowrap; }
  .hero-levels .lv-a, .hero-levels .lv-b, .hero-levels .lv-mid { display: inline; }
  .hero-promise { font-size: clamp(19px, 2.9vw, 25px); }
  .entrance-copy .lede { font-size: 16px; margin-bottom: 26px; }
  .entrance-actions { flex-direction: row; align-items: center; gap: 14px 26px; }
  .entrance-actions .btn-primary { width: auto; }
  .btn-quiet { align-self: auto; }
  .trust-row { grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 520px; }
  .trust-row li:nth-child(2n) { padding-left: 0; border-left: 0; }
  .trust-row li + li {
    padding-left: 12px;
    border-left: 1px solid rgba(38, 36, 46, 0.13);
  }
  .hero-proof { flex-direction: row; max-width: 100%; }
  .proof-rating { flex-direction: column; align-items: flex-start; }
  .proof-subjects {
    padding-top: 0; padding-left: 20px;
    border-top: 0; border-left: 1px solid rgba(38, 36, 46, 0.11);
  }
}

/* ---- JOURNEY FLOW on tablets held in stacked mode (861px+) ---- */
@media (min-width: 861px) {
  body.simple .flow-bar {
    position: relative;
    left: auto; bottom: auto;
    transform: none;
    margin: 22px auto 0;
  }
  body.simple .flow-bar .scene-cue { display: inline-flex; }
  body.simple .booking-summary,
  body.simple .farewell-panel {
    position: relative;
    left: auto; bottom: auto;
    transform: none;
    margin: 24px auto 0;
  }
  body.simple .booking-summary { width: min(420px, calc(100% - 80px)); }
}

/* ---- HERO on tablets held in stacked mode (coarse pointer, 861px+) ----
   Without this the hero copy stays absolutely centred over the photograph,
   because the stacked-layout resets live only in the 860px query. */
@media (min-width: 861px) {
  body.simple .scene-entrance { display: block; padding-top: var(--header-h); }
  body.simple .scene-entrance .kb,
  body.simple .scene-entrance .par { position: relative; inset: auto; }
  body.simple .scene-entrance .frame-door {
    position: relative;
    right: auto;
    width: 100%;
    max-width: none;
    aspect-ratio: auto;
    height: min(48vw, 38vh);
  }
  body.simple .scene-entrance .frame-door .photo {
    object-position: 38% 40%;
    -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent);
            mask-image: linear-gradient(to bottom, #000 70%, transparent);
  }
  body.simple .entrance-copy {
    position: relative;
    top: auto;
    left: auto;
    transform: none;
    max-width: 760px;
    margin: -5vh auto 0;
    padding: 0 40px 48px;
  }
  body.simple .scene-entrance .scroll-cue { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .bar-down, .cue-arrow, .twinkle, .boot-sub { animation: none; }
}


/* ============ NAVIGATION GUARDS ============ */

.flow-status.is-warn { color: var(--purple-deep); font-weight: 600; }

@keyframes flowShake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-5px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(3px); }
}
.flow-bar.is-shake { animation: flowShake 0.42s ease; }

.step.is-locked { opacity: 0.42; cursor: not-allowed; }
.step.is-locked .step-dot { background: rgba(238, 232, 221, 0.6); }
.menu-overlay a.is-locked { opacity: 0.38; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .flow-bar.is-shake { animation: none; }
}


/* ---- Page 6: the artwork's own Google pill, made clickable ----
   A transparent anchor sits exactly over the button drawn into the
   photograph, so there is one CTA and it is the prototype's own. */
.review-hit {
  position: absolute;
  display: block;
  border-radius: 999px;
  z-index: 6;
  cursor: pointer;
}
.review-hit::after {
  content: "";
  position: absolute;
  inset: -6%;
  border-radius: 999px;
  background: radial-gradient(60% 70% at 50% 50%, rgba(255, 236, 190, 0.55), transparent 72%);
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}
.review-hit:hover::after { opacity: 1; }
.review-hit:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 4px; }

/* On small screens the painted pill scales below a comfortable touch target,
   so the hit area is expanded around it without altering the artwork. */
.review-hit::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, 132px);
  height: max(100%, 46px);
  border-radius: 999px;
}

/* Shown only when a booking could not be written to the database, so a
   network failure is never mistaken for a confirmed booking. */
.bkc-warn {
  font-size: 2.3cqh;
  color: #a53f37;
  background: #fdeceb;
  border-radius: 1.2cqh;
  padding: 1cqh 2cqw;
  max-width: 92%;
}

/* ============ PAGE 1 · PROTOTYPE ELEMENTS ============ */

/* Email pill in the header */
.header-email {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 10px 16px;
  border: 1.5px solid rgba(124, 95, 196, 0.28);
  border-radius: 999px;
  background: #fff;
  font-size: 13.5px;
  color: var(--ink);
  text-decoration: none;
  transition: border-color 0.2s ease, background 0.2s ease;
}
.header-email svg { width: 17px; height: 17px; color: var(--purple); flex: none; }
.header-email:hover { border-color: var(--purple); background: var(--lavender-bg); }

/* Floating contact dock, bottom right. The dock itself is invisible — it just
   stacks the robot above the bubble, so hiding the bubble leaves the robot in
   place to bring it back. */
.contact-card {
  position: fixed;
  right: clamp(14px, 2vw, 30px);
  bottom: clamp(14px, 2vw, 28px);
  z-index: 55;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  width: clamp(240px, 24vw, 300px);
}
.contact-card[hidden] { display: none; }

.cc-bubble {
  display: flex;
  flex-direction: column;
  gap: 9px;
  width: 100%;
  padding: 16px;
  border-radius: 18px;
  background: #fff;
  box-shadow: 0 18px 45px rgba(72, 52, 130, 0.18);
}
.cc-bubble[hidden] { display: none; }
/* Plays whenever the bubble is shown — on the timed reveal and on every reopen
   — so it grows out of the robot rather than snapping into place. */
.cc-bubble {
  transform-origin: 100% 0;
  animation: ccBubbleIn 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes ccBubbleIn {
  from { opacity: 0; transform: translateY(10px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cc-bubble { animation: none; }
}

/* The mascot toggles the bubble. It sits proud of the bubble's top-right
   corner where the prototype draws it, and stays put when the bubble hides so
   there is always something to click to bring it back. */
.cc-bot-btn {
  position: relative;
  z-index: 1;
  width: clamp(44px, 3.9vw, 58px);
  margin-right: clamp(2px, 0.5vw, 10px);
  margin-bottom: -12px;
  padding: 0;
  line-height: 0;
  border-radius: 14px;
  filter: drop-shadow(0 7px 16px rgba(72, 52, 130, 0.32));
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}
.cc-bot-btn:hover, .cc-bot-btn:focus-visible { transform: translateY(-3px) rotate(-5deg); }
.cc-bot-btn:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 4px; }
/* Bubble hidden: nothing to overlap, so the robot sits square on the corner. */
.cc-bot-btn[aria-expanded="false"] { margin-bottom: 0; }
.cc-bot { display: block; width: 100%; height: auto; }

.cc-primary,
.cc-whatsapp {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 46px;
  padding: 12px 14px;
  border-radius: 12px;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: background 0.22s ease, color 0.22s ease;
}
.cc-primary svg, .cc-whatsapp svg { width: 18px; height: 18px; flex: none; }

.cc-primary { background: var(--purple); color: #fff; }
.cc-primary:hover { background: var(--purple-deep); }

.cc-whatsapp {
  background: #fff;
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px rgba(38, 36, 46, 0.12);
}
.cc-whatsapp:hover { background: #f2faf3; color: #1f7a43; box-shadow: inset 0 0 0 1.5px #1f7a43; }

/* Four trust badges rather than three. Scoped tighter than .trust-row, so it
   is confined to the wide layout — otherwise 42vw would squeeze the row to
   157px on a phone. */
@media (min-width: 861px) {
  .entrance-copy .trust-row { max-width: min(480px, 33.5vw); }
}

@media (max-width: 860px) {
  .header-email { display: none; }
  .contact-card {
    right: 10px;
    left: 10px;
    bottom: 10px;
    width: auto;
  }
  /* the two actions sit side by side on a phone; the robot keeps its own row */
  .cc-bubble { flex-direction: row; padding: 12px; transform-origin: 100% 100%; }
  /* Robot last in the column, so it stays pinned to the corner and the bubble
     grows upward out of it when the timer fires. */
  .contact-card { flex-direction: column-reverse; }
  .cc-bot-btn { margin-bottom: 0; margin-top: -12px; }
  .cc-bot-btn[aria-expanded="false"] { margin-top: 0; }
  @keyframes ccBubbleIn {
    from { opacity: 0; transform: translateY(8px) scale(0.96); }
    to   { opacity: 1; transform: none; }
  }
  .cc-primary, .cc-whatsapp { flex: 1; font-size: 12.5px; padding: 10px 8px; }
  .cc-bot-btn { width: 46px; margin-right: 4px; }
}

/* ============ HEADER LEGIBILITY OVER ARTWORK ============
   The header has no bar and no gradient — the controls sit directly on the
   photograph. The step numbers already carry their own pale pill, and the menu
   button its own purple circle, so only the bare text needs help. A soft light
   halo keeps it readable where the artwork behind is dark (the classroom,
   booking and wall plates all drop below 3:1 in places) without introducing a
   panel or a fade. */

.step-label,
.brand-name,
.brand-sub,
.goback-pill {
  text-shadow:
    0 1px 2px rgba(255, 255, 255, 0.85),
    0 0 10px rgba(255, 255, 255, 0.6);
}

/* The pale pill behind each step number does the same job; nudge it opaque so
   the digits stay crisp on the darker rooms. */
.step-dot { background: rgba(244, 239, 231, 0.96); }

/* ============ MEET YOUR TUTOR — POPUP ============
   Not a page: no number, no stepper entry, no menu item. It exists only while
   someone clicks "Learn more about Melita" (or the doorway itself) and closes
   on Escape, the backdrop, or the ×. The page underneath never scrolls; if the
   panel is taller than the window, the panel scrolls inside itself. */

.about-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  justify-content: center;
  padding: clamp(8px, 2vh, 26px) clamp(8px, 1.6vw, 26px);
  background: rgba(30, 26, 40, 0.46);
  overflow-y: auto;
  overscroll-behavior: contain;
  animation: aboutFade 0.26s ease both;
}
.about-overlay[hidden] { display: none; }
@keyframes aboutFade { from { opacity: 0; } to { opacity: 1; } }

/* margin:auto centres the panel when it fits and still lets the overlay scroll
   to the top edge when it does not — which a centred grid would clip. */
.about-panel {
  position: relative;
  margin: auto;
  width: min(1400px, 100%);
  background: #f7efeb;
  border-radius: clamp(14px, 1.5vw, 26px);
  box-shadow: 0 34px 90px rgba(30, 26, 40, 0.38);
  overflow: hidden;
  padding-bottom: clamp(16px, 2.4vh, 26px);
  animation: aboutRise 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes aboutRise {
  from { opacity: 0; transform: translateY(22px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

.about-close {
  position: absolute;
  top: clamp(8px, 0.9vw, 15px);
  right: clamp(8px, 0.9vw, 15px);
  z-index: 4;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  font-size: 25px; line-height: 1;
  color: var(--ink);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 4px 14px rgba(30, 26, 40, 0.18);
  transition: background 0.2s ease, color 0.2s ease;
}
.about-close:hover { background: #fff; color: var(--purple-deep); }

/* ---- intro ---- */
.about-intro {
  display: grid;
  grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
  align-items: center;
}
.about-intro-copy {
  padding: clamp(18px, 3.2vh, 42px) clamp(14px, 1.6vw, 30px)
           clamp(16px, 2.6vh, 34px) clamp(20px, 3vw, 56px);
}
.about-intro-photo { align-self: stretch; min-height: 0; }
.about-intro-photo img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 26%);
          mask-image: linear-gradient(to right, transparent, #000 26%);
}

.about-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(26px, 3.4vw, 54px);
  line-height: 1.04;
  letter-spacing: -0.012em;
  color: var(--ink);
}
.about-title::after {
  content: "";
  display: block;
  width: clamp(26px, 2.6vw, 44px);
  height: 3px;
  margin-top: clamp(7px, 1.2vh, 14px);
  border-radius: 2px;
  background: var(--purple-deep);
}
.about-hello {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(19px, 1.95vw, 32px);
  line-height: 1.2;
  color: var(--ink);
  margin-top: clamp(12px, 2.4vh, 30px);
}
.about-intro-copy > p:not(.about-hello) {
  font-size: clamp(12.5px, 0.95vw, 15.5px);
  font-weight: 300;
  line-height: 1.72;
  color: var(--ink-soft);
  max-width: 36em;
  margin-top: clamp(9px, 1.6vh, 18px);
}
.about-intro-copy strong { color: var(--purple-deep); font-weight: 600; }

/* ---- the two claim cards ---- */
.about-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(8px, 1.1vw, 18px);
  padding: clamp(8px, 1.4vh, 16px) clamp(12px, 1.8vw, 34px) 0;
}
/* The photograph is part of the card, not a decoration over it: it sits behind
   the copy and bleeds off the right edge exactly as in the prototype. Its own
   soft left edge dissolves into the card because the card is painted the same
   cream the photograph fades to — no mask, no gradient. */
.about-card {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: clamp(10px, 1.1vw, 20px);
  background: #f9f2ef;
  padding: clamp(12px, 2vh, 24px) clamp(14px, 1.5vw, 26px) clamp(14px, 2.2vh, 26px);
}
.about-card-photo {
  position: absolute;
  z-index: -1;
  top: 0; right: 0;
  width: 54%; height: 100%;
  object-fit: cover;
  object-position: right center;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 46%);
          mask-image: linear-gradient(to right, transparent, #000 46%);
}
/* The fade is what keeps the copy readable where the two meet — the picture
   has dissolved into the card's cream long before the text reaches it. */
.about-card > :not(.about-card-photo) { max-width: 52%; }
.about-card-expect > :not(.about-card-photo) { max-width: 56%; }

.about-card-head {
  display: flex;
  align-items: center;
  gap: clamp(9px, 1vw, 16px);
  max-width: none;
  margin-bottom: clamp(8px, 1.6vh, 18px);
}
.about-card-icon {
  width: clamp(34px, 3.3vw, 56px);
  aspect-ratio: 1;
  flex: none;
  border-radius: 50%;
  background: var(--lavender-bg);
  color: var(--purple);
  display: grid; place-items: center;
}
.about-card-icon svg { width: 54%; height: 54%; }
.about-card-head h3 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(16px, 1.5vw, 25px);
  line-height: 1.15;
  color: var(--ink);
}
.about-card-head h3::after {
  content: "";
  display: block;
  width: clamp(20px, 1.9vw, 32px);
  height: 2.5px;
  margin-top: clamp(4px, 0.7vh, 8px);
  border-radius: 2px;
  background: var(--purple);
}
.about-card p {
  font-size: clamp(11.5px, 0.86vw, 14px);
  font-weight: 300;
  line-height: 1.65;
  color: var(--ink-soft);
}
.about-card p + p { margin-top: clamp(7px, 1.2vh, 14px); }

.about-checks {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: clamp(5px, 1vh, 11px);
}
.about-checks li {
  display: flex;
  align-items: flex-start;
  gap: clamp(7px, 0.7vw, 11px);
  font-size: clamp(11.5px, 0.86vw, 14px);
  font-weight: 300;
  line-height: 1.45;
  color: var(--ink-soft);
}
.about-checks li::before {
  content: "";
  flex: none;
  width: clamp(14px, 1.15vw, 18px);
  height: clamp(14px, 1.15vw, 18px);
  margin-top: 1px;
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%237c5fc4'%20stroke-width='1.9'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'/%3E%3Cpath%20d='M8.2%2012.4l2.6%202.6%205-5.2'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* ---- the journey strip ---- */
/* The panel is painted the same colour the tile artwork fades to, so the six
   illustrations sit on it with no visible edge and no mask. */
.about-story {
  margin: clamp(8px, 1.4vh, 16px) clamp(12px, 1.8vw, 34px) 0;
  padding: clamp(9px, 1.5vh, 16px) clamp(10px, 1.2vw, 22px) clamp(10px, 1.8vh, 18px);
  border-radius: clamp(10px, 1.1vw, 20px);
  background: #f3eaeb;
}
.about-story-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(15px, 1.35vw, 23px);
  line-height: 1.1;
  text-align: center;
  color: var(--purple-deep);
}
.about-story-title::after {
  content: "";
  display: block;
  width: clamp(18px, 1.6vw, 27px);
  height: 2.5px;
  margin: clamp(4px, 0.6vh, 6px) auto 0;
  border-radius: 2px;
  background: var(--purple);
}
.story-strip {
  --story-gap: clamp(4px, 0.8vw, 14px);
  list-style: none;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  align-items: start;
  gap: var(--story-gap);
  margin-top: clamp(2px, 0.8vh, 8px);
}
.story-step { position: relative; text-align: center; }
.story-step img {
  display: block;
  width: auto;
  max-width: 100%;
  height: clamp(78px, 14.5vh, 154px);
  object-fit: contain;
  margin: 0 auto;
}
.story-step p {
  margin-top: clamp(3px, 0.7vh, 9px);
  font-size: clamp(9px, 0.72vw, 12px);
  font-weight: 300;
  line-height: 1.42;
  color: var(--ink-soft);
}
/* the arrow lives in the gutter, so it never eats into a tile */
.story-step::after {
  content: "\2192";
  position: absolute;
  top: clamp(34px, 6.4vh, 68px);
  right: calc(var(--story-gap) / -2 - 0.32em);
  font-size: clamp(11px, 1.05vw, 17px);
  line-height: 1;
  color: var(--purple);
}
.story-step:last-child::after { content: none; }

.about-cta {
  display: flex;
  justify-content: center;
  margin-top: clamp(10px, 1.6vh, 18px);
}
.about-cta .btn {
  border-radius: 12px;
  padding: clamp(11px, 1.5vh, 16px) clamp(22px, 2.4vw, 36px);
  font-size: clamp(13px, 1vw, 16px);
}

/* ---- narrow screens: one column, story in two rows of three ---- */
@media (max-width: 900px) {
  .about-intro { grid-template-columns: 1fr; }
  .about-intro-photo { order: -1; }
  .about-intro-photo img { height: clamp(160px, 30vh, 300px); }
  .about-intro-copy { padding: 18px 20px 4px; }
  .about-cards { grid-template-columns: 1fr; padding-top: 14px; }
  .about-card { min-height: 190px; }
  .about-card-photo { width: 48%; }
  .about-card > :not(.about-card-photo),
  .about-card-expect > :not(.about-card-photo) { max-width: 60%; }
  .story-strip { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 14px; }
  .story-step:nth-child(3)::after { content: none; }
  .story-step img { height: clamp(84px, 16vw, 132px); }
}
@media (max-width: 560px) {
  .about-card > :not(.about-card-photo),
  .about-card-expect > :not(.about-card-photo) { max-width: 100%; }
  .about-card-photo { display: none; }
  .story-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .story-step::after { content: none; }
}

/* Windows shorter than the prototype's 1024px: tighten the popup's vertical
   rhythm so the whole story still lands on one screen rather than asking the
   reader to scroll inside the panel. */
@media (min-width: 901px) and (max-height: 980px) {
  .about-intro-copy { padding-top: 18px; padding-bottom: 14px; }
  .about-hello { margin-top: 14px; }
  .about-intro-copy > p:not(.about-hello) { margin-top: 10px; line-height: 1.58; }
  .about-cards { padding-top: 9px; }
  .about-card { padding-top: 12px; padding-bottom: 12px; }
  .about-card-head { margin-bottom: 9px; }
  .about-card p { line-height: 1.55; }
  .about-checks { gap: 7px; }
  .about-story { margin-top: 9px; padding-top: 8px; padding-bottom: 8px; }
  .story-step img { height: clamp(70px, 11vh, 120px); }
  .story-step::after { top: clamp(28px, 5vh, 52px); }
  .about-cta { margin-top: 8px; }
  .about-panel { padding-bottom: 10px; }
}

/* ============================================================
   MOBILE — built to the supplied phone prototypes
   ============================================================
   Everything below is inside `max-width: 860px`, so the desktop journey is
   untouched. The phone layout differs from it in kind, not just in scale:
   each page is a column that scrolls inside itself, under a fixed cream
   header carrying a condensed step rail.
   ============================================================ */

@media (max-width: 860px) {
  :root {
    --header-h: 60px;   /* brand row */
    --rail-h: 54px;     /* step rail below it */
    --top-h: 114px;     /* both, the offset every page starts below */
    --m-pad: 20px;
    --m-line: rgba(38, 36, 46, 0.11);
    --m-card: rgba(255, 255, 255, 0.55);
  }

  /* ---------- header: two rows, solid, with a hairline ---------- */
  /* The desktop header floats transparently over the artwork. On a phone the
     page scrolls beneath it, so it needs a ground of its own. */
  .site-header {
    height: auto;
    flex-wrap: wrap;
    align-items: center;
    row-gap: 0;
    padding: 9px var(--m-pad) 0;
    background: var(--cream);
    box-shadow: inset 0 -1px 0 var(--m-line);
    pointer-events: auto;
  }
  .header-left { order: 1; }
  .brand-name { font-size: 25px; }
  .brand-sub { font-size: 9px; letter-spacing: 0.22em; }
  .goback-pill { display: none; }

  /* the address collapses to its envelope; font-size:0 hides the text node */
  .header-email {
    order: 2;
    display: grid;
    place-items: center;
    width: 42px; height: 42px;
    margin-left: auto;
    padding: 0;
    font-size: 0;
    border: 0;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 2px 10px rgba(72, 52, 130, 0.13);
  }
  .header-email svg { width: 19px; height: 19px; }
  .menu-btn { order: 3; margin-left: 10px; }

  /* ---------- the condensed step rail ---------- */
  /* Only the step you are on is named. Steps behind you become ticks, steps
     ahead stay as plain dots, exactly as drawn. */
  .stepper {
    order: 4;
    display: flex;
    flex: 0 0 100%;
    align-items: flex-start;
    gap: 0;
    height: var(--rail-h);
    padding: 9px 0 0;
    overflow: visible;
  }
  .step {
    flex: 0 0 auto;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 0;
    min-width: 0;
  }
  .step-dot {
    width: 28px; height: 28px;
    font-size: 11.5px;
    font-weight: 600;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: #e6dfd4;
    color: var(--ink-soft);
    box-shadow: none;
  }
  .step-label {
    display: none;
    font-size: 10.5px;
    line-height: 1.15;
    white-space: nowrap;
    color: var(--purple-deep);
    text-shadow: none;
  }
  .step.is-active .step-dot { background: var(--purple-deep); color: #fff; }
  .step.is-active .step-label { display: block; }

  /* behind you: a lavender tick in place of the number */
  .step.is-done .step-dot { background: var(--lavender-bg); color: transparent; }
  .step.is-done .step-dot::after {
    content: "";
    width: 11px; height: 6px;
    margin-top: -3px;
    border: 2px solid var(--purple);
    border-top: 0; border-right: 0;
    transform: rotate(-45deg);
  }
  /* ahead of you: a small plain dot, centred against the 28px circles */
  .step:not(.is-active):not(.is-done) .step-dot {
    width: 12px; height: 12px;
    margin: 8px 0;
    font-size: 0;
    background: #ded7cc;
  }
  .step-line {
    flex: 1 1 auto;
    height: 1px;
    margin-top: 14px;
    background: var(--m-line);
  }
  .step.is-locked { opacity: 0.45; }

  /* ---------- the page shell ---------- */
  /* The document still never scrolls — the current page scrolls inside itself,
     so the header and rail stay put while the content moves under them. */
  body.simple .scene {
    justify-content: flex-start;
    padding: var(--top-h) 0 34px;
  }
  body.simple .scene.is-current {
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    scrollbar-width: none;
  }
  body.simple .scene.is-current::-webkit-scrollbar { width: 0; height: 0; }
  body.simple .scene-entrance { padding-top: var(--top-h); }

  /* artwork band at the top of each page */
  body.simple .photo-frame,
  body.simple .scene-canvas { flex: none; }

  /* ---------- shared mobile card ---------- */
  .m-card {
    border: 1px solid var(--m-line);
    border-radius: 16px;
    background: var(--m-card);
  }

  /* ============ 01 · ENTRANCE ============ */

  /* A clean band, as drawn: nothing fades here because the copy sits below the
     picture rather than on top of it. */
  body.simple .frame-door {
    aspect-ratio: 1.5;
    height: auto;
  }
  body.simple .scene-entrance .frame-door .photo,
  body.simple .photo-frame .photo {
    -webkit-mask-image: none;
    mask-image: none;
    object-position: 42% 42%;
  }

  body.simple .entrance-copy {
    display: flex;
    flex-direction: column;
    max-width: 560px;
    margin: 0 auto;
    padding: 22px var(--m-pad) 0;
  }
  .hero-levels {
    font-size: 13px;
    letter-spacing: 0.16em;
    margin-bottom: 10px;
  }
  .hero-promise { font-size: clamp(27px, 8.2vw, 34px); line-height: 1.16; max-width: none; }
  .entrance-copy .lede { font-size: 16px; max-width: none; margin-top: 14px; }
  /* both promise lines are in the drawing, so neither is dropped */
  .entrance-copy .lede-quiet { display: block; font-size: 14.5px; max-width: none; }

  .entrance-actions { order: 1; margin-top: 22px; }
  .entrance-actions .btn-primary { border-radius: 12px; padding: 17px 24px; font-size: 15.5px; }
  .entrance-actions .btn-quiet { margin-top: 4px; font-size: 14.5px; }

  /* credentials: a bordered 2x2 with rules between the cells */
  .trust-row {
    order: 2;
    grid-template-columns: 1fr 1fr;
    max-width: none;
    margin-top: 20px;
    gap: 0;
    padding: 0;
    border: 1px solid var(--m-line);
    border-radius: 16px;
    background: var(--m-card);
    font-size: 12.5px;
  }
  .trust-row li {
    flex-direction: row;
    align-items: center;
    gap: 11px;
    padding: 15px 13px;
    border: 0;
  }
  .trust-row li:nth-child(odd) { border-right: 1px solid var(--m-line); }
  .trust-row li:nth-child(-n + 2) { border-bottom: 1px solid var(--m-line); }
  .trust-ic svg { width: 25px; height: 25px; }

  /* rating and subjects are two separate cards on a phone, not one strip */
  .hero-proof {
    order: 3;
    display: flex;
    flex-direction: column;
    gap: 14px;
    width: 100%;
    max-width: none;
    margin-top: 14px;
    padding: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
  }
  .proof-rating {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    row-gap: 7px;
    padding: 15px 16px;
    border: 1px solid var(--m-line);
    border-radius: 16px;
    background: var(--m-card);
  }
  .proof-rating .proof-label { grid-area: 1 / 1; }
  .proof-stars { grid-area: 2 / 1; font-size: 21px; }
  .proof-score {
    grid-area: 1 / 2 / span 2 / span 1;
    align-self: stretch;
    justify-content: center;
    font-size: 14px;
    border-left: 1px solid var(--m-line);
  }
  .proof-score strong { font-size: 19px; }

  .proof-subjects {
    gap: 12px;
    padding: 15px 12px 14px;
    border: 1px solid var(--m-line);
    border-top: 1px solid var(--m-line);
    border-left: 1px solid var(--m-line);
    border-radius: 16px;
    background: var(--m-card);
  }
  .proof-subjects .proof-label { padding-left: 4px; }
  .subject-icons { gap: 2px; }
  .sub-ic { width: 40px; height: 40px; font-size: 15px; }
  .sub-name { font-size: 9.5px; }
}

/* ============================================================
   PHONE — PAGE 1, matched to the prototype
   Three separate cards under the buttons: the credentials in a
   2x2 with a full cross of hairlines, the Google rating split
   left/right by a rule, and the subjects on their own card.
   Nothing here is reachable above 860px, so the laptop layout
   locked at version 9 is untouched.
   ============================================================ */

@media (max-width: 860px) {
  /* ---------- credentials: 2x2, hairlines both ways ---------- */
  .entrance-copy .trust-row {
    grid-template-columns: 1fr 1fr;
    align-items: stretch;
    row-gap: 0;
    padding: 0;
  }
  .trust-row li {
    align-items: center;
    gap: 12px;
    padding: 15px 14px;
    border: 0;
  }
  .trust-row li + li { padding-left: 14px; border-left: 0; }
  /* the cross: a rule down the middle and one across the waist */
  .trust-row li:nth-child(2n) { border-left: 1px solid var(--m-line); }
  .trust-row li:nth-child(n + 3) { border-top: 1px solid var(--m-line); }
  .trust-ic { flex: none; }

  /* ---------- rating and subjects: two cards, not one ---------- */
  .hero-proof {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 0;
    background: none;
    box-shadow: none;
    border-radius: 0;
  }

  .proof-rating,
  .proof-subjects {
    border: 0;
    border-radius: 16px;
    background: var(--m-card);
    box-shadow: 0 1px 0 rgba(38, 36, 46, 0.04);
  }

  /* Label over stars on the left, the score on the right behind a rule —
     the score spans both rows so the rule runs the full height. */
  .proof-rating {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: 4px 0;
    padding: 16px 18px;
  }
  .proof-rating .proof-label,
  .proof-rating .proof-stars { grid-column: 1; }
  .proof-rating .proof-score {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: stretch;
    align-items: center;
    padding-left: 18px;
    border-left: 1px solid var(--m-line);
    font-size: 15px;
  }
  .proof-rating .proof-score strong { font-size: 19px; }
  .proof-rating .proof-stars { font-size: 24px; letter-spacing: 3px; }
  .proof-rating .proof-label { font-size: 13px; }
  .g-mark { width: 18px; height: 18px; }

  .proof-subjects {
    display: block;
    padding: 15px 12px 14px;
    border-top: 0;
    border-left: 0;
  }
  .proof-subjects .proof-label {
    padding-left: 6px;
    margin-bottom: 12px;
    font-size: 13px;
  }
  .subject-icons { gap: 2px; }
  .subject-icons li { gap: 6px; }
  .sub-ic { width: 46px; height: 46px; font-size: 20px; }
  .sub-name { font-size: 10px; line-height: 1.25; }
}

/* Narrow phones: the seven subjects still have to fit one row. */
@media (max-width: 400px) {
  .sub-ic { width: 40px; height: 40px; font-size: 17px; }
  .sub-name { font-size: 9px; }
  .proof-rating .proof-stars { font-size: 21px; letter-spacing: 2px; }
}

/* ============================================================
   PHONE — PAGE 2, Choose Year
   The phone gets a portrait render of the classroom cut from the
   prototype, so the year plates are painted into the artwork and
   the ten hotspots sit on top of them, exactly as the laptop does
   with its landscape plate.
   ============================================================ */

@media (max-width: 860px) {
  /* the portrait plate, shown whole rather than cropped */
  body.simple .scene-year .scene-canvas,
  body.simple .scene-year .kb,
  body.simple .scene-year .par {
    position: relative;
    inset: auto;
    width: 100%;
    height: auto;
  }
  body.simple .scene-year .scene-canvas {
    aspect-ratio: 851 / 1622;
    overflow: hidden;
  }
  body.simple .scene-year .scene-canvas .photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
  }

  /* The painted plates are the buttons. Simple mode hides every hotspot layer
     by default (the chips stood in for them); the year plates are real targets
     on the portrait artwork, so this one comes back. */
  body.simple #deskLayer {
    display: block;
    position: absolute;
    inset: 0;
  }
  /* Same glow, ring and tick the laptop uses — only the coordinates differ.
     The laptop positions are written as inline styles, which no stylesheet
     rule can outrank, so the phone coordinates have to say so explicitly.
     Confined to this media query, the laptop never sees them. */
  #deskLayer .hotspot {
    left: var(--mx) !important;
    top: var(--my) !important;
    width: var(--mw) !important;
    height: var(--mh) !important;
    border-radius: 14px;
  }
  #deskLayer .hotspot .badge { width: 26px; height: 26px; font-size: 13px; top: -8px; right: -8px; }

  /* the chip fallback is redundant now the plates themselves are tappable */
  body.simple #yearChoices { display: none; }

  /* ---------- the bar under the artwork ---------- */
  body.simple .scene-year .flow-bar {
    position: relative;
    left: auto; right: auto; bottom: auto;
    transform: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 20px var(--m-pad) 26px;
    background: none;
  }
  body.simple .flow-status {
    margin: 0;
    padding: 9px 22px;
    border-radius: 999px;
    background: var(--lavender-bg);
    color: var(--purple-deep);
    font-size: 14px;
    font-weight: 500;
    text-align: center;
  }
  body.simple .flow-status.is-on {
    background: #e8f5ec;
    color: #2f7d55;
  }
  body.simple .scene-cue {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    max-width: 340px;
    min-height: 54px;
    padding: 14px 24px;
    border-radius: 12px;
    background: var(--lavender-bg);
    color: var(--purple-deep);
    font-size: 16px;
    font-weight: 500;
  }
  /* the mouse-scroll glyph means nothing on a phone */
  body.simple .scene-cue > svg:first-child { display: none; }
  body.simple .scene-cue .cue-go { display: inline; font-size: 18px; line-height: 1; }
  body.simple .scene-cue.is-ready {
    background: var(--purple);
    color: #fff;
    box-shadow: 0 10px 24px rgba(124, 95, 196, 0.32);
  }
}

/* ============================================================
   PHONE — centring fixes and a page 1 that fits one screen
   ============================================================ */

@media (max-width: 860px) {
  /* ---------- the envelope, actually in the middle ----------
     The pill still contains the address as a text node. In a grid that text
     becomes a second anonymous item, so the icon was centred in the TOP half
     of the circle rather than in the circle. A single flex line puts both on
     the same row and centres them together; the text is 0px wide, so what
     you see is the envelope, centred. */
  .header-email {
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 0;
  }
  .header-email svg { display: block; }

  /* ---------- the tick, actually in the middle ----------
     Same cause: the step number is still in the dot, so the tick was being
     laid out as a second grid row underneath it. Taking the number out of the
     flow and centring the tick on the circle fixes it. */
  .step.is-done .step-dot {
    position: relative;
    font-size: 0;
    color: transparent;
  }
  .step.is-done .step-dot::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 11px;
    height: 6px;
    margin: 0;
    border: 2px solid var(--purple);
    border-top: 0;
    border-right: 0;
    /* -70% rather than -50%: a tick's ink sits below its box centre once
       rotated, so the optical centre needs the nudge. */
    transform: translate(-50%, -70%) rotate(-45deg);
  }

  /* ---------- page 1 on one screen ----------
     The drawing fits the whole hero in a single phone screen. These sizes are
     taken from it, and the vertical rhythm is in vh so it holds from a small
     phone to a large one without ever needing a scroll. */

  /* one line, always — the level line is an eyebrow now, not a headline */
  .hero-levels {
    font-size: clamp(10px, 3.1vw, 14px) !important;
    line-height: 1.2 !important;
    letter-spacing: 0.13em !important;
    white-space: nowrap !important;
    margin-bottom: clamp(6px, 1.1vh, 12px) !important;
  }
  .hero-levels .lv-a,
  .hero-levels .lv-b,
  .hero-levels .lv-mid { display: inline !important; }
  .hero-levels .lv-sep { margin: 0 0.28em; }

  .hero-promise {
    font-size: clamp(21px, 6.4vw, 29px);
    line-height: 1.16;
    max-width: none;
  }
  .entrance-copy .lede {
    font-size: clamp(13px, 3.7vw, 15.5px);
    line-height: 1.45;
    max-width: none;
    margin-top: clamp(7px, 1.2vh, 12px);
  }
  .entrance-copy .lede-quiet {
    display: block;
    font-size: clamp(11.5px, 3.3vw, 13.5px);
    line-height: 1.45;
    margin-top: clamp(6px, 1vh, 10px);
  }

  .entrance-actions { margin-top: clamp(10px, 1.7vh, 18px); gap: 4px; }
  .entrance-actions .btn-primary {
    min-height: 0;
    padding: clamp(11px, 1.6vh, 15px) 20px;
    font-size: clamp(14px, 3.9vw, 16px);
    border-radius: 12px;
  }
  .btn-quiet {
    min-height: 0;
    padding: clamp(7px, 1.1vh, 11px) 8px;
    font-size: clamp(12.5px, 3.5vw, 14.5px);
  }

  /* the three cards, tightened to the drawing */
  .entrance-copy .trust-row { margin-top: clamp(8px, 1.4vh, 14px); }
  .trust-row li {
    gap: 10px;
    padding: clamp(8px, 1.3vh, 13px) 12px;
    font-size: clamp(10.5px, 2.9vw, 12.5px);
    line-height: 1.3;
  }
  .trust-ic svg { width: clamp(19px, 5.4vw, 24px); height: clamp(19px, 5.4vw, 24px); }

  .hero-proof { margin-top: clamp(8px, 1.4vh, 14px); gap: clamp(8px, 1.3vh, 13px); }
  .proof-rating { padding: clamp(9px, 1.4vh, 14px) 16px; }
  .proof-rating .proof-label { font-size: clamp(11px, 3vw, 12.5px); }
  .proof-rating .proof-stars { font-size: clamp(17px, 5vw, 22px); }
  .proof-rating .proof-score { font-size: clamp(12px, 3.4vw, 14px); }
  .proof-rating .proof-score strong { font-size: clamp(15px, 4.3vw, 18px); }

  .proof-subjects { padding: clamp(9px, 1.4vh, 13px) 10px clamp(8px, 1.2vh, 12px); }
  .proof-subjects .proof-label {
    margin-bottom: clamp(6px, 1vh, 10px);
    font-size: clamp(11px, 3vw, 12.5px);
  }
  .sub-ic {
    width: clamp(32px, 9.4vw, 42px);
    height: clamp(32px, 9.4vw, 42px);
    font-size: clamp(14px, 4.1vw, 18px);
  }
  .subject-icons li { gap: 4px; }
  .sub-name { font-size: clamp(8px, 2.3vw, 10px); }
}

/* Short phones have less to give, so the picture gives it. */
@media (max-width: 860px) and (max-height: 780px) {
  body.simple .scene-entrance .frame-door { height: min(46vw, 26vh); }
}

/* The envelope sits dead centre regardless of the address text node beside it. */
@media (max-width: 860px) {
  .header-email { position: relative; }
  .header-email svg {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
}

/* ---------- page 1: the last 190px, so nothing scrolls ----------
   Measured against the drawing block by block. The savings come from the
   gaps and the two buttons, which were carrying desktop-sized padding. */
@media (max-width: 860px) {
  body.simple .scene-entrance .frame-door { height: min(60vw, 30vh); }
  body.simple .entrance-copy { padding-top: 12px; }

  .hero-promise { font-size: clamp(20px, 5.9vw, 27px); line-height: 1.14; }
  .entrance-copy .lede {
    font-size: clamp(12.5px, 3.4vw, 14px);
    line-height: 1.42;
    margin-top: 9px;
  }
  .entrance-copy .lede-quiet {
    font-size: clamp(11px, 3.1vw, 12.5px);
    margin-top: 8px;
  }

  .entrance-actions { margin-top: 12px; gap: 2px; }
  .entrance-actions .btn-primary {
    min-height: 46px;
    padding: 11px 20px;
    font-size: clamp(13.5px, 3.7vw, 15px);
  }
  .btn-quiet { min-height: 36px; padding: 6px 8px; font-size: clamp(12px, 3.3vw, 13.5px); }

  .entrance-copy .trust-row { margin-top: 10px; }
  .trust-row li { padding: 9px 11px; font-size: clamp(10px, 2.8vw, 12px); }
  .trust-ic svg { width: clamp(18px, 5vw, 22px); height: clamp(18px, 5vw, 22px); }

  .hero-proof { margin-top: 10px; gap: 10px; }
  .proof-rating { padding: 10px 15px; }
  .proof-rating .proof-stars { font-size: clamp(16px, 4.6vw, 20px); }

  .proof-subjects { padding: 10px 8px 9px; }
  .proof-subjects .proof-label { margin-bottom: 7px; }
  .sub-ic {
    width: clamp(30px, 8.6vw, 38px);
    height: clamp(30px, 8.6vw, 38px);
    font-size: clamp(13px, 3.8vw, 16px);
  }
  .subject-icons li { gap: 3px; }
  .sub-name { font-size: clamp(7.5px, 2.15vw, 9.5px); }
}

/* ---------- page 1 never scrolls ----------
   Rather than pin the picture and let the copy spill, the doorway takes
   whatever height is left after the copy has had what it needs. The page then
   fits any phone — the picture is what flexes, and object-fit keeps it
   handsome at any height. */
@media (max-width: 860px) {
  body.simple .scene-entrance { overflow: hidden !important; }
  body.simple .scene-entrance .kb {
    flex: 1 1 auto;
    min-height: 110px;
    display: flex;
  }
  /* .par has to be its own flex line, otherwise the frame inside it is a block
     whose only child is absolutely positioned — and collapses to zero. */
  body.simple .scene-entrance .par { flex: 1 1 auto; display: flex; min-height: 0; }
  body.simple .scene-entrance .frame-door {
    position: relative;
    flex: 1 1 auto;
    right: auto;
    width: 100%;
    max-width: none;
    aspect-ratio: auto;
    height: auto;
    min-height: 0;
  }
  body.simple .scene-entrance .frame-door .photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 38% 42%;
  }
  body.simple .entrance-copy { flex: 0 0 auto; }

  /* the last of the trimming, to leave the doorway as much room as possible */
  body.simple .entrance-copy { padding-top: 9px; }
  .hero-promise { font-size: clamp(19px, 5.6vw, 26px); line-height: 1.12; }
  .entrance-copy .lede { margin-top: 7px; }
  .entrance-copy .lede-quiet { margin-top: 6px; }
  .entrance-actions { margin-top: 9px; }
  .entrance-copy .trust-row { margin-top: 8px; }
  .trust-row li { padding: 7px 11px; }
  .hero-proof { margin-top: 8px; gap: 8px; }
  .proof-rating { padding: 8px 15px; }
  .proof-subjects { padding: 8px 8px 7px; }
}

/* ---------- page 2: the ring sits on the plate ----------
   The laptop draws a soft radial bloom around a hotspot, which on a phone
   reads as a smudge beside the plate rather than a selection. Here the ring
   traces the plate's own rounded rectangle and the tick sits on its corner. */
@media (max-width: 860px) {
  #deskLayer .hotspot::before { display: none; }
  #deskLayer .hotspot.is-selected::after {
    inset: 0;
    border-radius: 13px;
    border: 3px solid var(--purple-deep);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.75), 0 8px 20px rgba(72, 52, 130, 0.3);
  }
  #deskLayer .hotspot.is-selected {
    border-radius: 13px;
    background: rgba(124, 95, 196, 0.12);
  }
}

/* ---------- page 2 never scrolls ----------
   The plates are painted into the artwork, so the canvas has to keep the
   picture's exact aspect or the hotspots drift off them. It therefore shrinks
   by width as well as height: on a short phone the classroom gets narrower and
   gains side margins rather than overflowing. */
@media (max-width: 860px) {
  body.simple .scene-year { overflow: hidden !important; }
  body.simple .scene-year .scene-canvas {
    aspect-ratio: 851 / 1622;
    height: min(calc(100vh - var(--top-h) - 126px), calc(100vw * 1622 / 851));
    width: auto;
    max-width: 100%;
    margin-inline: auto;
  }
  @supports (height: 100dvh) {
    body.simple .scene-year .scene-canvas {
      height: min(calc(100dvh - var(--top-h) - 126px), calc(100vw * 1622 / 851));
    }
  }
  body.simple .scene-year .kb,
  body.simple .scene-year .par { flex: 0 0 auto; }

  /* the bar underneath, trimmed to what it needs */
  body.simple .scene-year .flow-bar { gap: 10px; padding: 12px var(--m-pad) 6px; }
  body.simple .flow-status { padding: 8px 18px; font-size: 13px; }
  body.simple .scene-cue { min-height: 48px; padding: 12px 22px; font-size: 15px; }
}

/* ============================================================
   PHONE — PAGE 3, Choose Subject
   The phone shelf is a portrait render cut from the prototype with the books
   painted into it, so each button is an invisible hotspot over its own spine
   and the cut-out PNGs step aside. GCSE shows seven, A-Level five, exactly as
   the laptop does.
   ============================================================ */

@media (max-width: 860px) {
  body.simple .scene-subject { overflow: hidden !important; }

  /* the heading above the artwork, as drawn */
  body.simple .scene-subject .scene-copy,
  body.simple .subject-intro {
    order: -1;
    padding: 0 var(--m-pad) 10px;
    text-align: center;
  }

  /* the plate keeps its exact aspect so the hotspots stay on their books */
  body.simple .scene-subject .kb,
  body.simple .scene-subject .par { flex: 0 0 auto; }
  body.simple .scene-subject .scene-canvas {
    aspect-ratio: var(--shelf-ar, 853 / 1329);
    height: min(calc(100vh - var(--top-h) - 150px), calc(100vw / var(--shelf-num, 0.6418)));
    width: auto;
    max-width: 100%;
    margin-inline: auto;
    overflow: hidden;
  }
  @supports (height: 100dvh) {
    body.simple .scene-subject .scene-canvas {
      height: min(calc(100dvh - var(--top-h) - 150px), calc(100vw / var(--shelf-num, 0.6418)));
    }
  }
  body.simple .scene-subject .scene-canvas .photo {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
  }
  body.simple .scene-subject[data-level="alevel"] .scene-canvas {
    --shelf-ar: 862 / 1326;
    --shelf-num: 0.6501;
  }

  /* simple mode hides hotspot layers by default; the shelf needs this one */
  body.simple #bookLayer {
    display: block;
    position: absolute;
    inset: 0;
  }
  /* Each book is its own cut-out sitting exactly over its painted slot, so
     choosing one slides it forward off the shelf — the same gesture the laptop
     makes, scaled about the bottom edge so a book never uncovers its own slot.
     No tick: the movement and the lift are the confirmation. */
  body.simple #bookLayer .book {
    position: absolute;
    left: var(--mx) !important;
    top: var(--my) !important;
    width: var(--mw) !important;
    height: var(--mh) !important;
    background: none;
    box-shadow: none;
    transform-origin: 50% 100%;
  }
  body.simple #bookLayer .book-img { display: block; }
  /* The tick returns, pinned to the book's top-right corner the way the laptop
     marks a chosen book. It rides with the book as it slides forward. */
  body.simple #bookLayer .book .badge {
    display: grid;
    place-items: center;
    position: absolute;
    top: -9px;
    right: -9px;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--purple);
    color: #fff;
    font-size: 14px;
    line-height: 1;
    box-shadow: 0 6px 14px rgba(95, 67, 174, 0.5);
    transform: scale(0);
    transition: transform 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
    z-index: 2;
  }
  body.simple #bookLayer .book.is-selected .badge { transform: scale(1); }
  body.simple #bookLayer .book::before { display: none; }

  body.simple #bookLayer.is-in .book.is-selected {
    transform: scale(1.075);
    filter: brightness(1.08) drop-shadow(0 14px 26px rgba(95, 67, 174, 0.55));
    z-index: 3;
  }
  /* a moment of give on the press itself */
  body.simple #bookLayer .book:active { transform: scale(1.02); }

  /* the card grid stood in for the shelf on small screens; not needed now */
  body.simple #subjectChoices { display: none; }

  /* the bar underneath matches page 2 */
  body.simple .scene-subject .flow-bar {
    position: relative;
    left: auto; right: auto; bottom: auto;
    transform: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 12px var(--m-pad) 6px;
    background: none;
  }
}

/* ============================================================
   PHONE — PAGES 5 and 6
   Both are portrait renders cut from the prototypes with their buttons painted
   in, so the interactive parts are transparent targets laid over the artwork —
   the same pattern the laptop already uses for the Google pill.
   ============================================================ */

@media (max-width: 860px) {
  /* Both plates keep their exact aspect — the painted buttons only line up if
     the box matches the picture — so they shrink by width as well as height
     and gain side margins on a short phone rather than overflowing. */
  body.simple .scene-stories {
    --plate-h: min(calc(100vh - var(--top-h) - 8px), calc(100vw / 0.6074));
    overflow: hidden !important;
    padding-bottom: 0;
  }
  body.simple .scene-soon {
    --plate-h: min(calc(100vh - var(--top-h) - 8px), calc(100vw / 0.6142));
    overflow: hidden !important;
    padding-bottom: 0;
  }
  @supports (height: 100dvh) {
    body.simple .scene-stories { --plate-h: min(calc(100dvh - var(--top-h) - 8px), calc(100vw / 0.6074)); }
    body.simple .scene-soon { --plate-h: min(calc(100dvh - var(--top-h) - 8px), calc(100vw / 0.6142)); }
  }

  body.simple .scene-stories .kb,
  body.simple .scene-stories .par,
  body.simple .scene-soon .kb,
  body.simple .scene-soon .par { flex: 0 0 auto; display: block; }

  body.simple .scene-stories .scene-canvas,
  body.simple .scene-soon .scene-canvas {
    position: relative;
    height: var(--plate-h);
    width: auto;
    max-width: 100%;
    margin-inline: auto;
    overflow: hidden;
  }
  body.simple .scene-stories .scene-canvas { aspect-ratio: 899 / 1480; }
  body.simple .scene-soon .scene-canvas { aspect-ratio: 898 / 1462; }
  body.simple .scene-stories .scene-canvas .photo,
  body.simple .scene-soon .scene-canvas .photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* simple mode hides hotspot layers by default; these two carry the only
     controls on their page, so they come back */
  body.simple .scene-stories .hotspot-layer,
  body.simple .scene-soon .hotspot-layer {
    display: block;
    position: absolute;
    inset: 0;
  }

  /* the painted controls become real targets at their phone coordinates */
  body.simple .scene-stories .review-hit,
  body.simple .scene-stories .phone-hit,
  body.simple .scene-soon .glow-hotspot {
    left: var(--mx) !important;
    top: var(--my) !important;
    width: var(--mw) !important;
    height: var(--mh) !important;
    border-radius: 999px;
  }
  /* the laptop-only hotspot has no phone coordinates, so it steps aside */
  body.simple .scene-stories .ghost-hotspot:not(.phone-hit) { display: none; }
  body.simple .scene-soon .glow-hotspot { border-radius: 14px; }

  /* the cue is painted into the artwork on this page */
  body.simple .scene-stories > .scene-cue { display: none; }

  /* page 6: the live booking card sits exactly over the painted one, so the
     visitor reads their real date, level and reference rather than a mock-up */
  body.simple .farewell-panel {
    position: absolute;
    left: 50%;
    top: calc(var(--top-h) + var(--plate-h) * 0.513);
    width: calc(var(--plate-h) * 0.6142 * 0.4944);
    transform: translateX(-50%);
    margin: 0;
    padding: 14px 16px;
    border-radius: 18px;
    background: rgba(253, 251, 247, 0.97);
    box-shadow: 0 14px 34px rgba(72, 52, 130, 0.22);
    text-align: center;
  }
  body.simple .fp-title { font-size: 16px; font-weight: 600; color: var(--purple-deep); }
  body.simple .fp-body { margin-top: 6px; font-size: 12px; line-height: 1.4; color: var(--ink-soft); }
  body.simple .fp-cta {
    width: 100%;
    min-height: 42px;
    margin-top: 10px;
    padding: 10px 16px;
    border-radius: 999px;
    font-size: 13px;
    background: none;
    color: var(--purple-deep);
    box-shadow: inset 0 0 0 2px var(--purple-deep);
  }
}

/* ============================================================
   PHONE — PAGE 4, the confirmation state
   The booking form itself is untouched. This is what replaces it once the
   booking is placed: the same card, restated in px because the phone turns the
   laptop's container queries off.
   ============================================================ */

@media (max-width: 860px) {
  body.simple .bk-confirm {
    padding: 22px 18px 20px;
    gap: 0;
    text-align: center;
  }
  body.simple .bkc-tick {
    width: 58px; height: 58px;
    margin: 0 auto 14px;
  }
  body.simple .bkc-title { font-size: 24px; line-height: 1.2; }
  body.simple .bkc-lead {
    margin: 8px auto 0;
    font-size: 13.5px;
    line-height: 1.5;
    max-width: 30em;
  }
  body.simple .bkc-when {
    display: flex;
    justify-content: center;
    gap: 22px;
    margin: 16px 0;
    padding: 14px 0;
    border-top: 1px solid rgba(38, 36, 46, 0.12);
    border-bottom: 1px solid rgba(38, 36, 46, 0.12);
  }
  body.simple .bkc-chip { font-size: 14.5px; gap: 7px; }
  body.simple .bkc-chip svg { width: 18px; height: 18px; }

  body.simple .bkc-rows {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 11px 12px;
    font-size: 14px;
    text-align: left;
  }
  body.simple .bkc-rows dt { font-size: 14px; }
  body.simple .bkc-rows dd { font-size: 14px; }
  body.simple .bkc-ref { margin-top: 14px; font-size: 11.5px; }
  body.simple .bkc-warn {
    margin-top: 14px;
    padding: 12px 14px;
    border-radius: 12px;
    font-size: 13px;
    line-height: 1.45;
  }
  body.simple .bkc-home {
    width: 100%;
    min-height: 52px;
    margin-top: 16px;
    border-radius: 12px;
    font-size: 16px;
  }
  body.simple .bkc-home-lead { margin-top: 10px; font-size: 12.5px; line-height: 1.45; }
  body.simple .bkc-edit-lead { margin-top: 14px; font-size: 12.5px; }
  body.simple .bkc-edit { font-size: 14px; }
}

/* ============================================================
   PHONE — QA pass against a real handset
   Everything below is confined to the phone breakpoint; the laptop layout
   locked at version 9 never sees it.
   ============================================================ */

@media (max-width: 860px) {

  /* ---------- header: two rows that cannot wrap ----------
     It was a wrapping flex row. On a 360px phone the menu button dropped onto a
     line of its own, making the header 151px tall while the pages still offset
     themselves by 114px — which is why headings vanished underneath it and the
     hamburger floated over the rail. A grid fixes the rows in place, and the
     brand scales instead of pushing its neighbours out. */
  .site-header {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "brand email menu"
      "rail  rail  rail";
    align-items: center;
    column-gap: 8px;
    row-gap: 0;
    flex-wrap: nowrap;
    padding-top: max(8px, env(safe-area-inset-top));
    padding-right: max(var(--m-pad), env(safe-area-inset-right));
    padding-left: max(var(--m-pad), env(safe-area-inset-left));
    padding-bottom: 0;
  }
  .header-left { grid-area: brand; min-width: 0; }
  .header-email { grid-area: email; margin-left: 0; }
  .menu-btn { grid-area: menu; margin-left: 0; }
  .stepper { grid-area: rail; }

  /* the wordmark gives way before its neighbours do */
  .brand-name {
    font-size: clamp(17px, 5.9vw, 25px);
    line-height: 1.15;
    white-space: nowrap;
  }
  .brand-sub {
    font-size: clamp(7.5px, 2.4vw, 9px);
    letter-spacing: clamp(0.12em, 0.6vw, 0.22em);
    white-space: nowrap;
  }

  /* both controls: perfectly round, same size, comfortable to hit */
  .header-email,
  .menu-btn {
    width: 44px;
    height: 44px;
    min-width: 44px;
    flex: none;
    border-radius: 50%;
    align-self: center;
  }
  .menu-btn { display: grid; place-items: center; }

  /* ---------- the rail, tightened ----------
     It was eating 54px plus the header's own row. Same components, less air. */
  .stepper {
    height: auto;
    min-height: 0;
    padding: 4px 0 7px;
    align-items: center;
  }
  .step { align-self: flex-start; }
  .step-dot { width: 26px; height: 26px; font-size: 11px; }
  .step:not(.is-active):not(.is-done) .step-dot { width: 10px; height: 10px; margin: 8px 0; }
  .step-line { margin-top: 13px; }
  .step-label { font-size: 10px; margin-top: 2px; }

  /* ---------- every page starts clear of the header ----------
     --top-h is written by the header itself at runtime, so a device whose
     fonts make the header taller still gets the right offset. */
  body.simple .scene { padding-top: var(--top-h); }
  body.simple .scene-entrance { padding-top: var(--top-h); }

  /* ---------- pages scroll naturally when they must ----------
     A phone in a browser has less height than the drawings assume once the
     address bar is showing. Rather than clip, the page scrolls — but only when
     it genuinely has to, so on a tall phone it still lands on one screen. */
  body.simple .scene.is-current {
    overflow-y: auto !important;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  body.simple .scene-entrance,
  body.simple .scene-year,
  body.simple .scene-subject,
  body.simple .scene-stories,
  body.simple .scene-soon { overflow-y: auto !important; }

  /* ---------- page 1: the doorway keeps a dignified minimum ----------
     It was free to shrink to whatever was left, which on a 412px phone left a
     110px letterbox. Now it has a floor; if that means the page scrolls a
     little on a short handset, it scrolls. */
  body.simple .scene-entrance .kb { min-height: min(46vw, 230px); }
  body.simple .scene-entrance .frame-door { min-height: min(46vw, 230px); }
  body.simple .scene-entrance .frame-door .photo { object-position: 40% 42%; }

  /* ---------- the robot keeps out of the way ----------
     Fixed to the viewport it floated over whatever happened to be under it as
     the page scrolled — on a real phone that was the Google rating. It now
     rides at the end of page 1's own content, which is where the drawing puts
     it: bottom right, beside the subjects card, obscuring nothing. */
  /* The robot is a floating trigger, not page content: fixed to the viewport,
     so it holds its place however far you scroll and never adds to the page's
     height. Every page instead reserves room at its foot, which is what keeps
     it from covering the last card rather than moving it into the flow. */
  body.simple .contact-card {
    position: fixed;
    z-index: 70;
    right: max(12px, env(safe-area-inset-right));
    bottom: max(12px, env(safe-area-inset-bottom));
    left: auto;
    top: auto;
    width: min(300px, calc(100vw - 24px));
    align-items: flex-end;
    pointer-events: none;
  }
  body.simple .contact-card > * { pointer-events: auto; }
  body.simple .cc-bubble { width: 100%; }
  /* Nothing is reserved for the robot: it floats over the page, so the page
     ends where its content ends. Only the device's own inset is honoured. */
  body.simple .scene { padding-bottom: env(safe-area-inset-bottom); }

  /* ---------- CTAs clear of the device's own chrome ---------- */
  body.simple .flow-bar { padding-bottom: max(6px, env(safe-area-inset-bottom)); }
  body.simple .scene-cue { min-height: 52px; }

  /* ---------- page 4: nothing tucked under the header ----------
     The card was pulled up by a negative margin to overlap the artwork, which
     on a phone slid it straight under the fixed header and clipped "1. Choose
     a date". */
  body.simple .laptop-screen { margin-top: 0; }
  /* the booking form keeps a little, so its last field clears the robot */
  body.simple .scene-call { padding-bottom: calc(72px + env(safe-area-inset-bottom)); }

  /* ---------- page 3: the Continue button says what it means ---------- */
  body.simple .scene-cue:not(.is-ready) {
    background: var(--lavender-bg);
    color: rgba(95, 67, 174, 0.55);
    box-shadow: none;
  }
  body.simple .scene-cue.is-ready {
    background: var(--purple);
    color: #fff;
    box-shadow: 0 10px 24px rgba(124, 95, 196, 0.32);
  }
}

/* Real phones report a viewport that changes as the address bar comes and
   goes. svh is the smallest of those, so a layout sized against it is never
   clipped by browser chrome appearing. */
@supports (height: 100svh) {
  @media (max-width: 860px) {
    body.simple .scene-year .scene-canvas {
      height: min(calc(100svh - var(--top-h) - 126px), calc(100vw * 1622 / 851));
    }
    body.simple .scene-subject .scene-canvas {
      height: min(calc(100svh - var(--top-h) - 150px), calc(100vw / var(--shelf-num, 0.6418)));
    }
    body.simple .scene-stories { --plate-h: min(calc(100svh - var(--top-h) - 8px), calc(100vw / 0.6074)); }
    body.simple .scene-soon { --plate-h: min(calc(100svh - var(--top-h) - 8px), calc(100vw / 0.6142)); }
  }
}

/* ---------- page 6: the two states must not read alike ----------
   A completed booking and a half-finished one are different messages. The
   confirmation is affirmed with a tick and the brand purple; the reminder is
   quieter and amber, so nobody mistakes it for a booking that went through. */
@media (max-width: 860px) {
  body.simple .farewell-panel {
    /* the painted card is 49% of the plate, which is under 180px on a 360px
       phone — too tight for the booking line. A little wider reads properly
       and still sits on the drawn card. */
    width: min(84%, 320px);
    padding: 15px 17px;
  }
  body.simple .farewell-panel.is-booked .fp-title::before {
    content: "✓";
    display: grid;
    place-items: center;
    width: 34px; height: 34px;
    margin: 0 auto 8px;
    border-radius: 50%;
    background: var(--purple);
    color: #fff;
    font-size: 17px;
  }
  body.simple .farewell-panel.is-booked .fp-title { color: var(--purple-deep); }
  body.simple .farewell-panel.is-reminder .fp-title { color: #9a6b1f; font-size: 15px; }
  body.simple .farewell-panel.is-reminder {
    background: rgba(255, 251, 243, 0.97);
    box-shadow: 0 14px 34px rgba(120, 90, 30, 0.2), inset 0 0 0 1.5px rgba(201, 162, 77, 0.5);
  }
  body.simple .farewell-panel.is-reminder .fp-cta {
    color: #9a6b1f;
    box-shadow: inset 0 0 0 2px #c9a24d;
  }
}

/* ---------- the artwork is sized by width, and the page scrolls ----------
   Sizing the plates by the leftover height shrank them hard on a short phone:
   at 375x667 the bookshelf came out 263px wide and its books 43px — under the
   comfortable tap size, and a much tighter crop than the drawings show. Width
   drives them now, so every plate is exactly as framed in the prototype at
   every width; where that leaves the page taller than the screen, the page
   scrolls, which is the behaviour asked for. */
@media (max-width: 860px) {
  body.simple .scene-year .scene-canvas,
  body.simple .scene-subject .scene-canvas {
    height: auto !important;
    width: 100% !important;
    max-width: none;
    margin-inline: 0;
  }
  body.simple .scene-year .scene-canvas { aspect-ratio: 851 / 1622; }
  body.simple .scene-subject .scene-canvas { aspect-ratio: var(--shelf-ar, 853 / 1329); }

  body.simple .scene-stories,
  body.simple .scene-soon { --plate-h: auto; }
  body.simple .scene-stories .scene-canvas,
  body.simple .scene-soon .scene-canvas {
    height: auto;
    width: 100%;
    max-width: none;
    margin-inline: 0;
  }

  /* page 6's card is placed against the plate, which is now width-driven */
  body.simple .farewell-panel {
    top: calc(var(--top-h) + (100vw / 0.6142) * 0.513);
    width: min(84%, 320px);
  }

  /* every page can scroll to its end, clear of the device's own controls */
  body.simple .scene-year,
  body.simple .scene-subject,
  body.simple .scene-stories,
  body.simple .scene-soon { padding-bottom: env(safe-area-inset-bottom); }
}

/* The transparent targets over painted buttons follow the paint exactly, which
   on a narrow phone is a couple of pixels under a comfortable tap. They are
   invisible, so a small floor costs nothing visually. */
@media (max-width: 860px) {
  body.simple .scene-stories .review-hit,
  body.simple .scene-stories .phone-hit,
  body.simple .scene-soon .glow-hotspot { min-height: 44px; }
}

/* ---------- last of the touch-target and spacing snags ---------- */
@media (max-width: 860px) {
  /* the arrow was sitting against the final letter */
  .entrance-actions .btn-quiet {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    min-height: 44px;
    padding: 8px 6px;
  }
  .entrance-actions .btn-quiet span[aria-hidden] { line-height: 1; }

  /* comfortable to tap without changing the approved booking layout */
  body.simple .bk-altlink {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4em;
    min-height: 44px;
    padding: 8px 10px;
  }
}

/* The page beneath the map holds completely still, and nothing taps through. */
body.menu-open .scene.is-current { overflow: hidden !important; }
body.menu-open .stage,
body.menu-open .site-header,
body.menu-open .contact-card { pointer-events: none; }
body.menu-open #menuBtn { pointer-events: auto; }


/* ---------- no dead band at the foot of a page ----------
   The floating dock is only painted on page 1 — it lives inside that scene, so
   every other page was reserving 74px for something that was not there. Only
   page 1 makes room now, and only as much as the dock currently occupies. */
@media (max-width: 860px) {
  body.simple .scene { padding-bottom: env(safe-area-inset-bottom); }
  body.simple .scene-year,
  body.simple .scene-subject,
  body.simple .scene-stories,
  body.simple .scene-soon { padding-bottom: max(8px, env(safe-area-inset-bottom)); }
  body.simple .scene-call { padding-bottom: max(14px, env(safe-area-inset-bottom)); }

  /* Page 1 reserves nothing either: the robot floats over it. */
  body.simple .scene-entrance { padding-bottom: max(8px, env(safe-area-inset-bottom)); }
}

/* ---------- no cream gap under the artwork ----------
   Each page ends on the colour its own plate ends on — the classroom floor,
   the library shelf, the booking desk — so the strip below the picture reads
   as part of the room rather than as bare page. Sampled from the bottom row
   of each plate, so the join is invisible. */
@media (max-width: 860px) {
  /* The classroom now reaches the foot of the page itself, so the ground only
     has to cover the last few pixels below it — the floor's own tone. */
  body.simple .scene-year { background: #d48c48; }
  body.simple .scene-subject { background: #ebdacf; }
  body.simple .scene-subject[data-level="alevel"] { background: #eeddd2; }
  body.simple .scene-call { background: #956235; }

  /* the flow bar sits on that ground rather than punching a pale hole in it */
  body.simple .scene-year .flow-bar,
  body.simple .scene-subject .flow-bar { background: none; }
}

/* ---------- page 2: the controls sit on their painted counterparts ----------
   The supplied artwork carries the whole classroom right down to the bookshelf,
   rug and plants, with the status pill and the Continue button drawn into it.
   The live controls are laid exactly over those, the way the Google pill works
   on page 5 — so the scene stays whole and the text stays real. */
@media (max-width: 860px) {
  body.simple .scene-year .kb { position: relative; }
  /* The overlay carries the artwork's own aspect ratio rather than filling its
     parent, so its percentages land on the picture at every width. Sized off
     the parent it drifted, and at 360px the painted button showed below the
     live one. */
  body.simple .scene-year .flow-bar {
    position: absolute;
    left: 50%;
    /* An absolutely positioned child is placed against the scene's PADDING box,
       and the scene is padded down by the header. Without this offset the
       overlay sat a header's height above the artwork, which is why the live
       button appeared as a second button above the painted one. */
    top: var(--top-h);
    transform: translateX(-50%);
    width: 100%;
    max-width: none;
    aspect-ratio: 851 / 1622;
    height: auto;
    /* an inherited top margin was pushing the whole overlay 18px down the page */
    margin: 0;
    padding: 0;
    gap: 0;
    pointer-events: none;
    background: none;
  }
  body.simple .scene-year .flow-bar > * { pointer-events: auto; }
  /* This artwork paints only the Continue button, so the live button covers it
     exactly and the status pill — which the drawing no longer includes — sits
     on the clear floor just above it. Nothing appears twice. */
  body.simple .scene-year .flow-status {
    position: absolute;
    left: 50%;
    /* pinned to the button rather than to a percentage of its own, so it always
       sits just above it and never drifts up over the desks */
    top: auto;
    bottom: calc(9.37% + 12px);
    transform: translateX(-50%);
    width: auto;
    min-height: 34px;
    display: grid;
    place-items: center;
    padding: 0 18px;
    margin: 0;
    font-size: clamp(11px, 3.1vw, 14px);
    white-space: nowrap;
  }
  /* The artwork already draws "Choose your subject". Rather than print it a
     second time, the live control becomes a transparent target laid over the
     painted one — the same pattern as the Google pill on page 5. Its label
     stays in the accessibility tree for screen readers. */
  body.simple .scene-year .scene-cue {
    position: absolute;
    left: 15.86%;
    top: 90.63%;
    width: 64.63%;
    max-width: none;
    height: 5.30%;
    min-height: 44px;
    margin: 0;
    padding: 0;
    border-radius: 999px;
    background: none !important;
    box-shadow: none !important;
    color: transparent !important;
    font-size: 0;
    /* the button carries a backdrop blur for the laptop; over the painted
       button it was frosting the artwork's own lettering */
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  body.simple .scene-year .scene-cue > * { visibility: hidden; }
  body.simple .scene-year .scene-cue:focus-visible {
    outline: 3px solid var(--purple-deep);
    outline-offset: 3px;
  }
}

/* ============================================================
   LAPTOP — refinements. Everything here is above the phone
   breakpoint, so the mobile build is untouched.
   ============================================================ */

@media (min-width: 861px) {
  /* ---- page 1: let the wording stretch ----
     The columns had been pulled in tight so the copy stayed clear of the
     doorway. There is more room than that on a laptop, so the headline and
     both paragraphs run wider while still finishing before the picture. */
  /* Stretched as far as the doorway allows. Past roughly x=576 the body ink
     falls under 4.5:1 against the fading photograph, so the columns stop
     there — still far wider than before, and still legible. The caps are in
     em, so they hold their measure as the type below grows. */
  .hero-promise {
    font-size: clamp(28px, min(3.4vw, 6.1vh), 52px);
    max-width: 15.6em;
  }
  .entrance-copy .lede {
    font-size: clamp(16px, 1.42vw, 21px);
    max-width: 26.5em;
  }
  .entrance-copy .lede-quiet {
    font-size: clamp(14px, 1.2vw, 18px);
    max-width: 27.5em;
  }
  /* Wider and larger copy reaches further into the doorway, where the
     photograph is already 40% opaque. A shade more ink keeps both paragraphs
     above 4.5:1 there; they still read quieter than the headline. */
  .entrance-copy .lede { color: #4a4652; }

  /* ---- pages 2 and 3: a button, not a scroll prompt ----
     Scrolling no longer moves the story, so the mouse glyph would be a lie.
     Both cues get the same treatment the phone already gives them. */
  .scene-year .scene-cue > svg:first-child,
  .scene-subject .scene-cue > svg:first-child { display: none; }
  .scene-year .scene-cue,
  .scene-subject .scene-cue {
    gap: 10px;
    padding: 14px 30px;
    font-size: 16px;
  }
  .scene-year .scene-cue .cue-go,
  .scene-subject .scene-cue .cue-go { display: inline; font-size: 18px; line-height: 1; }

  /* ---- page 4: the alternative is easier to read and to hit ---- */
  .bk-altlink {
    font-size: 3.1cqh;
    padding: 1.2cqh 1.2cqw;
    font-weight: 600;
  }

  /* ---- page 6: the confirmation sits lightly over the scene ----
     A booked visitor gets a compact, translucent bubble that lets the room
     read through it, rather than a panel across the artwork. The prompt to
     book keeps its fuller treatment, because that one is asking for an action. */
  .farewell-panel.is-booked {
    width: min(380px, 38vw);
    padding: 18px 22px;
    background: rgba(250, 246, 238, 0.82);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    box-shadow: 0 12px 30px rgba(72, 52, 130, 0.16);
  }
  .farewell-panel.is-booked .fp-title { font-size: 20px; }
  .farewell-panel.is-booked .fp-body { font-size: 14px; }
}


/* A word that must never be broken across two lines. */
.nowrap { white-space: nowrap; }

/* ============================================================
   PAGE 2 · THE SHORTCUT TO BOOKING
   The cue in the middle is still the gate — it goes to Choose Subject, and
   only once a year has been picked. This stands apart from it, quieter and
   off to the side, for a parent who already knows what they want and would
   rather book the call than walk the rest of the journey.
   ============================================================ */

.flow-shortcut {
  position: absolute;
  /* Right-aligned with the contact dock and stacked directly above it, so the
     two never sit on top of each other however tall the bubble is. */
  right: clamp(16px, 2.4vw, 30px);
  bottom: calc(var(--dock-top, 210px) + 16px);
  z-index: 6;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.9);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  box-shadow: 0 6px 18px rgba(72, 52, 130, 0.14);
  color: var(--purple-deep);
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}
.flow-shortcut .fs-go { font-size: 17px; line-height: 1; }
.flow-shortcut:hover {
  background: #fff;
  box-shadow: 0 10px 24px rgba(72, 52, 130, 0.2);
  transform: translateY(-1px);
}
.flow-shortcut:focus-visible { outline: 3px solid var(--purple-soft); outline-offset: 3px; }

/* Phones are locked: their page 2 is the painted plate and nothing else. */
@media (max-width: 860px) { .flow-shortcut { display: none; } }

/* ============================================================
   PAGE 6 · ONCE THE BOOKING IS MADE
   The purple "Book Your First Lesson" button is painted into the artwork, so
   a booked visitor cannot simply be shown a different panel — the offer would
   still be there behind it. Instead the wall is repainted over the button and
   the confirmation takes its place, translucent, so the room still reads.
   ============================================================ */

.fw-patch {
  position: absolute;
  left: 35.677%;
  top: 39.735%;
  width: 33.073%;
  height: 18.322%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.45s ease;
}

@media (min-width: 861px) {
  body:not(.simple) .scene-soon.is-booked .fw-patch { opacity: 1; }

  /* the painted button is gone, so its hotspot goes with it */
  body:not(.simple) .scene-soon.is-booked #bookLessonBtn {
    opacity: 0;
    pointer-events: none;
  }

  /* Sat exactly where the button was: the canvas is centred on the viewport
     and keeps the artwork's own ratio, so the button's centre — 52.18% across
     and 49.28% down the plate — is these two offsets from the middle. */
  body:not(.simple) .scene-soon.is-booked .farewell-panel {
    bottom: auto;
    left: calc(50% + 0.0218 * max(100vw, 100vh * var(--r-wide)));
    top: calc(50% - 0.0072 * max(100vh, 100vw / var(--r-wide)));
    transform: translate(-50%, -50%);
  }
}

/* ============================================================
   PHONE — THE ARTWORK IS THE PAGE
   The prototype renders are full-screen: 852x1847, which is a phone's own
   shape, and they carry their own chrome — the wordmark, the mail and menu
   buttons, and the step rail, already drawn in the right state for the page
   they belong to. So the plate is not a band with cream above and below it any
   more; it IS the page, and the live header stops drawing itself and becomes
   invisible targets laid over the paint. That is the same pattern the year
   signs and the Continue button have always used.

   Applies only to scenes listed in PAINTED_CHROME in main.js, which is how the
   converted pages and the ones still on the old plates coexist.
   ============================================================ */

@media (max-width: 860px) {
  /* ---------- the plate fills the screen ---------- */
  body.simple.painted-chrome .scene.is-current { padding-top: 0; }

  body.simple .scene-year .scene-canvas {
    /* the prototype's own shape; width-driven, so it always spans the screen */
    aspect-ratio: 852 / 1847 !important;
  }

  /* The header is the shared component below; nothing here positions it.
     Each plate used to carry its own painted rail, so each page pinned the
     live controls to that plate's paint — six geometries for one component,
     which is what made the rail move as you walked through the flow. The
     paint is gone from the plates and so are the six. */

  /* A cue carries `backdrop-filter: blur(5px)` so that, floating over artwork,
     it lifts its own label off the picture. Laid over a painted button as an
     invisible target it does the opposite: it blurs the very paint it is
     meant to reveal, and the painted label smears. */
  body.simple.painted-chrome .scene-cue {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  /* A cue laid over a painted button must be the painted button's size, not a
     44px minimum: forced taller, its rounded cap no longer coincides with the
     paint's, and the painted pill shows around the live one as a pale outline.
     The tap area is grown by a pseudo element instead, which does not move or
     resize the pill itself. */
  body.simple.painted-chrome .scene-cue { min-height: 0; }
  body.simple.painted-chrome .scene-cue::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: max(100%, 44px);
    height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }

  /* ---------- the ground under the plate ----------
     Each page ends on the colour its own plate ends on, so where a handset is
     a little taller than the picture the strip below reads as more floor
     rather than as a band. These were sampled from the OLD plates and were
     left pointing at colours that no longer appear anywhere on the page —
     which is why a bold stripe showed up under pages 2 and 3. Re-measured from
     the bottom rows of the plates actually in use. */
  body.simple.painted-chrome[data-scene="1"] .scene-year { background: #ac6426; }
  body.simple.painted-chrome[data-scene="2"] .scene-subject { background: #482305; }
  body.simple.painted-chrome[data-scene="2"] .scene-subject[data-level="alevel"] { background: #442612; }
  body.simple.painted-chrome[data-scene="3"] .scene-call {
    /* The scrolling form runs below the bottom of the fixed-height artwork.
       Continue the actual desk colours at each exposed side instead of ending
       the page on one bold brown strip. */
    background: #c18b60;
  }

  /* ---------- page 3: two shelves, two renders ----------
     GCSE and A-Level are separate prototype renders and their chrome does not
     land in quite the same place, so the header's targets are restated per
     level off `body[data-level]`, which renderShelf() writes. */
  body.simple .scene-subject .scene-canvas {
    aspect-ratio: 853 / 1844 !important;
    --shelf-ar: 853 / 1844;
  }
  body.simple .scene-subject[data-level="alevel"] .scene-canvas {
    aspect-ratio: 851 / 1847 !important;
    --shelf-ar: 851 / 1847;
    --shelf-num: 0.4607;
  }
  /* The phone uses cut-outs from these exact portrait prototypes. Resting they
     cover the painted books pixel-for-pixel; selected they can lift forward. */
  body.simple.painted-chrome .scene-subject .book { background: none; }
  body.simple.painted-chrome .scene-subject .book-img { display: block; }
  body.simple.painted-chrome .scene-subject .book.is-selected .book-img {
    outline: none;
  }
  /* Scale from the book's own base and do not lift it.
     A cut-out ends where the book stops being visible, and on the shelves that
     is the line where the wood crosses in front of it. `translateY` slid the
     whole cut-out up off that line, so the last few pixels of the painted book
     were left behind as a strip under the one that had moved — the book looked
     cut in half. Scaling about `50% 100%`, which these already do, grows the
     book from its base: the bottom edge stays welded to the shelf, and the
     enlarged cut-out covers every pixel of the painted book beneath it, because
     a shape scaled up about a point on its own boundary contains the original.
     Geography never showed the fault only because it stands clear on the
     bottom shelf with nothing crossing in front of it. */
  body.simple.painted-chrome .scene-subject #bookLayer.is-in .book.is-selected {
    transform: scale(1.075);
    filter: brightness(1.08) drop-shadow(0 16px 26px rgba(95, 67, 174, 0.52));
  }

  /* The two pills at the foot are painted too. The Continue button never
     changes its wording on a phone, so it stays a transparent target; the
     status pill DOES change — it counts the subjects chosen — so the live one
     is drawn opaque over its painted twin rather than hidden. */
  body.simple.painted-chrome .scene-subject .flow-bar {
    position: absolute;
    left: 0; top: 0; right: auto; bottom: auto;
    width: 100%;
    max-width: none;
    height: auto;
    aspect-ratio: var(--shelf-ar, 853 / 1844);
    margin: 0;
    padding: 0;
    transform: none;
    background: none;
    display: block;
    pointer-events: none;
  }
  body.simple.painted-chrome .scene-subject .flow-bar > * { pointer-events: auto; }

  body.simple.painted-chrome .scene-subject .flow-status {
    position: absolute;
    left: 15.944%; top: 87.798%; width: 69.050%; height: 3.905%;
    display: grid;
    place-items: center;
    margin: 0;
    padding: 0 2%;
    border-radius: 999px;
    background: #ece7fa;
    color: var(--purple-deep);
    font-size: clamp(11px, 3.3vw, 15px);
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body.simple.painted-chrome .scene-subject[data-level="alevel"] .flow-status {
    left: 11.163%; top: 87.331%; width: 77.556%; height: 3.952%;
  }

  body.simple.painted-chrome .scene-subject .scene-cue {
    position: absolute;
    left: 12.309%; top: 92.950%; width: 76.436%; height: 4.664%;
    padding: 0;
    border-radius: 999px;
    background: none;
    box-shadow: none;
    color: transparent;
    font-size: 0;
  }
  body.simple.painted-chrome .scene-subject[data-level="alevel"] .scene-cue {
    left: 11.281%; top: 92.420%; width: 77.438%; height: 5.089%;
  }
  body.simple.painted-chrome .scene-subject .scene-cue svg,
  body.simple.painted-chrome .scene-subject .scene-cue .cue-go { display: none; }
  /* The prototype already paints the Continue bubble. It stays the one visible
     bubble in both states; selection changes its behaviour, not its paint. */
  body.simple.painted-chrome .scene-subject .scene-cue.is-ready {
    background: none;
    color: transparent;
    font-size: 0;
    box-shadow: none;
  }
  body.simple.painted-chrome .scene-subject[data-level="alevel"] .scene-cue.is-ready {
    left: 11.281%;
    top: 92.420%;
    width: 77.438%;
    height: 5.089%;
  }
  body.simple.painted-chrome .scene-subject .scene-cue.is-ready .cue-go { display: none; }

  /* ---------- pages 5 and 6 ----------
     These two plates are still the shape they were drawn at, 0.52 rather than
     a phone's 0.46, so they run full width and leave a strip at the foot. That
     strip is painted the colour each plate ends on — desk, carpet — so it
     reads as more floor rather than as a band. Page 6 has two plates, one per
     state, and they are different shapes, so each is given its own. */
  /* These two were drawn at 0.52 and a phone is 0.46, so run at full width they
     stop about 75px short of the bottom — far too deep a strip to disguise with
     a matched colour, which is the very thing that made pages 2 and 3 read as
     banded. So the plate is widened until it covers the screen instead, and the
     scene clips what hangs over the sides: about 5.7% off each edge, which
     costs the outer sliver of a plant and a notepad and nothing that is read.

     The canvas keeps the picture's own ratio throughout, so every painted
     target still sits at the same percentage of it — none of the coordinates
     move. `--cw` is the plate's real width, which anything positioned outside
     the canvas has to measure itself against. */
  /* Set on the body, not the scene: the header is fixed and sits outside the
     scene, and it has to line its targets up against the same box. */
  /* Fill the viewport by height while preserving each image's own aspect ratio.
     The small horizontal overhang is clipped; page 6 is biased left below so
     its farther-right menu circle stays completely visible. */
  body.simple.painted-chrome[data-scene="4"] { --cw: max(100vw, calc(100dvh * 905 / 1738)); }
  body.simple.painted-chrome[data-scene="5"] {
    --cw: max(100vw, calc(100dvh * 904 / 1740));
  }
  body.simple.painted-chrome[data-scene="5"].booked { --cw: max(100vw, calc(100dvh * 854 / 1842)); }

  body.simple .scene-stories,
  body.simple .scene-soon { overflow-x: hidden !important; }

  body.simple .scene-stories .scene-canvas,
  body.simple .scene-soon .scene-canvas {
    position: relative;
    height: auto !important;
    width: var(--cw, 100%) !important;
    max-width: none;
    margin-inline: 0;
    left: 50%;
    transform: translateX(-50%);
  }
  body.simple .scene-stories .scene-canvas { aspect-ratio: 905 / 1738 !important; }
  body.simple .scene-soon .scene-canvas { aspect-ratio: 904 / 1740 !important; }
  body.simple .scene-soon.is-booked .scene-canvas { aspect-ratio: 854 / 1842 !important; }
  body.simple .scene-stories .scene-canvas .photo,
  body.simple .scene-soon .scene-canvas .photo {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
  }
  /* the feather that softened the old letterboxed plates has nothing to soften
     now that each page ends on its own floor */
  body.simple .scene-stories .scene-canvas,
  body.simple .scene-soon .scene-canvas {
    -webkit-mask-image: none;
    mask-image: none;
  }
  body.simple.painted-chrome[data-scene="4"] .scene-stories { background: #bf844d; }
  body.simple.painted-chrome[data-scene="5"] .scene-soon { background: #d2a07b; }
  body.simple.painted-chrome[data-scene="5"].booked .scene-soon { background: #ac8462; }

  /* Page 6's card carries the real booking, so it is drawn over the painted
     one rather than hidden. Each state has its own box because each state is
     its own render. */
  /* Measured against `--cw` rather than the scene, because the plate is wider
     than the screen and the painted card it covers sits on the plate. */
  body.simple.painted-chrome .farewell-panel {
    position: absolute;
    left: calc(50% - var(--cw, 100%) / 2 + var(--cw, 100%) * 0.155);
    top: 59.5%;
    width: calc(var(--cw, 100%) * 0.61);
    height: auto;
    min-height: 17.5%;
    max-width: none;
    margin: 0;
    padding: 14px 16px;
    border-radius: 20px;
    background: #fdfaf5;
    box-shadow: 0 14px 34px rgba(72, 52, 130, 0.18);
    text-align: center;
    transform: none;
    /* the card has to stay as tall as the painted one it covers, so where the
       copy runs shorter the slack is shared top and bottom rather than left
       hanging under the button */
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  body.simple.painted-chrome.booked .farewell-panel {
    left: calc(50% - var(--cw, 100%) / 2 + var(--cw, 100%) * 0.235);
    top: 45.0%;
    width: calc(var(--cw, 100%) * 0.53);
    min-height: 38.5%;
  }

  /* the offer is painted into the pre-booking plate only, so once the booking
     exists there is no painted button left to cover — and none to disable */
  body.simple.painted-chrome .scene-soon .scene-canvas::after { content: none; }

  /* ---------- page 4: the live card stands on the painted one ----------
     The background switches between the supplied form and confirmation renders.
     The booking UI stays live — a real calendar and real fields — in an opaque
     card occupying the prototype's panel. */
  body.simple .scene-call .scene-canvas {
    aspect-ratio: 852 / 1847 !important;
    height: auto !important;
    width: 100% !important;
    max-width: none;
    margin-inline: 0;
  }
  body.simple .scene-call .scene-canvas .photo {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
  }
  body.simple.painted-chrome .scene-call .kb,
  body.simple.painted-chrome .scene-call .par { position: absolute; inset: 0; display: block; }

  body.simple.painted-chrome .scene-call .scene-canvas {
    aspect-ratio: auto !important;
    min-height: calc(100vw * 1847 / 852);
    padding-top: calc(100vw * 1847 / 852 * 0.125);
    padding-bottom: max(26px, 6vw);
    overflow: visible;
    isolation: isolate;
  }
  body.simple.painted-chrome .scene-call .scene-canvas picture {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: calc(100vw * 1847 / 852);
    overflow: hidden;
    z-index: 0;
  }
  body.simple.painted-chrome .scene-call .scene-canvas .photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  body.simple.painted-chrome .laptop-screen {
    position: relative;
    left: auto;
    top: auto;
    width: 73%;
    height: auto;
    margin: 0 auto;
    border-radius: 22px;
    /* Fully opaque, not merely near it: at 97% the painted card's own
       "Thank you for the confirmation!" and its sample date read straight
       through the live form behind the calendar. */
    background: #fdfaf5;
    box-shadow: 0 18px 44px rgba(72, 52, 130, 0.18);
    overflow: visible;
    overscroll-behavior: auto;
    z-index: 2;
  }
  body.simple.painted-chrome .laptop-screen::-webkit-scrollbar { width: 0; height: 0; }

  /* The phone form was laid out in px against a card spanning the full width
     less 40px. This panel is the painted card's box instead — narrower — so
     the form is scaled to it rather than re-stated field by field. 0.82 is the
     ratio between the two widths, which is what stops "Parent / Guardian name"
     running off the right edge.

     Scaled on the two form columns and not on `.bk` itself: the confirmation
     is an absolutely positioned panel filling `.bk`, so zooming the parent
     shrank the panel to 82% of the card and left the last fifth of it empty —
     the gap under the booking summary. */
  body.simple.painted-chrome .laptop-screen .bk {
    height: auto;
    grid-auto-rows: auto;
  }
  body.simple.painted-chrome .laptop-screen .bk-left,
  body.simple.painted-chrome .laptop-screen .bk-right {
    zoom: 0.82;
    min-height: max-content;
  }

  /* The confirmation cannot be zoomed the same way — it is a panel pinned to
     the card, so scaling it shrinks the panel and puts the gap back. Its type
     is tightened instead, which fits the whole summary and its two buttons on
     the card without the card having to scroll. */
  body.simple.painted-chrome .bk-confirm { padding: 14px 15px 12px; }
  body.simple.painted-chrome .bkc-tick { width: 42px; height: 42px; margin-bottom: 8px; }
  body.simple.painted-chrome .bkc-title { font-size: 18.5px; }
  body.simple.painted-chrome .bkc-lead { font-size: 11.5px; margin-top: 5px; }
  body.simple.painted-chrome .bkc-when {
    gap: 12px;
    margin: 9px 0;
    padding: 8px 0;
  }
  body.simple.painted-chrome .bkc-chip { font-size: 12.5px; gap: 5px; }
  body.simple.painted-chrome .bkc-chip svg { width: 15px; height: 15px; }
  body.simple.painted-chrome .bkc-rows { gap: 7px 10px; font-size: 12px; }
  body.simple.painted-chrome .bkc-rows dt,
  body.simple.painted-chrome .bkc-rows dd { font-size: 12px; }
  body.simple.painted-chrome .bkc-ref { margin-top: 9px; font-size: 10.5px; }
  body.simple.painted-chrome .bkc-home {
    min-height: 42px;
    margin-top: 11px;
    font-size: 13.5px;
  }
  body.simple.painted-chrome .bkc-home-lead { margin-top: 7px; font-size: 11px; }
  body.simple.painted-chrome .bkc-edit-lead { margin-top: 9px; font-size: 11px; }
  body.simple.painted-chrome .bkc-edit { font-size: 12.5px; }

  /* ---------- page 2's own painted controls ---------- */
  /* This plate paints only the Continue button, no status pill — but the laptop
     has always said what you have chosen, and without it the phone gives no
     feedback beyond the ring on the sign. So the live pill is drawn in, sitting
     just above the painted button and styled like the one on page 3. */
  body.simple.painted-chrome .scene-year .flow-status {
    display: grid;
    place-items: center;
    position: absolute;
    /* the rule this overrides centres by transform off `bottom`; both have to
       be undone or the pill lands half its own width off the left edge */
    left: 16%;
    right: auto;
    top: 85.1%;
    bottom: auto;
    transform: none;
    width: 66%;
    height: 3.9%;
    min-height: 0;
    margin: 0;
    padding: 0 3%;
    border-radius: 999px;
    background: #ece7fa;
    color: var(--purple-deep);
    font-size: clamp(11px, 3.3vw, 14.5px);
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    box-shadow: 0 6px 16px rgba(72, 52, 130, 0.14);
  }
  body.simple.painted-chrome .scene-year .flow-bar {
    position: absolute;
    left: 0; top: 0; right: auto; bottom: auto;
    width: 100%;
    max-width: none;
    height: auto;
    aspect-ratio: 852 / 1847;
    margin: 0;
    padding: 0;
    transform: none;
    background: none;
    pointer-events: none;
  }
  body.simple.painted-chrome .scene-year .flow-bar > * { pointer-events: auto; }
  body.simple.painted-chrome .scene-year .scene-cue {
    position: absolute;
    left: 19.72%;
    top: 90.42%;
    width: 58.69%;
    height: 4.71%;
    padding: 0;
    border-radius: 999px;
    background: none !important;
    box-shadow: none !important;
    color: transparent !important;
    font-size: 0;
  }
  body.simple.painted-chrome .scene-year .scene-cue svg,
  body.simple.painted-chrome .scene-year .scene-cue .cue-go { display: none; }

  /* The unconfirmed page already contains the exact white reminder card from
     the prototype. Do not lay a second live card over it. The painted purple
     booking button immediately above remains the route back to page 4. */
  body.simple.painted-chrome:not(.booked) .scene-soon .farewell-panel { display: none; }

  /* Page 6 uses the same height-filling treatment as page 5. Its menu is drawn
     slightly farther right, so bias the wider plate left just enough to keep
     the whole circle visible without distorting the artwork. */
  body.simple.painted-chrome[data-scene="5"]:not(.booked) .scene-soon .scene-canvas {
    left: calc(50% - 7px);
  }
  body.painted-chrome[data-scene="5"]:not(.booked) .site-header {
    left: calc((100vw - var(--cw, 100vw)) / 2 - 7px);
  }

}
/* ============================================================
   PROTOTYPE PHONE PLATE GEOMETRY
   The shared live header below remains the sole visible chrome; this section
   maps each supplied portrait and its interactive content to the viewport.
   ============================================================ */
@media (max-width: 860px) {
  /* Page 4 uses the supplied form render at its native 909:1731 ratio. It fills
     tall phones by height, preserving the photograph rather than stretching or
     reflecting it. The live form is scaled into the one painted card. */
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) {
    --call-cw: max(100vw, calc(100dvh * 909 / 1731));
  }
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call {
    overflow-x: hidden !important;
    background: #b98158;
  }
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call .scene-canvas {
    position: relative;
    left: 50%;
    width: var(--call-cw) !important;
    height: auto !important;
    min-height: 0;
    aspect-ratio: 909 / 1731 !important;
    padding: 0;
    margin: 0;
    transform: translateX(-50%);
    overflow: visible;
    isolation: isolate;
  }
  body.simple.painted-chrome[data-scene="3"] .scene-call .scene-canvas picture {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    z-index: 0;
  }
  body.simple.painted-chrome[data-scene="3"] .scene-call .scene-canvas .photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  body.simple.painted-chrome[data-scene="3"] .scene-call .scene-canvas::after {
    content: none !important;
  }
  body.simple.painted-chrome[data-scene="3"] .laptop-screen {
    position: absolute;
    left: 13.97%;
    top: 12.48%;
    width: 72.6%;
    height: auto;
    margin: 0;
    transform: none;
    overflow: visible;
    background: #fdfaf5;
    z-index: 2;
  }
  body.simple.painted-chrome[data-scene="3"] .laptop-screen .bk-left,
  body.simple.painted-chrome[data-scene="3"] .laptop-screen .bk-right {
    zoom: 0.64;
  }

  /* Once confirmed, the supplied confirmation render is the sole visible card.
     Only transparent hit targets are layered over its two painted actions. */
  body.simple.painted-chrome[data-scene="3"]:has(.bk-confirm:not([hidden])) {
    --call-cw: max(100vw, calc(100dvh * 852 / 1846));
  }
  body.simple.painted-chrome[data-scene="3"] .scene-call:has(.bk-confirm:not([hidden])) .scene-canvas {
    aspect-ratio: 852 / 1846 !important;
  }
  body.simple.painted-chrome[data-scene="3"] .scene-call:has(.bk-confirm:not([hidden])) .laptop-screen {
    display: none;
  }
  .phone-call-confirm-actions {
    display: none;
    position: absolute;
    inset: 0;
    z-index: 4;
    pointer-events: none;
  }
  body.simple.painted-chrome[data-scene="3"] .scene-call:has(.bk-confirm:not([hidden])) .phone-call-confirm-actions {
    display: block;
  }
  .phone-call-confirm-actions button {
    position: absolute;
    display: block;
    padding: 0;
    border: 0;
    background: transparent;
    pointer-events: auto;
  }
  /* The painted actions are only as tall as the paint — the lower one is 22px.
     A pseudo element carries the 44px tap area so the target grows without the
     box moving off the artwork it is registered against. */
  .phone-call-confirm-actions button::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    height: max(100%, 44px);
  }
  .phone-call-confirm-actions button:first-child {
    left: 18.310%; top: 71.831%; width: 61.385%; height: 5.417%;
  }
  .phone-call-confirm-actions button:last-child {
    left: 24.178%; top: 89.166%; width: 48.709%; height: 2.654%;
  }

  /* Page 6's reminder and confirmation cards are already painted into their
     respective prototypes. Do not put a second live card or a repaint patch on
     top. The prototype's Review your booking strip is the live target. */
  body.simple.painted-chrome .scene-soon .farewell-panel {
    display: none !important;
  }
  body.simple.painted-chrome .scene-soon .scene-canvas::after {
    content: none !important;
  }
  body.simple.painted-chrome .scene-soon.is-booked #bookLessonBtn {
    --mx: 28.101% !important;
    --my: 75.896% !important;
    --mw: 44.379% !important;
    --mh: 5.103% !important;
    min-height: 44px;
    opacity: 1 !important;
    pointer-events: auto !important;
  }
}

/* ============================================================
   SHARED MOBILE ONBOARDING CHROME
   Page 1 is the single source of truth for the logo, controls and six-step
   rail. The portrait artwork on Pages 2–6 still contains an older painted
   header, so each plate is shifted behind this opaque live header until its
   content begins. The room itself keeps its native aspect ratio and is scaled
   only enough to cover the remaining viewport height.
   ============================================================ */
@media (max-width: 860px) {
  :root {
    --mobile-header-pad: 20px;
    --mobile-control: 44px;
    /* One geometry for the six-step rail, shared by every page. The step
       column is as wide as the largest dot and as tall as a dot plus its
       label, so the six dots land on the same coordinates whatever state
       they are in and the rail never changes height. */
    --rail-dot: 26px;
    --rail-label-h: 17.5px;
  }

  /* One header implementation at this breakpoint, on every step. */
  .site-header,
  body.painted-chrome .site-header,
  body.painted-chrome[data-scene] .site-header {
    position: fixed;
    inset: 0 0 auto 0;
    left: 0 !important;
    right: 0 !important;
    width: 100% !important;
    height: auto !important;
    aspect-ratio: auto !important;
    transform: none !important;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "brand email menu"
      "rail  rail  rail";
    align-items: center;
    column-gap: 8px;
    row-gap: 0;
    padding:
      max(8px, env(safe-area-inset-top))
      max(var(--mobile-header-pad), env(safe-area-inset-right))
      0
      max(var(--mobile-header-pad), env(safe-area-inset-left));
    background: var(--cream);
    box-shadow: inset 0 -1px 0 var(--m-line);
    pointer-events: auto;
    z-index: 60;
  }
  /* The band is fixed across the top of every page, so anything it covers is
     unreachable while it takes taps of its own — the first field of page 4's
     form sat under it. Only the controls need to be hit; the band does not. */
  .site-header,
  body.painted-chrome .site-header,
  body.painted-chrome[data-scene] .site-header { pointer-events: none; }
  .site-header > *,
  body.painted-chrome .site-header > * { pointer-events: auto; }

  /* On the artwork pages the header has no ground of its own. The plates no
     longer carry a painted header for it to hide, so the room runs to the top
     of the screen and the wordmark, the controls and the rail float on it —
     which is how the prototypes drew them. Page 1 is a cream page and keeps
     its bar. */
  body.painted-chrome .site-header,
  body.painted-chrome[data-scene] .site-header {
    background: none;
    box-shadow: none;
  }
  /* Floating ink over a photograph needs its own ground. A soft light halo
     does it without a panel and without a wash over the artwork. */
  body.painted-chrome .site-header .brand-name,
  body.painted-chrome .site-header .brand-sub,
  body.painted-chrome .site-header .step-label {
    text-shadow:
      0 0 2px rgba(255, 253, 248, 0.98),
      0 0 8px rgba(255, 252, 245, 0.96),
      0 1px 20px rgba(255, 250, 240, 0.86);
  }
  body.painted-chrome .site-header .step-dot {
    box-shadow: 0 2px 8px rgba(96, 72, 40, 0.16);
  }

  .site-header .header-left,
  body.painted-chrome .site-header .header-left {
    grid-area: brand;
    position: relative;
    left: auto;
    top: auto;
    min-width: 0;
  }
  .site-header .brand,
  body.painted-chrome .site-header .brand,
  body.painted-chrome.show-goback .site-header .brand {
    display: flex !important;
    visibility: visible !important;
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
  .site-header .brand-name,
  body.painted-chrome .site-header .brand-name {
    font-size: clamp(17px, 5.9vw, 25px);
    line-height: 1.15;
    white-space: nowrap;
  }
  .site-header .brand-sub,
  body.painted-chrome .site-header .brand-sub {
    font-size: clamp(7.5px, 2.4vw, 9px);
    letter-spacing: clamp(0.12em, 0.6vw, 0.22em);
    white-space: nowrap;
  }
  .site-header .goback-pill { display: none; }

  .site-header .header-email,
  .site-header .menu-btn,
  body.painted-chrome[data-scene] .site-header .header-email,
  body.painted-chrome[data-scene] .site-header .menu-btn {
    position: relative;
    left: auto;
    top: auto;
    width: var(--mobile-control);
    height: var(--mobile-control);
    min-width: var(--mobile-control);
    min-height: var(--mobile-control);
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 50%;
    align-self: center;
    overflow: visible;
    color: var(--purple-deep);
  }
  .site-header .header-email,
  body.painted-chrome[data-scene] .site-header .header-email {
    grid-area: email;
    display: grid;
    place-items: center;
    background: #fff !important;
    box-shadow: 0 2px 10px rgba(72, 52, 130, 0.13) !important;
    font-size: 0;
  }
  .site-header .menu-btn,
  body.painted-chrome[data-scene] .site-header .menu-btn {
    grid-area: menu;
    display: grid;
    place-items: center;
    background: var(--purple-soft) !important;
    box-shadow: 0 8px 20px rgba(124, 95, 196, 0.35) !important;
  }
  .site-header .header-email::after,
  .site-header .menu-btn::after,
  body.painted-chrome .site-header .header-email::after,
  body.painted-chrome .site-header .menu-btn::after { content: none; }
  .site-header .header-email > svg,
  body.painted-chrome .site-header .header-email > svg {
    visibility: visible;
    width: 19px;
    height: 19px;
  }
  .site-header .menu-btn > span,
  body.painted-chrome .site-header .menu-btn > span {
    visibility: visible;
    width: 18px;
    height: 2px;
    margin: 2.5px 0;
    background: #fff;
  }

  /* ---------- the six-step rail, one geometry for pages 1-6 ----------
     Every step is the same fixed-width, fixed-height column and the label is
     taken out of the flow, so the only thing that changes from page to page is
     which dot is active, done or still to come. Previously the steps were
     auto-width: a 26px dot on one page and a 10px dot with a wide label on the
     next, which moved every dot sideways at each step of the journey. */
  .site-header .stepper,
  body.painted-chrome[data-scene] .site-header .stepper {
    grid-area: rail;
    position: relative;
    inset: auto;
    display: flex;
    width: 100%;
    height: auto;
    min-height: 0;
    padding: 4px 0 7px;
    align-items: flex-start;
    overflow: visible;
    pointer-events: auto;
  }
  .site-header .stepper > .step,
  body.painted-chrome[data-scene] .site-header .stepper > .step {
    position: relative !important;
    inset: auto !important;
    left: auto !important;
    top: auto !important;
    flex: 0 0 var(--rail-dot);
    width: var(--rail-dot) !important;
    height: calc(var(--rail-dot) + var(--rail-label-h)) !important;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    align-self: flex-start;
    gap: 0;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none !important;
    box-shadow: none !important;
    color: inherit;
    overflow: visible;
    pointer-events: auto;
  }
  .site-header .stepper > .step::before,
  .site-header .stepper > .step::after,
  body.painted-chrome .site-header .stepper > .step::before,
  body.painted-chrome .site-header .stepper > .step::after { content: none !important; }
  .site-header .step-dot,
  body.painted-chrome .site-header .step-dot {
    visibility: visible;
    width: var(--rail-dot);
    height: var(--rail-dot);
    margin: 0;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: #e6dfd4;
    color: var(--ink-soft);
    font-size: 11px;
    font-weight: 600;
    box-shadow: none;
  }
  .site-header .step.is-active .step-dot,
  body.painted-chrome .site-header .step.is-active .step-dot {
    background: var(--purple-deep);
    color: #fff;
  }
  .site-header .step.is-done .step-dot,
  body.painted-chrome .site-header .step.is-done .step-dot {
    position: relative;
    background: var(--lavender-bg);
    color: transparent;
    font-size: 0;
  }
  /* The dot still holds its number. Laid out by the grid, the tick becomes a
     second row underneath it and sits low and right of the circle, which is
     what made the ticks look off centre. Take it out of the flow instead. */
  .site-header .step.is-done .step-dot::after,
  body.painted-chrome .site-header .step.is-done .step-dot::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 11px;
    height: 6px;
    margin: 0;
    border: 2px solid var(--purple);
    border-top: 0;
    border-right: 0;
    /* -70% rather than -50%: a tick's ink sits below its own box centre once
       rotated, so the optical centre needs the nudge. The last 0.75px is what
       the render still measured off centre at 26px. */
    transform: translate(-50%, calc(-70% - 0.75px)) rotate(-45deg);
  }
  /* A step still to come is a small dot, centred in the same column box so it
     shares its neighbours' centre line rather than shifting them. */
  .site-header .step:not(.is-active):not(.is-done) .step-dot,
  body.painted-chrome .site-header .step:not(.is-active):not(.is-done) .step-dot {
    width: 10px;
    height: 10px;
    margin: calc((var(--rail-dot) - 10px) / 2) 0;
    background: #ded7cc;
    color: transparent;
    font-size: 0;
  }
  /* Only the current step is labelled, and the label is positioned rather than
     laid out: a long one ("Success Stories") must not widen its column. */
  .site-header .step-label,
  body.painted-chrome .site-header .step-label {
    visibility: visible;
    display: none;
    position: absolute;
    top: calc(var(--rail-dot) + 6px);
    left: 50%;
    transform: translateX(-50%);
    margin: 0;
    color: var(--purple-deep);
    font-size: 10px;
    line-height: 1.15;
    white-space: nowrap;
  }
  .site-header .step.is-active .step-label,
  body.painted-chrome .site-header .step.is-active .step-label { display: block; }
  /* The outer two labels are wider than their column, so they hang off the
     rail's own edges instead of off the screen. */
  .site-header .stepper > .step:first-of-type .step-label,
  body.painted-chrome .site-header .stepper > .step:first-of-type .step-label {
    left: 0;
    transform: none;
  }
  .site-header .stepper > .step:last-of-type .step-label,
  body.painted-chrome .site-header .stepper > .step:last-of-type .step-label {
    left: auto;
    right: 0;
    transform: none;
  }
  .site-header .step-line,
  body.painted-chrome .site-header .step-line {
    visibility: visible;
    position: relative;
    flex: 1 1 auto;
    width: auto;
    height: 1px;
    margin: calc((var(--rail-dot) - 1px) / 2) 0 0;
    border: 0;
    background: var(--m-line);
  }

  /* Each plate is whole and starts at the top of the screen. The width is
     whichever is larger: the screen, or what it takes for the plate's own
     ratio to reach the full height — so the artwork always covers, and the
     percentages every hotspot is measured in still address the whole picture.
     Nothing is cropped off the top any more; there is no painted header left
     up there to hide. */
  body.simple.painted-chrome { --plate-top: 0px; }
  body.simple.painted-chrome[data-scene="1"] {
    --plate-cw: max(100vw, calc(100dvh * 0.461289));
  }
  body.simple.painted-chrome[data-scene="2"][data-level="gcse"] {
    --plate-cw: max(100vw, calc(100dvh * 0.462581));
  }
  body.simple.painted-chrome[data-scene="2"][data-level="alevel"] {
    --plate-cw: max(100vw, calc(100dvh * 0.460747));
  }
  body.simple.painted-chrome[data-scene="3"] {
    --plate-cw: max(100vw, calc(100dvh * 0.525130));
  }
  body.simple.painted-chrome[data-scene="3"]:has(.bk-confirm:not([hidden])) {
    --plate-cw: max(100vw, calc(100dvh * 0.461538));
  }
  body.simple.painted-chrome[data-scene="4"] {
    --plate-cw: max(100vw, calc(100dvh * 0.520713));
  }
  body.simple.painted-chrome[data-scene="5"] {
    --plate-cw: max(100vw, calc(100dvh * 0.519540));
  }
  body.simple.painted-chrome[data-scene="5"].booked {
    --plate-cw: max(100vw, calc(100dvh * 0.463626));
  }

  body.simple.painted-chrome .scene.is-current {
    padding-top: 0;
    /* The plate covers the viewport by construction now, so the 8px the older
       layout reserved at the foot is dead space — and dead space here is a
       sliver of cream under the artwork the moment the page is over-scrolled. */
    padding-bottom: env(safe-area-inset-bottom);
    overflow-x: hidden !important;
    background: var(--cream);
  }
  body.simple.painted-chrome .scene.is-current .scene-canvas,
  body.simple.painted-chrome[data-scene="3"] .scene-call .scene-canvas,
  body.simple.painted-chrome[data-scene="4"] .scene-stories .scene-canvas,
  body.simple.painted-chrome[data-scene="5"] .scene-soon .scene-canvas,
  body.simple.painted-chrome[data-scene="5"]:not(.booked) .scene-soon .scene-canvas {
    position: relative;
    left: 50%;
    top: auto;
    width: var(--plate-cw) !important;
    height: auto !important;
    max-width: none;
    margin: var(--plate-top) 0 0;
    transform: translateX(-50%);
    overflow: visible;
  }
  body.simple.painted-chrome[data-scene="1"] .scene-year .scene-canvas { aspect-ratio: 852 / 1847 !important; }
  body.simple.painted-chrome[data-scene="2"][data-level="gcse"] .scene-subject .scene-canvas { aspect-ratio: 853 / 1844 !important; }
  body.simple.painted-chrome[data-scene="2"][data-level="alevel"] .scene-subject .scene-canvas { aspect-ratio: 851 / 1847 !important; }
  body.simple.painted-chrome[data-scene="3"] .scene-call .scene-canvas { aspect-ratio: 909 / 1731 !important; }
  body.simple.painted-chrome[data-scene="3"] .scene-call:has(.bk-confirm:not([hidden])) .scene-canvas { aspect-ratio: 852 / 1846 !important; }
  body.simple.painted-chrome[data-scene="4"] .scene-stories .scene-canvas { aspect-ratio: 905 / 1738 !important; }
  body.simple.painted-chrome[data-scene="5"] .scene-soon .scene-canvas { aspect-ratio: 904 / 1740 !important; }
  body.simple.painted-chrome[data-scene="5"].booked .scene-soon .scene-canvas { aspect-ratio: 854 / 1842 !important; }

  /* These controls are siblings of the portrait canvas. Give them the same
     cropped coordinate box so their labels and tap targets move with the art
     and do not create a second, invisible full-height scroll area. */
  body.simple.painted-chrome .scene-year .flow-bar,
  body.simple.painted-chrome .scene-subject .flow-bar {
    left: 50%;
    top: var(--plate-top);
    width: var(--plate-cw);
    height: calc(var(--plate-cw) * 1847 / 852);
    transform: translateX(-50%);
  }
  body.simple.painted-chrome[data-scene="2"][data-level="gcse"] .scene-subject .flow-bar {
    height: calc(var(--plate-cw) * 1844 / 853);
  }
  body.simple.painted-chrome[data-scene="2"][data-level="alevel"] .scene-subject .flow-bar {
    height: calc(var(--plate-cw) * 1847 / 851);
  }

  body.simple.painted-chrome .scene.is-current .scene-canvas picture,
  body.simple.painted-chrome .scene.is-current .scene-canvas .photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }
  body.simple.painted-chrome .scene.is-current .scene-canvas .photo { object-fit: fill; }

  /* Page 2 uses one outline treatment for every painted year sign. */
  body.simple.painted-chrome .scene-year .hotspot {
    border-radius: 18px;
  }
  body.simple.painted-chrome .scene-year .hotspot.is-selected::after {
    inset: -4px;
    border: 3px solid rgba(95, 67, 174, 0.92);
    border-radius: 22px;
    box-shadow: 0 0 18px rgba(95, 67, 174, 0.42);
  }

  /* Page 3: the live control covers the painted disabled button. Its state is
     now genuinely driven by the subject selection class. */
  body.simple.painted-chrome .scene-subject .scene-cue,
  body.simple.painted-chrome .scene-subject[data-level="alevel"] .scene-cue {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    /* No 44px floor. The painted button is 38.9px tall here, and a taller pill
       has a wider cap: forced to 44 its rounded ends no longer coincide with
       the paint's and the painted pill shows around it as a pale rim. The tap
       area is grown by `.scene-cue::after` instead, which does not resize the
       pill itself. */
    min-height: 0;
    /* And this one is not a pill. Page 2's painted Continue is a full pill and
       the live control matches it, but page 3's prototype draws a rounded
       rectangle — a 24px corner on an 853px plate, where a pill's would be 43.
       A pill's cap is twice as deep, so the painted button showed around the
       live one at both ends. Expressed against the plate so it holds at every
       screen width. */
    border-radius: calc(var(--plate-cw, 100vw) * 0.02814) !important;
    background: rgba(250, 246, 238, 0.97) !important;
    color: var(--purple-soft) !important;
    font-size: clamp(14px, 4vw, 17px) !important;
    font-weight: 600;
    box-shadow: 0 10px 24px rgba(72, 52, 130, 0.16) !important;
  }
  body.simple.painted-chrome .scene-subject .scene-cue.is-ready,
  body.simple.painted-chrome .scene-subject[data-level="alevel"] .scene-cue.is-ready {
    background: var(--purple) !important;
    color: #fff !important;
    box-shadow: 0 14px 30px rgba(95, 67, 174, 0.38) !important;
  }
  body.simple.painted-chrome .scene-subject .scene-cue svg { display: none; }
  body.simple.painted-chrome .scene-subject .scene-cue .cue-go,
  body.simple.painted-chrome .scene-subject .scene-cue.is-ready .cue-go { display: inline; }

  /* ---------- the header tucks away while you scroll ----------
     Everything but the menu button fades and lifts a little, so the room, the
     cards and the form below can be read without a wordmark and a step rail
     standing over them. Coming back to the top brings it back.

     Height is deliberately untouched: `--top-h` is measured off this element
     and every page is laid out below it, so anything that collapsed the header
     would pull the whole page up with it. Opacity and transform move nothing.

     Page 1 is excluded in main.js and never gets the class. */
  .site-header .header-left,
  .site-header .header-email,
  .site-header .stepper {
    transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0s;
  }
  body.header-tucked .site-header .header-left,
  body.header-tucked .site-header .header-email,
  body.header-tucked .site-header .stepper {
    opacity: 0;
    transform: translateY(-10px);
    /* out of the way for a thumb as well as for the eye, and out of the
       reading order once it has finished fading */
    pointer-events: none;
    visibility: hidden;
    transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0.3s;
  }
  /* The menu button is the one thing that stays. */
  body.header-tucked .site-header .menu-btn {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }

  .site-header .step:focus { outline: none; }
  .site-header .step:focus-visible .step-dot {
    outline: 2px solid var(--purple-soft);
    outline-offset: 3px;
  }

  /* ---------- page 4: the booking form ----------
     The plate for this page is a render of the form itself, so the live card
     used to be pinned to the painted one and zoomed to 64% to fit it: 10px
     type, 44px targets only because they were 69px before the zoom, and a card
     still taller than the artwork. What hung below the plate was the flat band
     of colour under the page.

     The room is a layer of its own now, pinned to the viewport so it covers
     however tall the form grows, and the card is ordinary page content
     standing on it at full size. The painted card sits directly behind the
     live one, wider than it on both sides, and is never seen. Every rule here
     is scoped away from :has(.bk-confirm), so the confirmation state keeps the
     supplied artwork and its two painted actions exactly as they are. */
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call {
    display: block;
    overflow-y: auto !important;
    padding: var(--top-h) 0 calc(30px + env(safe-area-inset-bottom));
    background: none;
    isolation: isolate;
  }
  /* `will-change: transform` on .kb is for the laptop's camera move. Left on,
     it becomes the containing block for the pinned room below and drops it by
     the scene's own top padding, uncovering the plate's obsolete header. */
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call .kb,
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call .par {
    display: block;
    position: static;
    height: auto;
    padding: 0;
    margin: 0;
    will-change: auto;
    transform: none;
    filter: none;
  }
  /* The canvas stops being a coordinate box — nothing on this page is placed
     against the artwork any more, so it collapses to its content. */
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call .scene-canvas {
    position: static;
    left: auto;
    top: auto;
    width: auto !important;
    height: auto !important;
    max-width: none;
    margin: 0 !important;
    padding: 0;
    transform: none;
    aspect-ratio: auto !important;
    overflow: visible;
  }
  /* The room, pinned. Its own asset — assets/mobile/page-4-room.jpg — is the
     prototype's photograph with the painted card taken out and the chrome band
     cropped off, so there is nothing left in it that has to line up with
     anything. That frees it to be an ordinary cover background: it fills the
     viewport at every size and cannot run out underneath a form that scrolls.
     The plate itself is still what the confirmation state shows. */
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call .scene-canvas picture {
    position: fixed;
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
  }
  @supports (height: 100dvh) {
    body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call .scene-canvas picture {
      height: 100dvh;
    }
  }
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .scene-call .scene-canvas .photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
  }
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .laptop-screen {
    position: relative;
    left: auto;
    top: auto;
    /* Sized for the form now, not for the shape painted behind it, with
       enough of the room left either side for the card to read as standing
       on the desk. */
    width: min(420px, calc(100vw - 36px));
    max-width: none;
    height: auto;
    max-height: none;
    margin: 8px auto 0;
    padding: 0;
    border-radius: 22px;
    background: #fdfaf5;
    box-shadow: 0 18px 44px rgba(72, 52, 130, 0.24);
    overflow: visible;
    transform: none;
    z-index: 2;
  }
  body.simple.painted-chrome[data-scene="3"] .laptop-screen .bk {
    height: auto;
    grid-template-columns: 1fr;
    font-size: 15px;
  }
  /* The zoom goes with the pinning it existed to serve. */
  body.simple.painted-chrome[data-scene="3"] .laptop-screen .bk-left,
  body.simple.painted-chrome[data-scene="3"] .laptop-screen .bk-right {
    zoom: normal;
    min-height: 0;
  }
  body.simple.painted-chrome[data-scene="3"] .bk-col { padding: 15px 16px; }
  body.simple.painted-chrome[data-scene="3"] .bk-left {
    border-right: 0;
    border-bottom: 1px solid rgba(38, 36, 46, 0.1);
  }

  /* One set of real sizes: 16px inputs so iOS does not zoom on focus, 46px
     minimum on anything you tap, and a month that reads as a month without
     taking half the screen. */
  body.simple.painted-chrome[data-scene="3"] .bk-step { font-size: 16.5px; margin-bottom: 7px; }
  body.simple.painted-chrome[data-scene="3"] .bk-step-time { margin-top: 13px; }
  body.simple.painted-chrome[data-scene="3"] .bk-sub { font-size: 13px; margin-bottom: 10px; }
  body.simple.painted-chrome[data-scene="3"] .cal-head { margin-bottom: 4px; }
  body.simple.painted-chrome[data-scene="3"] .cal-head strong { font-size: 15px; }
  body.simple.painted-chrome[data-scene="3"] #calPrev,
  body.simple.painted-chrome[data-scene="3"] #calNext {
    width: 44px;
    height: 44px;
    min-width: 44px;
    min-height: 44px;
    font-size: 16px;
  }
  body.simple.painted-chrome[data-scene="3"] .cal-grid { gap: 1px; }
  body.simple.painted-chrome[data-scene="3"] .cal-dow { font-size: 10px; padding: 2px 0; }
  body.simple.painted-chrome[data-scene="3"] .cal-day {
    font-size: 13.5px;
    padding: 0;
    min-height: 33px;
  }
  body.simple.painted-chrome[data-scene="3"] .bk-selectwrap > svg,
  body.simple.painted-chrome[data-scene="3"] .bk-field > svg { left: 13px; width: 17px; height: 17px; }
  body.simple.painted-chrome[data-scene="3"] .bk-selectwrap select {
    font-size: 16px;
    min-height: 46px;
    padding: 11px 32px 11px 38px;
    border-width: 2px;
    border-radius: 12px;
  }
  body.simple.painted-chrome[data-scene="3"] .bk-note { font-size: 12px; margin-top: 5px; }
  body.simple.painted-chrome[data-scene="3"] .bk-field { margin-bottom: 9px; }
  body.simple.painted-chrome[data-scene="3"] .bk-field input {
    font-size: 16px;
    min-height: 46px;
    padding: 11px 13px 11px 38px;
    border-width: 2px;
    border-radius: 12px;
  }
  body.simple.painted-chrome[data-scene="3"] .bk-contact { margin-bottom: 9px; }
  body.simple.painted-chrome[data-scene="3"] .bk-contact legend { font-size: 13.5px; margin-bottom: 6px; }
  body.simple.painted-chrome[data-scene="3"] .bk-choices { gap: 0 9px; }
  body.simple.painted-chrome[data-scene="3"] .bk-radio {
    font-size: 15px;
    min-height: 46px;
    padding: 10px 11px;
    gap: 8px;
    border-width: 2px;
    border-radius: 12px;
  }
  body.simple.painted-chrome[data-scene="3"] .bk-radio input { width: 18px; height: 18px; }
  body.simple.painted-chrome[data-scene="3"] .bk-hint { font-size: 12px; margin-bottom: 10px; }
  body.simple.painted-chrome[data-scene="3"] .bk-submit {
    font-size: 16px;
    min-height: 50px;
    margin-top: 2px;
    padding: 13px 0;
    border-radius: 14px;
  }
  body.simple.painted-chrome[data-scene="3"] .bk-safe { font-size: 11.5px; margin-top: 8px; }
  body.simple.painted-chrome[data-scene="3"] .bk-alt { margin-top: 9px; font-size: 13px; }
  body.simple.painted-chrome[data-scene="3"] .bk-altlink { font-size: 14px; min-height: 44px; }
}

/* Page 4 on a tablet: the width is there for the two columns the laptop has
   always used, so the date and the details sit side by side and the card stops
   being a long scroll. */
@media (min-width: 600px) and (max-width: 860px) {
  body.simple.painted-chrome[data-scene="3"]:not(:has(.bk-confirm:not([hidden]))) .laptop-screen {
    width: min(660px, calc(100vw - 96px));
    margin-top: 22px;
  }
  body.simple.painted-chrome[data-scene="3"] .laptop-screen .bk {
    grid-template-columns: 1fr 1fr;
  }
  body.simple.painted-chrome[data-scene="3"] .bk-col { padding: 20px 20px; }
  body.simple.painted-chrome[data-scene="3"] .bk-left {
    border-right: 1px solid rgba(38, 36, 46, 0.09);
    border-bottom: 0;
  }
  body.simple.painted-chrome[data-scene="3"] .cal-day { min-height: 38px; font-size: 14.5px; }
}

/* A reduced-motion preference still wants the header out of the way while
   scrolling — it just does not want to watch it travel. */
@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
  .site-header .header-left,
  .site-header .header-email,
  .site-header .stepper,
  body.header-tucked .site-header .header-left,
  body.header-tucked .site-header .header-email,
  body.header-tucked .site-header .stepper {
    transition: none;
    transform: none;
  }
}

/* ============================================================
   PHONE — THE BOOKING'S OWN VALUES, ON THE PAINTED CARD
   Pages 4 and 6 show the prototype's confirmation artwork, re-rendered with
   its data rows drawn empty. The card, its tick, the sparkles, the rules, the
   hearts and both buttons are the picture and nothing here touches them; the
   booking is the only live thing on either plate.

   One coordinate system: the plate's own. Every position and every type size
   below is a fraction of the plate's width — which --plate-cw (page 4) and
   --cw (page 6) already carry — so the text scales with the artwork and holds
   its place at any width, instead of needing a rule per handset.

   Positions were measured off the cleaned renders: page 4's values are
   right-aligned to x=620 of 852, the axis its painted divider rules (165-662)
   are drawn about, and each sits on its own painted label's row. Page 6's two
   lines are centred in the band the plate leaves between the gold rule and the
   hairline, y 1110-1257 of 1842.
   ============================================================ */
.plate-data { display: none; }

@media (max-width: 860px) {
  .plate-data {
    position: absolute;
    inset: 0;
    z-index: 3;
    pointer-events: none;      /* the painted buttons keep their own targets */
    font-family: var(--sans);
  }
  body.simple.painted-chrome[data-scene="3"] .scene-call:has(.bk-confirm:not([hidden])) .plate-data-call,
  body.simple.painted-chrome[data-scene="5"].booked .plate-data-soon {
    display: block;
  }
  .plate-data .pd {
    position: absolute;
    display: block;
    line-height: 1.5;
  }

  /* ---------- page 4 ---------- */
  .plate-data-call {
    --pw: var(--plate-cw, 100vw);
    color: #161c28;
    font-weight: 600;
    font-size: calc(var(--pw) * 0.0340);
  }
  .plate-data-call .pd { right: 27.230%; text-align: right; }
  /* Every value row is bounded on BOTH sides: right at x=620, left just clear
     of its own painted label. Without a left bound a long value grows leftwards
     over the label and then wraps down into the row beneath — which a 40-
     character email address does. These rows hold one line and are fitted to
     the width by fitPlateRows(); the ellipsis is only a last resort under it. */
  .plate-data-call .pd-session,
  .plate-data-call .pd-level,
  .plate-data-call .pd-contact,
  .plate-data-call .pd-email,
  .plate-data-call .pd-whats {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .plate-data-call .pd-session { top: 44.529%; left: 38.028%; }
  .plate-data-call .pd-level   { top: 47.779%; left: 34.977%; }
  .plate-data-call .pd-subject { top: 51.463%; left: 36.033%; }
  .plate-data-call .pd-contact { top: 57.367%; left: 38.967%; }
  .plate-data-call .pd-email   { top: 60.943%; left: 34.977%; }
  .plate-data-call .pd-whats   { top: 64.518%; left: 42.958%; }
  /* set by fitPlateRows() when a row will not fit on one line even at the
     smallest step it is allowed */
  .plate-data-call .pd.is-wrapped {
    white-space: normal;
    overflow-wrap: anywhere;
    line-height: 1.25;
  }
  /* The date and the time each stand beside their own painted icon, in the
     slot that icon leaves. This render sets its clock at x=510 of 852, well
     left of where the render before it did, so the date has 293px to work in:
     enough for the longest date the site can produce ("Wed 28 September 2026")
     at this size, and no more. Both are held on one line — a wrap here would
     push into the rule below. */
  .plate-data-call .pd-date,
  .plate-data-call .pd-time {
    right: auto;
    top: 38.727%;
    text-align: left;
    white-space: nowrap;
    font-size: calc(var(--pw) * 0.0270);
  }
  .plate-data-call .pd-date { left: 24.296%; width: 34.390%; }
  .plate-data-call .pd-time { left: 64.554%; width: 13.146%; }
  /* The plate leaves two lines for the subject and 109px of room before the
     row beneath. A longer list steps down a size rather than running into it —
     seven subjects still set inside the gap at the smallest step. */
  .plate-data-call .pd-subject.is-long  { font-size: calc(var(--pw) * 0.0293); }
  .plate-data-call .pd-subject.is-xlong { font-size: calc(var(--pw) * 0.0258); }

  /* ---------- page 6 ---------- */
  .plate-data-soon {
    --pw: var(--cw, 100vw);
    color: #2f2d36;
    font-weight: 500;
    font-size: calc(var(--pw) * 0.0281);
  }
  /* Centred in the plate's empty band, so one line, two or three all sit
     correctly without any of the artwork moving. */
  .plate-data-soon .pd-block {
    position: absolute;
    left: 27.518%;
    top: 60.261%;
    width: 44.965%;
    height: 7.980%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    line-height: 1.55;
  }
  .plate-data-soon .pd-block.is-long { font-size: calc(var(--pw) * 0.0252); }
}
