/* FROZEN on 4 September 2026, when the home page's hero demo was replaced
   by the film-and-app demo. The 35 course landing pages keep the demo they
   had (the course's own lesson and quiz on the photographed screens), so
   the stylesheet and script they used to lift out of index.html live here
   now, unchanged from that day's index.html. Edit these to change the
   course pages' hero; edit index.html to change the home page's. */

/* ==========================================================================
   HERO CONCEPT: the desk scene.

   The photo ships with the laptop screen painted dark. The live app sits on
   top of it, mapped onto the screen's four corners with a homography, so the
   app leans with the laptop instead of floating flat on the picture. The
   corner percentages below were measured from the photo, not eyeballed.

   Everything inside the screen is real DOM. The quiz at the end of the little
   performance is genuinely clickable, which is the whole point: the visitor
   answers a real question inside a photograph of a laptop.
   ========================================================================== */

:root {
  --scene-ar: 1.7686;          /* 2400 / 1357, the desk photo */
  /* Nothing reads this any more. The hand-and-phone photograph now ships in
     two crops, upright and wide, and the script takes the ratio from whichever
     one the browser loaded rather than from a constant that can only describe
     one of them. Kept only as a note of where the numbers came from:
     1200 / 2122 upright, 3772 / 2122 wide. */
  /* Design size of the app inside the screen. The screen is about 640 CSS
     pixels wide on a 1600 pixel window, so designing at 640 keeps the
     transform near 1:1 there and the type honest either side of it. Must stay
     in step with SW and SH in the script, and with the screen's own 1.488
     aspect ratio. */
  --screen-w: 640px;
  --screen-h: 430px;
}

/* The hero stays put while the page slides over it.

   It is sticky rather than fixed so it takes part in normal layout, and the
   band that follows carries its own background and a higher stacking order,
   so it rides over the top like a card being drawn across a table. */
.scene {
  position: sticky; top: 0; z-index: 0;
  overflow: hidden;
  background: #1b1409;
  height: calc(100svh - 65px);
  min-height: 540px;
}
/* A real box on desktop, so the whole hero can be moved as one thing when the
   page scrolls over it. */
.hero-screen { position: absolute; inset: 0; overflow: hidden; }

/* The hero recedes as the page covers it.

   Sticky on its own read as a bug: the hero simply stopped while everything
   slid past, with no sign that was deliberate. Now it drifts back and dims as
   the sheet arrives, so it reads as one surface passing over another. --hero-p
   runs 0 to 1 across the first screen and is written by the script. */
@media (min-width: 901px) {
  .hero-screen, .scene-copy, .scene-hint {
    transform: translateY(calc(var(--hero-p, 0) * -26px)) scale(calc(1 - var(--hero-p, 0) * 0.045));
    transform-origin: 50% 34%;
    opacity: calc(1 - var(--hero-p, 0) * 0.72);
  }
  /* The sheet casts a shadow onto the hero it is covering. */
  .after-hero { box-shadow: 0 -20px 46px rgba(6, 12, 24, .30); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-screen, .scene-copy, .scene-hint { transform: none; opacity: 1; }
}
/* Everything after the hero scrolls over it, on one opaque full width sheet.

   Per-section backgrounds were not enough. A .wrap section is capped at 1080px
   and centred, so on a wide screen the hero showed through the margins either
   side of it. This sheet has no margins. */
.after-hero { position: relative; z-index: 1; background: var(--paper); }
@media (prefers-reduced-motion: reduce) { .scene { position: relative; } }

/* Cover the section without object-fit, so the overlay shares the photo's
   coordinate space exactly. aspect-ratio does the covering, because deriving
   width and height separately let a scrollbar skew one and not the other,
   which stretched the photo by half a percent and slid the overlay off the
   bezel. */
/* The photo now carries its own room on the left, so it simply covers the
   section. The earlier version was nudged sideways to get the laptop clear of
   the words, which left a bar of bare background down the left edge. */
/* Anchored to the right and zoomed.

   The wide photograph put the laptop at a quarter of the frame, which is
   correct for the room and far too small for the app: the screen came out at
   415 pixels and the lesson text with it. Scaling to 155% and pinning the
   right edge brings the laptop back to a readable size while the extra room
   the photo gained runs off the left, so the picture still fills the section
   edge to edge with no bar down the side. */
/* Sat a little lower than centre, so the top of the laptop screen clears the
   header bar instead of running into it. */
.stage {
  position: absolute; top: 50%; right: 0; left: auto;
  transform: translateY(calc(-50% + clamp(14px, 3.2vh, 42px)));
  width: max(155%, calc((100svh - 65px) * var(--scene-ar)));
  aspect-ratio: var(--scene-ar);
}
.stage img.desk { width: 100%; height: 100%; display: block; }
.stage-phone { display: none; }

/* Warm scrim so the headline has something to sit on. Stops before the
   laptop starts (the screen's left edge is at 48% of the photo). */
/* The shade holds until the laptop starts, then lets go.

   Its stops are driven by --laptop-x, the real measured left edge of the
   photographed screen, so the dark part always covers exactly the width the
   words occupy. Fixed percentages could not: the photo is cropped to fill the
   window, so the laptop sits somewhere different at every size, and the fade
   kept landing in the middle of a sentence.

   90deg, not a diagonal, because then the stops can be stated in pixels and
   land where they say they do. */
.scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(90deg,
    rgba(16,28,48,.86) 0%,
    rgba(16,28,48,.84) calc(var(--laptop-x, 45%) - 100px),
    rgba(16,28,48,.60) calc(var(--laptop-x, 45%) - 20px),
    rgba(16,28,48,.22) calc(var(--laptop-x, 45%) + 70px),
    rgba(16,28,48,0) calc(var(--laptop-x, 45%) + 190px));
}

/* Centred in the space between the left edge and the laptop, at every size.
   --laptop-x is the measured left edge of the photographed screen, so the
   column re-centres itself whenever the window changes rather than sitting at
   a fixed inset that only looks right on one monitor. */
.scene-copy {
  position: absolute; z-index: 3;
  left: 0; padding: 0 clamp(16px, 2.2vw, 40px);
  /* Centred both ways with flexbox, not a translate: the transform property is
     spoken for by the scroll effect. */
  top: 0; bottom: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  /* The column IS the space between the left edge and the laptop.

     --laptop-x is written by the script on every resize: it is the real left
     edge of the photographed screen, in this section's own pixels. Percentages
     could not do this, because the photo is cropped to cover the window and
     the laptop therefore sits at a different place at every window size. */
  width: var(--laptop-x, 45%);
  color: #fdfaf3;
}
/* Each block is centred as a unit while its own text stays left aligned, so
   the column has equal air either side and one clean left edge. */
.scene-copy > * { width: 100%; max-width: 33em; }
/* The headline carries the page, so it is sized off the window's height as
   well as its width: it grows on a big monitor and still fits a short laptop
   screen without pushing the offer below the fold. */
/* Sized to fill the column it has, rather than sitting in the middle of it.
   The hero had a lot of empty space on the left; the type now grows into it. */
.scene-copy h1 {
  font-size: clamp(2.5rem, min(5vw, 8.4vh), 5.1rem);
  line-height: 1.02; margin: 0; letter-spacing: -.025em;
}
.scene-copy h1 em { color: #ffa585; font-style: italic; }
.scene-copy h1 { text-shadow: 0 2px 20px rgba(6,10,18,.55); }
/* Brighter, and carrying its own shadow. Body-sized type over a photograph
   needs both: the shade handles the background, the shadow handles the edge
   of each letter. */
.scene-copy .lede {
  color: #f6f1e6; max-width: 34em; margin: clamp(14px, 2.4vh, 26px) 0 0;
  font-size: clamp(1rem, min(1.32vw, 2.5vh), 1.35rem); line-height: 1.55;
  text-shadow: 0 1px 10px rgba(6,10,18,.8), 0 0 2px rgba(6,10,18,.55);
}
/* The one shouted phrase on the page, and it is shouted because that is
   literally what the quiz does to your attention. */
.scene-copy .shout {
  color: #ffcf8f; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  white-space: nowrap;
}
.scene-copy .standout {
  color: #fff0e0; font-weight: 600;
  border-left: 3px solid var(--coral); padding-left: 13px;
}
.scene-copy .standout a { color: #ffb489; font-weight: 800; text-decoration: none; border-bottom: 2px solid rgba(255,180,137,.5); }
.scene-copy .standout a:hover { border-bottom-color: #ffb489; }

/* Three separate moves, set as three lines.

   As one paragraph the middle clause did the work of all three and the last one
   was rarely reached. Ticks rather than bullets because each line is a thing the
   product already does.

   The mark is a pseudo element over a padded left edge, not a list marker, so a
   line that wraps stays lined up under its own first word instead of running
   back underneath the tick. */
.scene-copy .hero-checks { list-style: none; padding: 0; }
.scene-copy .hero-checks li { position: relative; padding-left: 1.55em; }
.scene-copy .hero-checks li + li { margin-top: .5em; }
.scene-copy .hero-checks li::before {
  content: "\2713"; position: absolute; left: 0; top: 0;
  color: #ff9d70; font-weight: 800;
  /* Same shadow the surrounding type carries, or the tick floats loose over a
     bright patch of the photograph. */
  text-shadow: 0 1px 10px rgba(6,10,18,.8), 0 0 2px rgba(6,10,18,.55);
}

.scene-copy .cta-row { margin-top: clamp(13px, 2.4vh, 26px); display: flex; gap: 10px; flex-wrap: wrap; }

/* Desktop only: a smaller headline and more air between the blocks.

   The column was crowded. Four things stack in it (headline, the three checks,
   the Genie line, the buttons) and they were separated by gaps tuned when there
   were fewer. Every value stays a clamp with a vh term in the middle, so
   a short window still tightens everything rather than pushing the buttons off
   the bottom, which is the failure this spacing has to keep avoiding.

   Scoped to the wide layout on purpose: on a phone the headline and buttons
   move into .hero-top and are budgeted against the photograph by the script,
   so loosening them here would eat the space the demo is measured into. */
@media (min-width: 901px) {
  .scene-copy h1 { font-size: clamp(2.3rem, min(4.4vw, 7.5vh), 4.5rem); }
  .scene-copy .lede { margin-top: clamp(18px, 3.2vh, 34px); }
  .scene-copy .cta-row { margin-top: clamp(18px, 3.2vh, 34px); }
}
/* Seats left, under each Join button.

   "First 300 testers" is a claim; a number that is going down is scarcity. It
   is filled in by script and starts hidden, so a slow network or a database
   hiccup shows nothing at all rather than a zero or a flash of the wrong
   number. The hero copy sits over a photograph and the pricing card sits on
   cream, so the two need different colours. */
.seats-left {
  flex: 0 0 100%;
  margin: 12px 0 0;
  font-size: .95rem; font-weight: 700; letter-spacing: .01em;
}
/* Both scopes, because the buttons live in two different places.

   On a phone the script moves the headline and the whole cta-row out of
   .scene-copy and into .hero-top so they can sit over the photograph. This
   rule was scoped to .scene-copy only, so the moment the line moved it lost
   its colour and fell back to the inherited navy ink, which put navy text on
   the navy scrim over the phone. It was rendered, on screen, and completely
   unreadable. */
.scene-copy .seats-left,
.hero-top .seats-left {
  color: #ffcf74;
  text-shadow: 0 1px 10px rgba(6,10,18,.85), 0 0 2px rgba(6,10,18,.7);
}
.plan .seats-left { color: var(--gold-text, #8a6a1a); margin-top: 10px; }
.seats-left.low { color: #ff9d70; }
.plan .seats-left.low { color: #b0401c; }

/* Not a transparent outline. Over a photograph an outline button disappears
   into whatever is behind it, and this one was sitting on a bright notebook. */
.scene-copy .btn.ghost {
  border-color: rgba(253,250,243,.85); color: #fdfaf3;
  background: rgba(10,15,26,.62); backdrop-filter: blur(6px);
  box-shadow: 0 6px 20px rgba(0,0,0,.3);
}
.scene-copy .btn.ghost:hover { border-color: #fdfaf3; background: rgba(10,15,26,.78); }
.scene-copy .micro { color: #e6ddcd; }

/* The one thing every visitor should be able to find without looking. */
.join-btn { color: #fff !important; font-weight: 800 !important; letter-spacing: .01em; }
/* The header's Join button says the whole promise everywhere it fits, and a
   short version on a phone, where it shares the bar with Sign in. Swapped by
   the rule in the 720px block below rather than by script, so it is right in
   the markup the first time it paints. */
.nav .j-short { display: none; }

/* The nudge under the laptop, telling people the thing is alive. */
.scene-hint {
  position: absolute; z-index: 3; right: clamp(16px, 3vw, 48px); bottom: clamp(12px, 3vh, 30px);
  color: #e6ddcd; font-size: .78rem; letter-spacing: .06em; text-transform: uppercase;
  display: flex; align-items: center; gap: 10px;
  text-shadow: 0 1px 6px rgba(0,0,0,.7);
}
.scene-hint button {
  font: inherit; letter-spacing: .06em; text-transform: uppercase;
  background: rgba(253,250,243,.12); color: #fdfaf3; border: 1px solid rgba(253,250,243,.45);
  border-radius: 999px; padding: 5px 13px; cursor: pointer;
}
.scene-hint button:hover { background: rgba(253,250,243,.24); }

/* ---------- the screen ---------- */
.screen-wrap {
  position: absolute; left: 0; top: 0; z-index: 2;   /* above the shade */
  width: var(--screen-w); height: var(--screen-h);
  transform-origin: 0 0;
  /* set by script; hidden until then so it never flashes in the wrong place */
  opacity: 0; transition: opacity .3s ease .1s;
}
.screen-wrap.ready { opacity: 1; }

.mac {
  position: absolute; inset: 0; overflow: hidden;
  background: #f9f5ed; color: #1a2f4f;
  font: 400 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  display: flex; flex-direction: column;
}
/* Glass. Sells the fact that this is behind a screen. */
.glare {
  position: absolute; inset: 0; z-index: 20; pointer-events: none;
  background:
    linear-gradient(112deg, rgba(255,255,255,.20) 0%, rgba(255,255,255,.05) 20%, rgba(255,255,255,0) 42%),
    radial-gradient(120% 90% at 92% 96%, rgba(0,0,0,.22), rgba(0,0,0,0) 62%);
}

/* ------------------------------------------------------------------ */
/* Making the phone version look switched on rather than stuck on.     */
/* ------------------------------------------------------------------ */
/* The app was already the right size, in the right place, on the right
   rectangle, with corners matching the photographed screen, and it still read
   as a sticker. What was missing had nothing to do with geometry: a lit screen
   in a dim room throws light on everything near it, and this one threw none.

   So the screen glows onto the bezel and the fingers holding the phone. That
   one cue does more than any amount of edge work, because it is the thing the
   eye actually uses to decide whether a light source is in the scene. The rest
   below is seating: the glass rim, the room falling off toward the bottom
   right, and a warm wash that puts the app in the same exposure as the
   photograph instead of a stop brighter than it. */
.mac.portrait {
  box-shadow:
    0 0 12px 1px rgba(255,242,220,.40),
    0 0 34px 6px rgba(255,236,210,.22),
    0 0 78px 20px rgba(255,230,198,.11);
}
.mac.portrait .glare {
  background:
    /* the window is on the left of the photograph, so the sheen is too */
    linear-gradient(112deg, rgba(255,255,255,.40) 0%, rgba(255,255,255,.12) 16%, rgba(255,255,255,0) 38%),
    /* a second, tighter band: glass rarely reflects in one clean wash */
    linear-gradient(112deg, rgba(255,255,255,0) 46%, rgba(255,255,255,.07) 53%, rgba(255,255,255,0) 60%),
    /* the room, falling away from the light */
    radial-gradient(125% 95% at 96% 99%, rgba(26,19,10,.28), rgba(0,0,0,0) 58%),
    /* same exposure as the photograph, not a stop brighter */
    linear-gradient(rgba(255,240,214,.07), rgba(255,240,214,.07));
  box-shadow:
    /* the lit edge of the glass against the bezel */
    inset 0 0 0 1px rgba(255,255,255,.30),
    /* and the bezel's own shadow falling onto it, so the app tucks under the
       phone instead of butting up against it */
    inset 0 2px 3px -1px rgba(28,20,10,.30),
    inset 0 -8px 14px -8px rgba(28,20,10,.26);
}

.mtop {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
  padding: 9px 16px; border-bottom: 1px solid #e6ddcd; background: #fffdf8;
}
.mtop .brand { font-family: Georgia, serif; font-size: 19px; }
.mtop .brand b { font-weight: 700; }
.mtop .right { font-size: 12.5px; color: #8291ad; display: flex; align-items: center; gap: 12px; }
.mtop .streak { color: #b0401c; font-weight: 700; }

/* Portrait: the same app, on a phone screen instead of a laptop one. Tighter
   because the box is 290 wide rather than 640, and taller, so the lesson and
   the quiz get room they never had. */
/* Bits that only belong on one shape of screen. */
.narrow-only, .mac.portrait .wide-only { display: none; }
.mac.portrait .narrow-only { display: inline; }
/* Specificity matters here: .urow sets display:flex further down the sheet, so
   a bare .tall-only rule loses to it and the extra rows leak onto the laptop. */
.mac .urow.tall-only { display: none; }
.mac.portrait .urow.tall-only { display: flex; }
/* A small phone gets a smaller screen, so the extra rows come back off and
   everything tightens. Measured against the real box, not the device, so a
   short window on a laptop behaves the same way. */
.mac.portrait.short .urow.tall-only { display: none; }
.mac.portrait.short { font-size: 12.5px; }
.mac.portrait.short .mtop { padding: 6px 10px; }
.mac.portrait.short .mtop .brand { font-size: 14px; }
.mac.portrait.short .mview { padding: 9px 11px 4px; }
.mac.portrait.short .mview h3 { font-size: 16px; }
.mac.portrait.short .urow { padding: 7px 9px; margin-top: 6px; }
.mac.portrait.short .urow .u-title { font-size: 12px; }
.mac.portrait.short .urow .u-sub { font-size: 9.5px; }
.mac.portrait.short .qstem, .mac.portrait.short #mv2 p, .mac.portrait.short .mcallout { font-size: 11.5px; }
.mac.portrait.short #mv2 p.mh { font-size: 13px; margin-top: 11px; }
.mac.portrait.short .qopt { font-size: 11px; padding: 7px 9px; }
.mac.portrait.short .meyebrow { display: none; }
.mac.portrait.short .mbar { margin: 6px 0 4px; height: 5px; }
.mac.portrait.short .mview h3 { margin-bottom: 3px; }
.mac.portrait.short .mdim { font-size: 10.5px; }
.mac.portrait.short .urow .state { width: 20px; height: 20px; font-size: 10px; }

/* Bigger than it was. The demo is the product, and squinting at it is the one
   thing that cannot happen. Content is allowed to run past the bottom of the
   phone: scrolling for the rest of a question is normal, shrinking the type to
   avoid scrolling is not. */
.mac.portrait { font: 400 15.5px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }
.mac.portrait .mtop { padding: 9px 13px; }
.mac.portrait .mtop .brand { font-size: 18px; }
.mac.portrait .mtop .right { font-size: 12px; gap: 9px; }
.mac.portrait .mview { padding: 13px 14px 14px; }
.mac.portrait .mview h3 { font-size: 20px; }
.mac.portrait .mview h4 { font-size: 19px; }
.mac.portrait .urow { padding: 9px 11px; gap: 10px; margin-top: 8px; }
.mac.portrait .urow .state { width: 24px; height: 24px; font-size: 12px; }
/* The list rows are the one place the bigger type does not pay: a course name
   wrapping onto three lines reads as broken. They stay compact, and the score
   goes, so the name gets the whole row. The lesson and the quiz, which are the
   parts people actually read, keep the larger size. */
.mac.portrait .urow .u-title { font-size: 13.5px; line-height: 1.3; }
.mac.portrait .urow .u-sub { font-size: 11px; line-height: 1.35; }
.mac.portrait .urow .score { display: none; }
.mac.portrait #mv2 .scroller, .mac.portrait #mv3 .scroller { padding: 13px 14px 16px; }
.mac.portrait #mv2 p, .mac.portrait .mcallout { font-size: 14px; }
.mac.portrait #mv2 p.mh { font-size: 16px; margin-top: 14px; }
.mac.portrait .qstem { font-size: 14px; }
.mac.portrait .qopt { font-size: 13.5px; padding: 10px 12px; }
.mac.portrait .qfb { font-size: 13px; }
.mac.portrait .mred, .mac.portrait .mgate p { font-size: 13.5px; }
.mac.portrait .mbtn { font-size: 14.5px; padding: 12px 20px; }

.mstack { position: relative; flex: 1 1 auto; min-height: 0; }
/* The outgoing screen clears before the incoming one arrives. A true
   crossfade shows two different lessons through each other for a third of a
   second, which reads as a rendering fault rather than a transition. */
.mview {
  position: absolute; inset: 0; padding: 14px 18px 16px;
  overflow: hidden; opacity: 0; pointer-events: none;
  transition: opacity .14s ease;
}
.mview.on { opacity: 1; pointer-events: auto; transition: opacity .26s ease .14s; }
.mview .inner { }

.meyebrow { font-size: 10.5px; letter-spacing: .13em; text-transform: uppercase; color: #8291ad; font-weight: 700; margin: 0 0 4px; }
.mview h3 { font-family: Georgia, serif; font-size: 21px; margin: 0 0 6px; line-height: 1.15; }
.mview h4 { font-family: Georgia, serif; font-size: 20px; margin: 0 0 8px; line-height: 1.15; }
.mdim { font-size: 12px; color: #8291ad; margin: 0; }

.mbar { height: 6px; background: #e6ddcd; border-radius: 3px; overflow: hidden; margin: 8px 0 6px; }
.mbar > i { display: block; height: 100%; background: #2c7a6e; border-radius: 3px; }

.urow {
  display: flex; align-items: center; gap: 11px;
  background: #fffdf8; border: 1.5px solid #e6ddcd; border-radius: 11px;
  padding: 9px 12px; margin-top: 8px;
}
.urow .state {
  flex: 0 0 auto; width: 25px; height: 25px; border-radius: 50%;
  background: #ece4d4; color: #8291ad; font-size: 12px; font-weight: 700;
  display: grid; place-items: center;
}
.urow.done .state { background: #2c7a6e; color: #fff; }
.urow.next { border-color: #d9a13f; box-shadow: 0 0 0 3px rgba(217,161,63,.16); }
.urow.next .state { background: #d9a13f; color: #2a1e06; }
.urow .u-title { font-weight: 600; font-size: 14px; }
.urow .u-sub { font-size: 11.5px; color: #8291ad; }
.urow .score { margin-left: auto; font-size: 12px; color: #2c7a6e; font-weight: 700; }
.urow.hit { background: #f3ecdd; }

/* the lesson and the quiz both scroll, like they do in the app */
#mv2, #mv3 { padding: 0; }
#mv2 .scroller, #mv3 .scroller { position: absolute; inset: 0; overflow: hidden; padding: 14px 18px 18px; }
.mcallout {
  background: #f6eed9; border-left: 3px solid #d9a13f; border-radius: 0 10px 10px 0;
  padding: 10px 13px; margin: 10px 0; font-size: 13.5px; line-height: 1.55;
}
#mv2 p { font-size: 13.5px; line-height: 1.62; margin: 10px 0; color: #46587a; }
#mv2 p b, .mcallout b { color: #1a2f4f; }
/* A heading inside a lesson body. The app's lesson blocks are paragraphs,
   headings, callouts and warnings; this is the heading. */
#mv2 p.mh {
  font-family: Georgia, serif; font-size: 15.5px; font-weight: 400; color: #1a2f4f;
  line-height: 1.25; margin: 16px 0 2px;
}
.mred { background: #f5dfdc; border-radius: 10px; padding: 10px 13px; margin-top: 10px; font-size: 13px; color: #7c3a3a; }
.mred b { color: #7c3a3a; }
.mgate { margin-top: 18px; padding-top: 14px; border-top: 1px solid #e6ddcd; text-align: center; }
.mgate p { margin: 0 0 10px; font-size: 13px; }
.mbtn {
  display: inline-block; border: 0; cursor: pointer; font-family: inherit; font-weight: 700; font-size: 14px; line-height: 1;
  background: #d9a13f; color: #2a1e06; border-radius: 10px; padding: 12px 22px;
}
.mbtn.plain { background: #1a2f4f; color: #f9f5ed; }
.mbtn.hit { filter: brightness(.92); }

/* quiz */
.qtop { display: flex; align-items: center; gap: 10px; margin: 2px 0 12px; }
.qtop .mbar { flex: 1; margin: 0; }
.qtop .mdim { white-space: nowrap; }
.qstem { font-size: 13.5px; line-height: 1.55; margin: 0 0 11px; }
.qopt {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: #fffdf8; border: 1.5px solid #e6ddcd; border-radius: 10px;
  padding: 9px 12px; margin: 7px 0; font-family: inherit; font-weight: 500; font-size: 12.8px; line-height: 1.42; color: #1a2f4f;
}
.qopt:hover:not(:disabled) { border-color: #1a2f4f; }
.qopt:disabled { cursor: default; }
.qopt.correct { border-color: #4d7a46; background: #e7f0e2; }
.qopt.wrong { border-color: #b35d5d; background: #f5dfdc; }
.qfb { border-radius: 10px; padding: 10px 13px; margin-top: 10px; font-size: 12.6px; line-height: 1.5; }
.qfb.good { background: #e7f0e2; }
.qfb.bad { background: #fdeae3; }
.qfb .again {
  display: inline-block; margin-top: 8px; background: none; border: 0; padding: 0;
  font-family: inherit; font-weight: 700; font-size: 12.5px; color: #b0401c; cursor: pointer; text-decoration: underline;
}

/* the fake cursor */
.mcursor {
  position: absolute; z-index: 25; left: 0; top: 0; width: 30px; height: 34px;
  pointer-events: none; opacity: 0;
  transform: translate(240px, 200px);
  transition: transform .78s cubic-bezier(.32,.72,.28,1), opacity .3s ease;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.4));
}
.mcursor.show { opacity: 1; }
.mcursor.press { transform-origin: 6px 4px; }
.ripple {
  position: absolute; z-index: 24; width: 18px; height: 18px; margin: -9px 0 0 -9px;
  border-radius: 50%; border: 2px solid #b0401c; pointer-events: none;
  animation: rip .5s ease-out forwards;
}
@keyframes rip { from { transform: scale(.4); opacity: .9; } to { transform: scale(2.6); opacity: 0; } }

/* ==========================================================================
   THE COURSE FINDER

   Thirty-two cards on the page at once is a wall, and a wall is where people
   stop reading. So the library asks a question instead: what do you want to
   get good at. Type an answer and it ranks the shelf; pick a shelf and it
   shows that one.
   ========================================================================== */
/* site.css sets smooth scrolling globally; anyone who has asked their system
   not to animate should get the jump instead. */
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Jump links land on the top of a SECTION, clear of the sticky header, so the
   heading and the card under it arrive together. Aiming at the card itself put
   its own top edge at the top of the window and cut the heading off above it. */
#pricing, #topics, #genie, #how, #why { scroll-margin-top: 70px; }

/* A link inside body text on a light background.

   .foot-link exists for the footer, where the background is navy, so it fades
   to WHITE on hover. Used on cream it vanished under the cursor. This is the
   same idea built for the other direction: brand coral, dark enough to pass
   contrast at body size, and it deepens rather than disappears. */
/* One value, not two: the site is light only, so there is no second palette
   for this to flip to. Kept as a variable because .body-link and its hover
   both read it. */
:root { --link-ink: #B0401C; --link-ink-hover: #8a2f11; }

.body-link {
  color: var(--link-ink); font-weight: 600;
  text-decoration: underline; text-underline-offset: 2px;
  text-decoration-thickness: 1.5px;
  text-decoration-color: color-mix(in srgb, var(--link-ink) 50%, transparent);
  transition: color .12s ease, text-decoration-color .12s ease;
}
.body-link:hover, .body-link:focus-visible {
  color: var(--link-ink-hover); text-decoration-color: var(--link-ink-hover);
}

/* Back to the top, once the first screen is behind you. */
.totop {
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--ink); color: var(--paper); border: 0; cursor: pointer;
  box-shadow: 0 2px 6px rgba(26,47,79,.2), 0 10px 28px rgba(26,47,79,.3);
  opacity: 0; transform: translateY(10px); pointer-events: none;
  transition: opacity .25s ease, transform .25s ease, background .15s ease;
}
.totop.on { opacity: 1; transform: none; pointer-events: auto; }
.totop:hover { background: var(--coral); }
.totop:focus-visible { outline: 2px solid var(--coral); outline-offset: 3px; }
.totop svg { width: 20px; height: 20px; display: block; }
@media (prefers-reduced-motion: reduce) { .totop { transition: none; } }

/* ==========================================================================
   THE PROMISE BAND

   One sentence over the photograph. His face sits in the left third of the
   frame, so the type lives on the right and the photo is anchored left, which
   keeps him visible at every width instead of being cropped or written over.
   ========================================================================== */
.promise { position: relative; overflow: hidden; isolation: isolate; }
.promise-photo {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 12% 40%;
}
.promise-veil {
  position: absolute; inset: 0;
  background:
    linear-gradient(90deg, rgba(19,35,59,.40) 0%, rgba(19,35,59,.44) 32%, rgba(19,35,59,.68) 54%, rgba(19,35,59,.76) 100%),
    linear-gradient(180deg, rgba(19,35,59,0) 34%, rgba(19,35,59,.36) 64%, rgba(19,35,59,.60) 100%);
}
.promise-inner {
  position: relative; z-index: 1;
  display: flex; justify-content: flex-end;
  padding-top: clamp(56px, 9vw, 110px); padding-bottom: clamp(30px, 5vw, 60px);
}
.promise-inner h2 {
  width: min(52%, 560px); margin: 0; color: #fdfaf3;
  font-size: clamp(1.5rem, 2.6vw, 2.5rem); line-height: 1.18;
}
/* How it works sits on the same photograph, below the sentence, so the whole
   picture is visible with the cards laid over it. */
.how-inner { position: relative; z-index: 1; padding-top: clamp(16px, 3vw, 34px); }
.how-inner h2, .how-inner .sub { color: #fdfaf3; }
.how-inner .sub { color: #cbd5e4; }
.how-inner .feature {
  background: color-mix(in srgb, var(--card) 94%, transparent);
  border: 1px solid rgba(255,255,255,.14);
  backdrop-filter: blur(3px);
  box-shadow: 0 10px 34px rgba(0,0,0,.28);
}
@media (max-width: 880px) {
  /* Phone order: the sentence, then his photograph, then how it works.

     The photograph is dissolved into the navy at both ends with a mask rather
     than covered by a veil, so it reads as part of the section instead of a
     picture pasted into it, and nothing is laid over his face. */
  .promise {
    background: var(--band);
    display: flex; flex-direction: column;
  }
  .promise-inner { order: 1; justify-content: flex-start; padding-top: 44px; padding-bottom: 40px; }
  .promise-inner h2 { width: auto; }
  /* Navy above and below him, and the photograph dissolving into it at both
     ends, so he sits in the section rather than being wedged between two
     blocks of text. */
  .promise-photo {
    order: 2; position: relative; width: 100%; height: 58vw; min-height: 220px;
    margin: 8px 0 20px; object-position: 26% 24%;
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 70%, transparent 100%);
    mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 70%, transparent 100%);
  }
  .promise-veil { display: none; }
  .how-inner { order: 3; padding-top: 26px; }
}

.finder { margin-top: 26px; }
.finder-search {
  display: flex; align-items: center; gap: 10px;
  background: var(--card); border: 1.5px solid var(--line); border-radius: 14px;
  padding: 4px 8px 4px 14px; box-shadow: var(--shadow);
  max-width: 640px; margin: 0 auto;
  transition: border-color .15s ease;
}
.finder-search:focus-within { border-color: var(--coral); }
.finder-search svg {
  width: 20px; height: 20px; flex: 0 0 auto; fill: none;
  stroke: var(--faint); stroke-width: 2; stroke-linecap: round;
}
/* Set long-hand, not with the font shorthand: "font: 400 1rem/1.4 inherit" is
   invalid (inherit cannot be the family inside the shorthand) and the browser
   throws the whole declaration away, which left this at the 13px default. */
.finder-search input {
  flex: 1; border: 0; outline: 0; background: none; color: var(--ink);
  font-family: inherit; font-size: 1rem; font-weight: 400; line-height: 1.4;
  padding: 13px 0;
}
.finder-search input::placeholder { color: var(--faint); }
.finder-search button {
  border: 0; background: none; color: var(--faint); cursor: pointer;
  font-size: 1.5rem; line-height: 1; padding: 4px 10px;
}
.finder-search button:hover { color: var(--ink); }
.finder-hint { font-size: .82rem; color: var(--faint); text-align: center; margin: 10px 0 0; }

.chips {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  margin: 22px auto 0; max-width: 900px;
}
.chip {
  border: 1.5px solid var(--line); background: var(--card); color: var(--soft);
  border-radius: 999px; padding: 8px 15px; cursor: pointer;
  font-family: inherit; font-weight: 600; font-size: .86rem; line-height: 1; white-space: nowrap;
  transition: border-color .12s ease, color .12s ease, background .12s ease;
}
.chip:hover { border-color: var(--ink); color: var(--ink); }
.chip[aria-selected="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.chip .n { opacity: .55; font-weight: 500; margin-left: 5px; }
.finder-count { text-align: center; font-size: .82rem; color: var(--faint); margin: 20px 0 0; }
.finder .grid.tiles { margin-top: 12px; }
/* The expand control under a capped shelf. Centred and quiet: it is a way to
   see more, not a call to action competing with the tiles above it. */
.shelf-more { display: block; margin: 14px auto 0; }
/* A tile marked hidden must actually be hidden.

   `.tile` is display:grid, and a class selector beats the browser's built-in
   [hidden] { display: none }, so setting el.hidden = true changed the DOM and
   nothing else: the collapse button toggled an attribute while all 44 cards
   stayed on screen. This is the one place !important is the right answer,
   because "hidden" is not a style suggestion. */
.tile[hidden] { display: none !important; }
/* A footer bar across the bottom of a card, for the shelf a search result came
   from and for a course the Genie built.

   Absolutely positioned on purpose. site.css styles EVERY span inside .tile as
   the 44 pixel icon and drops it into a two row grid, so a second span landed
   on top of the title. Taking these out of the grid entirely is the fix. */
.finder .tile { position: relative; padding-bottom: 32px; overflow: hidden; }
.tile .why, .tile .gtag {
  position: absolute; left: 0; right: 0; bottom: 0;
  width: auto; height: auto; border-radius: 0; grid-row: auto;
  display: block; text-align: center; font-style: normal;
  font-size: .68rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: 5px 8px;
}
.tile .why { color: var(--faint); background: color-mix(in srgb, var(--line) 45%, transparent); }
.tile .gtag { color: #7a5a12; background: rgba(217,161,63,.28); border-top: 1px solid rgba(217,161,63,.5); }
/* The Genie shelf chip carries a hint of gold so it reads as its own thing. */
.chip[data-cat="genie"] { border-color: rgba(217,161,63,.65); color: #8a6413; }
.chip[data-cat="genie"]:hover { border-color: var(--gold); }
.chip[data-cat="genie"][aria-selected="true"] { background: var(--gold); border-color: var(--gold); color: #2a1e06; }

/* The beta card stands alone now that there is nothing to compare it to. */
.plan.solo { max-width: 560px; margin: 0 auto; }
/* On navy, the muted grey this class normally uses all but disappears. */
.beta-sub { color: #fff; }

/* The sentence that lands the whole argument, now closing the beta section.
   It was set as fine print, which was the wrong weight for it, and it sits on
   navy, so it takes a light colour rather than the muted grey that class
   normally uses. */
.closing-line {
  margin: 26px auto 0; max-width: 40em;
  font-size: clamp(1.02rem, 1.5vw, 1.24rem); line-height: 1.55;
  color: #dbe3ef;
}
.closing-line strong, .closing-line b { color: #fff; }

/* The Genie is the one premium thing on the page and in light mode it was
   sitting on the same cream as everything else. It now has its own warm gold
   ground with a gold rule above it, so the eye stops there. */
.genie {
  background:
    radial-gradient(120% 90% at 12% 0%, rgba(217,161,63,.16), rgba(217,161,63,0) 62%),
    linear-gradient(180deg, color-mix(in srgb, var(--gold) 9%, var(--paper)) 0%, var(--paper) 78%);
  border-top: 2px solid var(--gold);
}
.genie .wishbar, .genie .ps-frame { box-shadow: 0 10px 34px rgba(120, 88, 20, .16); }

/* ---------- responsive ----------

   The laptop cannot come to a phone. Its screen would land at about 150 pixels
   across, and no type size survives that. So the phone gets the same three
   pieces in a stack instead: the words, a crop of the desk that keeps the mood
   (the notebook and the coffee, left of where the laptop starts), and the app
   itself as a full width card that is every bit as clickable. */
/* ==========================================================================
   THE PHONE HERO

   Below 900px the desk goes away and the app is held in a hand instead. The
   overlay machinery is identical: the same live app markup, mapped onto the
   four corners of a photographed phone screen rather than a laptop one.

   The first screen carries the headline, the running demo and the two buttons,
   and nothing else. Everything else waits below the fold.
   ========================================================================== */
@media (max-width: 900px) {
  .scene {
    height: auto; min-height: 0; padding: 0;
    background: var(--paper);
    position: relative;                 /* no sticky hero on a phone */
  }
  .hero-screen {
    display: block; position: relative; overflow: hidden;
    height: calc(100svh - 58px); min-height: 560px;
  }
  .stage, .scrim { display: none; }

  /* The photo is blown up until the phone in it is a usable size, then pinned
     so the screen lands under the headline. Everything is in vw so the whole
     arrangement scales with the device instead of drifting. */
  /* Size and position are written by the script, from the space available on
     the device. These are only the fallbacks if it never runs. */
  .stage-phone { display: block; position: absolute; inset: 0; overflow: hidden; }

  /* Sideways there used to be a blurred copy of the photograph behind this,
     to fill the space either side of a portrait picture with something other
     than a slab of navy. It has been replaced by the real thing: the markup
     now serves a genuinely wider crop of the same room when the device is
     turned, so the frame opens onto the window and the shelves instead of
     onto a guess at them. */
  .stage-phone img.handphone {
    position: absolute; width: 176vw; height: auto;
    left: -38vw; top: -40vw; max-width: none;
    z-index: 1;
  }
  .scrim-phone { z-index: 2; }
  /* Dark at the top so the headline reads, dark at the bottom so the buttons
     do, clear through the middle where the phone is. */
  .scrim-phone {
    position: absolute; inset: 0; pointer-events: none;
    background:
      linear-gradient(180deg, rgba(14,22,38,.86) 0%, rgba(14,22,38,.62) 16%, rgba(14,22,38,0) 30%),
      linear-gradient(0deg, rgba(14,22,38,.92) 0%, rgba(14,22,38,.7) 12%, rgba(14,22,38,0) 26%);
  }

  .hero-top { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
  .hero-top > * { pointer-events: auto; }
  /* Two lines, always, centred, and sat down off the header bar. The break in
     the markup splits it after "anything", so the job here is only to keep
     each half on one line, which leaves the rest of the screen for the phone. */
  .hero-top h1 {
    position: absolute; top: 30px; left: 18px; right: 18px; margin: 0;
    text-align: center;
    color: #fdfaf3; font-size: clamp(1.2rem, 6vw, 2rem); line-height: 1.16;
    letter-spacing: -.015em; text-shadow: 0 2px 18px rgba(8,14,26,.65);
  }
  .hero-top h1 em { color: #ffa585; font-style: italic; }
  .hero-top .cta-row {
    position: absolute; left: 20px; right: 20px; bottom: 22px;
    display: flex; gap: 10px; margin: 0; isolation: isolate;
  }
  /* The buttons sit over the lower part of the phone, so they carry their own
     shade. The scrim on the photograph cannot do it: the app is painted on top
     of the photograph, not under it. */
  .hero-top .cta-row::before {
    content: ""; position: absolute; inset: -26px -20px -26px; z-index: -1;
    background: linear-gradient(180deg, rgba(10,16,28,0) 0%, rgba(10,16,28,.72) 38%, rgba(10,16,28,.9) 100%);
  }
  .hero-top .cta-row .btn { flex: 1; text-align: center; padding: 14px 10px; }
  .hero-top .cta-row .btn.ghost {
    border-color: rgba(253,250,243,.9); color: #fdfaf3;
    background: rgba(10,16,28,.72); backdrop-filter: blur(6px);
  }

  /* The app itself keeps the mapped overlay, so it sits on the photographed
     screen and leans with it exactly as the laptop version does. */
  /* Rounded like the phone it is drawn on. Square corners on a rounded screen
     were the giveaway that the app was pasted on rather than running.

     The radius is set by the script from the width, because the app is sized
     to whatever phone it is drawn on. Measured off the photograph: the screen
     is 493px across and its corners turn over about 35px, so 7.1% of the
     width. The 15px here is only a fallback for a first paint. */
  /* The desktop version maps the app onto the laptop with a homography and
     needs its origin at the corner. The phone version is a plain rotation
     about the middle of the screen, so it needs the origin there instead. */
  .screen-wrap { z-index: 2; transform-origin: 50% 50%; }
  .mac { font-size: 13px; }
  .mac, .mac .glare { border-radius: var(--screen-r, 15px); }

  /* The demo scrolls under a finger.

     Measured on a 390 wide phone: the fourth answer sat 198 pixels below the
     visible screen with no way to reach it, so the question could be read but
     not answered. Scroll chaining is left alone on purpose: once the demo hits
     its end, the swipe carries on down the page as usual. */
  .mview, #mv2 .scroller, #mv3 .scroller {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .mview::-webkit-scrollbar, #mv2 .scroller::-webkit-scrollbar, #mv3 .scroller::-webkit-scrollbar { width: 0; height: 0; }
  /* A soft edge at the bottom of the screen, so there is a visible sign that
     the content carries on past it. */
  .mstack::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 34px;
    z-index: 15; pointer-events: none;
    background: linear-gradient(180deg, rgba(249,245,237,0), rgba(249,245,237,.92));
  }
  .mcursor { display: none; }

  /* Sat above the buttons, measured rather than guessed.

     This was bottom: 86px, a number tuned when the cta-row was one line of
     buttons. Adding the seats counter gave the row a second line, the row
     grows upward from the bottom of the screen, and the hint ended up printed
     across the Join button. A fixed offset cannot be right in both states
     anyway: the seats line is hidden until the API answers, so the row
     changes height at runtime. The script sets --hint-bottom from the height
     it already measures for the layout budget, and the fallback here is only
     for a first paint. */
  .scene-hint {
    position: absolute; left: 0; right: 0; bottom: var(--hint-bottom, 96px); z-index: 3;
    justify-content: center; color: #e6ddcd; text-shadow: 0 1px 8px rgba(0,0,0,.8);
    padding: 0; font-size: .7rem;
  }
  .scene-hint button { background: rgba(253,250,243,.14); color: #fdfaf3; border-color: rgba(253,250,243,.45); padding: 4px 10px; }

  /* Everything the first screen does not need, on navy so it reads as the
     continuation of the hero rather than a separate white page. Tight to the
     hero above it: the gap between the replay line and this text was the
     largest empty space on the phone. */
  .scene {
    background: var(--band);
    background-image: linear-gradient(180deg, #13233b 0%, #1a2f4f 100%);
  }
  /* Three things, not one paragraph.

     On a phone this was a solid block of similar-sized text and the eye had
     nowhere to land. Now: the explanation reads first and quietest, the
     choice of where to start is set apart by a rule, and the offer is a box.
     Different size, different colour, different shape, in that order. */
  .scene-copy {
    position: static; transform: none; width: auto;
    padding: 18px 20px 26px; color: #e6ddcd;
  }
  .scene-copy .lede {
    color: #cfd9e8; text-shadow: none;
    font-size: 1.02rem; line-height: 1.62; margin: 0;
  }
  .scene-copy .shout { color: #ffcf8f; }
  .scene-copy .standout {
    color: #fff3e6; border-left-color: var(--coral); border-left-width: 4px;
    font-size: 1.1rem; line-height: 1.5; font-weight: 600;
    margin-top: 22px; padding-left: 15px;
  }
  .scene-copy .standout a { color: #ffb489; border-bottom-color: rgba(255,180,137,.5); }
  /* The headline and the buttons are moved into the photo by script. They are
     not hidden here on purpose: if the script never runs they simply appear
     below the hero, which is plain but perfectly usable. */
  /* These were written for a cream section. The block above puts this content
     on navy instead, so only the sizing survives here. */
  .scene-copy h1 { font-size: clamp(2rem, 8.6vw, 2.9rem); }
  .scene-copy .lede { font-size: 1rem; max-width: none; }
  .scene-copy .shout { white-space: normal; }
  .scene-copy .standout { max-width: none; }
  .scene-copy .micro { color: #aab7cc; }
}

/* The real site's header has a proper small screen treatment; this page copies
   the markup only, so the links are folded away here rather than pushing the
   whole document wider than the phone.

   SIGN IN IS THE EXCEPTION, since 22 August 2026. Folding the section links
   away is right, because they are anchors to places further down this same
   page and a phone gets there by scrolling. Sign in is not one of those: it
   is the way back in for somebody who already has an account, and hiding it
   left them a header whose only control was the signup. It is named here
   rather than the rule above being loosened, so the anchors stay folded.

   The Join button drops to its short label at the same width. The two doors
   do not both fit at 320px otherwise, and the one that gave way is the one
   whose full wording is repeated twice more further down the page. */
@media (max-width: 720px) {
  .nav { padding: 12px 14px; gap: 10px; }
  .nav nav a:not(.btn) { display: none; }
  .nav nav a.signin { display: inline; }
  .nav nav { gap: 8px; align-items: center; }
  .nav .j-long { display: none; }
  .nav .j-short { display: inline; }
}
/* At phone width the logo and the call to action were sitting on top of each
   other. Everything in the header shrinks together rather than one thing
   getting cut. */
@media (max-width: 470px) {
  .nav { padding: 10px 12px; }
  .nav .logo { font-size: 1.02rem; gap: 6px; }
  .nav .logo-mark { width: 22px; height: 24px; }
  .nav nav { gap: 6px; }
  .nav nav .btn.small { font-size: .74rem; padding: 8px 11px; white-space: nowrap; }
  .nav nav a.signin { font-size: .74rem; }
}

/* The button and the "See plans" link under it (Michael, 13 September
   2026): one door into the app, one jump to the offer on this page. Side by
   side where the bar is wide; on a phone the link tucks under the button,
   which is the one place the folded section links leave for it. */
.nav .nav-cta { display: inline-flex; align-items: center; gap: 20px; }
.nav nav a.plans-link { text-decoration: none; color: var(--soft); font-size: .9rem; font-weight: 600; }
.nav nav a.plans-link:hover { color: var(--ink); }
@media (max-width: 720px) {
  .nav .nav-cta { gap: 10px; }
  .nav nav a.signin, .nav nav a.plans-link { white-space: nowrap; }
  /* Its own colour on a phone, so it does not read as part of Sign in
     (Michael, 13 September 2026). */
  .nav nav a.plans-link { display: inline; font-size: .74rem; color: var(--coral); font-weight: 700; }
}
/* The narrowest phones (320px): the same row, everything a touch closer. */
@media (max-width: 360px) {
  .nav { padding-inline: 8px; }
  .nav .logo { font-size: .95rem; gap: 5px; }
  .nav nav, .nav .nav-cta { gap: 6px; }
  .nav nav a.signin, .nav nav a.plans-link { font-size: .7rem; }
  .nav nav .btn.small { padding: 8px 9px; }
}

/* Phone held sideways.

   The hint reads "The quiz on the screen is real" and it is centred, which is
   right in portrait: the phone photograph is centred too and the line sits
   under it. Turn the phone and the hero gets short and wide, the photograph
   keeps the middle, and the centred line lands directly across the screen it
   is pointing at.

   So in landscape it moves to the right, into the empty space beside the
   phone, and stops stretching the full width. Kept last in the stylesheet
   because it shares its specificity with the portrait rule and has to win on
   source order.

   The max-height is what keeps this off tablets. A landscape iPad is 1024x768
   and has no such problem, so bounding by height means this only applies to
   the case that actually breaks: a phone on its side. */
@media (max-width: 950px) and (orientation: landscape) and (max-height: 560px) {
  .scene-hint {
    left: auto;
    right: clamp(12px, 3vw, 30px);
    width: auto;
    justify-content: flex-end;
    text-align: right;
  }
}


/* ---------- course landing pages ---------- */
.csec { padding: 54px 0; }
.csec > h2 { font-size: clamp(1.5rem, 3vw, 2.1rem); letter-spacing: -.01em; margin: 0 0 8px; }
.csec > .sub { margin: 0 0 28px; max-width: 44em; }
/* First responder pages: the EMT stands at the foot of the shelf, on the
   section's bottom edge, his open hand toward the courses. Laptops only,
   like the figure he is on /emt/. */
.shelf-foot { display: flex; align-items: center; gap: 28px; }
.shelf-foot > p { flex: 1; }
.shelf-foot > img { display: none; }
@media (min-width: 900px) {
  .shelf-foot > img { display: block; flex: none; width: auto; align-self: flex-end; height: 250px; margin: 22px 0 -30px; -webkit-mask-image: linear-gradient(180deg, #000 78%, transparent 100%); mask-image: linear-gradient(180deg, #000 78%, transparent 100%); }
}

.syl { list-style: none; padding: 0; margin: 0; counter-reset: u; }
.syl li {
  counter-increment: u; display: grid; grid-template-columns: 46px 1fr auto;
  gap: 4px 16px; align-items: baseline; padding: 15px 0; border-bottom: 1px solid var(--line);
}
.syl li::before {
  content: counter(u, decimal-leading-zero); grid-row: 1 / span 2;
  font-variant-numeric: tabular-nums; font-weight: 800; color: var(--coral); font-size: .95rem;
}
.syl li.is-sim::before { color: var(--gold); }
.syl b { font-size: 1.04rem; }
.syl i { grid-column: 2; font-style: normal; color: var(--soft); font-size: .94rem; }
.syl span { color: var(--faint); font-size: .82rem; white-space: nowrap; }
.syl-more { margin-top: 4px; }
.syl-more > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px;
  margin-top: 18px; padding: 10px 18px; border: 1.5px solid var(--line); border-radius: 999px;
  background: var(--card); color: var(--ink); font-weight: 700; font-size: .9rem;
}
.syl-more > summary::-webkit-details-marker { display: none; }
.syl-more > summary:hover { border-color: var(--coral); }
.syl-more > summary::after {
  content: ""; width: 8px; height: 8px; border-right: 2px solid var(--coral);
  border-bottom: 2px solid var(--coral); transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .15s ease;
}
.syl-more[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.syl-more .shut, .syl-more[open] .open { display: none; }
.syl-more[open] .shut { display: inline; }

.peek { background: var(--card); border: 1.5px solid var(--line); border-radius: 20px; padding: 30px 32px; }
.peek h3 { font-size: 1.18rem; margin: 26px 0 10px; }
.peek p { color: var(--soft); margin: 0 0 14px; }
.peek p:last-child { margin-bottom: 0; }
.peek .lmeta { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--faint); font-weight: 700; margin: 0 0 6px; }
.peek .ltitle { font-size: clamp(1.3rem, 2.4vw, 1.7rem); margin: 0 0 4px; }
.peek .lsub { color: var(--faint); font-size: .95rem; margin: 0 0 20px; }
.peek > h3:first-of-type { margin-top: 0; }
.lbul, .lnum { margin: 0 0 16px; padding-left: 22px; color: var(--soft); }
.lbul li, .lnum li { margin: 6px 0; }
.peek .cbox { border-left: 4px solid var(--coral); background: rgba(240,116,79,.07); border-radius: 0 12px 12px 0; padding: 14px 18px; margin: 18px 0; }
/* The label is the callout's FIRST bold, a direct child. The old selector
   (.cbox b) also caught every bold inside the text, and a memory hook such
   as "MTV: Measles, TB, Varicella" came out one letter per line, in coral
   capitals (Michael, 5 September 2026, on the NCLEX page). */
.peek .cbox > b { display: block; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--coral); margin-bottom: 5px; }
.peek .cbox p b { font-weight: 700; }
.peek .cbox p { margin: 0; color: var(--ink); }
.peek .cbox.gold { border-left-color: var(--gold); background: rgba(217,161,63,.10); }
.peek .cbox.gold > b { color: #8a6413; }
.peek .cbox.red { border-left-color: #b35d5d; background: var(--red-tint); }
.peek .cbox.red > b { color: var(--red-ink); }

.qcard { background: var(--card); border: 1.5px solid var(--line); border-radius: 20px; padding: 30px 32px; margin-top: 18px; }
.qstem { font-size: 1.1rem; font-weight: 600; margin: 0 0 18px; }
.qopts { padding: 0; margin: 0 0 20px; display: grid; gap: 9px; }
.qopt {
  display: block; width: 100%; text-align: left; cursor: pointer;
  border: 1.5px solid var(--line); border-radius: 13px; padding: 12px 16px;
  background: var(--paper); color: var(--ink);
  font: 500 .96rem/1.45 inherit; transition: border-color .12s ease;
}
.qopt:hover:not(:disabled) { border-color: var(--ink); }
.qopt:focus-visible { outline: 2px solid var(--coral); outline-offset: 2px; }
.qopt:disabled { cursor: default; }
.qopt.right { border-color: #4d7a46; background: #e7f0e2; font-weight: 600; }
.qopt.wrong { border-color: #b35d5d; background: var(--red-tint); }
.qwhy { border-top: 1.5px solid var(--line); padding-top: 16px; color: var(--soft); font-size: .96rem; margin: 0; }
.qwhy b { color: var(--ink); }

.faq { display: grid; gap: 10px; }
.faq details { background: var(--card); border: 1.5px solid var(--line); border-radius: 15px; padding: 4px 20px; }
.faq summary {
  list-style: none; cursor: pointer; font-weight: 700; padding: 14px 0;
  display: flex; justify-content: space-between; align-items: center; gap: 14px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--coral); font-size: 1.3rem; font-weight: 400; line-height: 1; }
.faq details[open] summary::after { content: "\2013"; }
.faq p { color: var(--soft); margin: 0 0 16px; }

.mlist { margin: 4px 0 8px; padding-left: 18px; }
.mlist li { margin: 3px 0; }

/* The typed-answer drill, for the course that has no options to click. */
.mdrill { text-align: center; padding: 6px 0 2px; }
.mdrill .dq { font-size: 1.5em; font-weight: 700; margin: 2px 0 8px; }
.mdrill .da {
  display: inline-block; min-width: 3.2em; padding: 4px 12px; border-radius: 8px;
  border: 2px solid var(--coral); font-size: 1.3em; font-weight: 800; color: var(--coral);
}
.mdrill .dk { margin-top: 8px; font-size: .8em; opacity: .75; }

@media (max-width: 640px) {
  .peek, .qcard { padding: 24px 20px; border-radius: 16px; }
  .syl li { grid-template-columns: 34px 1fr; }
  .syl span { grid-column: 2; }
}
