/*
 * Light Learning — lightlearning.ca
 *
 * One stylesheet, no framework, no build step, no fonts fetched from anybody else's
 * server. The whole site is four static files that can be dropped on any host, and that
 * is deliberate: a marketing site that needs a deploy pipeline is a marketing site that
 * goes stale, and this one has to state numbers that change with every release.
 *
 * The palette is the app's own, so a parent who has seen the App Store listing recognises
 * the site and the other way round.
 */
:root {
  --ink: #10213f;
  --muted: #55617a;
  --line: #e2e7f0;
  --bg: #ffffff;
  --wash: #f5f7fb;
  --blue: #3168ea;
  --blue-soft: #e8eeff;
  --green: #0f9d6e;
  --green-soft: #e3f7ef;
  --amber: #f2a33c;
  --red: #e8542f;
  --purple: #8b5cf6;
  --radius: 18px;
  --shadow: 0 6px 24px rgba(16, 33, 63, 0.08);
  --max: 1080px;
}

/* This site is light, on every device, whatever the browser is set to.
   The dark palette used to be swapped in by prefers-color-scheme, and the result was a
   page that could not be trusted: the illustrations are 3D renders on white, the app
   screenshots are photographs of a light interface, and the certificate is cream and
   gold. Inverting the text and the panels around them left light objects floating on a
   near-black page with no relationship to each other.
   A marketing page has one job, which is to be read by somebody deciding whether to trust
   you with their child. Two palettes means two designs to check, and only one of them was
   ever looked at. Declaring color-scheme keeps form controls and scrollbars light too,
   which is what made the earlier version look half-converted rather than dark. */
:root { color-scheme: light; }

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 17px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 22px; }

a { color: var(--blue); }

/* ------------------------------------------------------------------ header --- */

.top {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--line);
}
.top .wrap { display: flex; align-items: center; justify-content: space-between; height: 62px; gap: 16px; }
.brand { display: flex; align-items: center; gap: 9px; font-weight: 800; font-size: 18px; color: var(--ink); text-decoration: none; letter-spacing: -0.2px; }
.brand .mark { font-size: 23px; }
.top nav { display: flex; gap: 22px; }
.top nav a { color: var(--muted); text-decoration: none; font-size: 15px; font-weight: 600; }
.top nav a:hover { color: var(--ink); }
/* --------------------------------------------------------------------------
   The mobile menu.

   This rule used to be the whole story: `.top nav { display: none; }` and nothing put in
   its place, so below 700px the site had no navigation at all. Every page was reachable
   only by typing the URL. It is the kind of bug that survives because the person checking
   is looking at a laptop.

   No JavaScript. A checkbox holds the open state and a label toggles it, which works with
   scripts blocked and on a phone too old to run them.
   -------------------------------------------------------------------------- */
.menu-button { display: none; }

@media (max-width: 700px) {
  /* height:62px was fixed, so an opened menu overflowed the header and drew ON TOP of the
     hero photograph with nothing behind it: five links in muted grey over a picture of a
     child, which is not a menu anybody can read. The header has to GROW when the menu
     opens, and it can only grow if its height is not nailed down. */
  .top .wrap { position: relative; flex-wrap: wrap; height: auto; min-height: 62px; }

  /* Opaque, not translucent. The header is normally 88% of the background colour with a
     blur behind it, which is fine over a page and not fine over a photograph. */
  .top:has(.menu-toggle:checked) { background: var(--bg); backdrop-filter: none; }
  .menu-toggle:checked ~ nav { background: var(--bg); }

  /* The button: three bars, big enough to hit. 44px is the smallest target a thumb finds
     reliably, and this one is used by a parent holding a child. */
  .menu-button {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 44px;
    height: 44px;
    margin-left: auto;
    padding: 0 9px;
    border: 1px solid var(--line);
    border-radius: 11px;
    background: var(--card, #fff);
    cursor: pointer;
  }
  .menu-button span {
    display: block;
    height: 2.5px;
    border-radius: 2px;
    background: var(--ink);
    transition: transform .18s ease, opacity .18s ease;
  }

  /* Closed. max-height rather than display:none so it can animate, and visibility so a
     closed menu is not reachable by the keyboard or read out by a screen reader. */
  .top nav {
    display: flex;
    flex-direction: column;
    gap: 0;
    width: 100%;
    max-height: 0;
    overflow: hidden;
    visibility: hidden;
    transition: max-height .22s ease, visibility 0s linear .22s;
  }
  .menu-toggle:checked ~ nav {
    max-height: 60vh;
    overflow-y: auto;
    visibility: visible;
    transition: max-height .22s ease, visibility 0s;
    margin-top: 10px;
    border-top: 1px solid var(--line);
  }
  .top nav a {
    padding: 14px 2px;
    font-size: 16.5px;
    /* Full ink, not --muted. Muted is right for small links in a horizontal bar and wrong
       for a list of five destinations, where it reads as five disabled options. */
    color: var(--ink);
    font-weight: 700;
    border-bottom: 1px solid var(--line);
  }
  .top nav a:last-child { border-bottom: 0; }

  /* Open: the bars become a cross, so the button says what it will do next. */
  .menu-toggle:checked ~ .menu-button span:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
  .menu-toggle:checked ~ .menu-button span:nth-child(2) { opacity: 0; }
  .menu-toggle:checked ~ .menu-button span:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }
}

@media (prefers-reduced-motion: reduce) {
  .top nav, .menu-button span { transition: none; }
}

/* -------------------------------------------------------------------- hero --- */

.hero { padding: 76px 0 40px; text-align: center; }
.hero h1 {
  font-size: clamp(34px, 6vw, 56px);
  line-height: 1.08;
  letter-spacing: -1.4px;
  margin: 0 0 18px;
  font-weight: 800;
}
/* The hero break is right on a wide screen and wrong on a phone, where it left the word
   "child" alone on a line of its own. Let the headline wrap naturally below 700px. */
.wide-only { display: inline; }
@media (max-width: 700px) { .wide-only { display: none; } }

.lede { font-size: clamp(17px, 2.2vw, 21px); color: var(--muted); max-width: 640px; margin: 0 auto 30px; }
.ctas { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.cta {
  display: inline-block;
  background: var(--blue);
  color: #fff;
  text-decoration: none;
  font-weight: 700;
  font-size: 16px;
  padding: 15px 30px;
  border-radius: 999px;
  border: 2px solid var(--blue);
}
.cta:hover { filter: brightness(1.07); }
.cta.ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.note { color: var(--muted); font-size: 14.5px; margin-top: 18px; }

/* The phone shots. Real screens from the build that is on TestFlight, never a mockup. */
.shots {
  display: flex;
  gap: 20px;
  justify-content: center;
  align-items: flex-end;
  margin: 52px auto 0;
  flex-wrap: wrap;
}
.shot { width: 218px; }
.shot img {
  width: 100%;
  display: block;
  border-radius: 26px;
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  background: var(--wash);
}
.shot span { display: block; text-align: center; color: var(--muted); font-size: 13.5px; margin-top: 11px; font-weight: 600; }
@media (max-width: 640px) { .shot { width: 44%; min-width: 150px; } }

/* ------------------------------------------------------------------ blocks --- */

h2 { font-size: clamp(26px, 3.6vw, 36px); letter-spacing: -0.7px; margin: 0 0 10px; font-weight: 800; }
.sub { color: var(--muted); margin: 0 0 30px; font-size: 17px; max-width: 620px; }
section { padding: 44px 0; }
@media (max-width: 760px) { section { padding: 32px 0; } }
.band { background: var(--wash); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; }
.card {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
}
.card .emoji { font-size: 32px; line-height: 1; }
.card h3 { margin: 13px 0 7px; font-size: 18.5px; font-weight: 800; }
.card p { margin: 0; color: var(--muted); font-size: 15.5px; }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 18px; text-align: center; }
.stat b { display: block; font-size: clamp(28px, 4.4vw, 42px); font-weight: 800; letter-spacing: -1px; color: var(--blue); }
.stat span { color: var(--muted); font-size: 14.5px; }

/* The curricula, as flags rather than a list nobody reads. */
.flags { display: flex; flex-wrap: wrap; gap: 12px; }
.flag {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 10px 18px;
  background: var(--bg);
  font-weight: 700;
  font-size: 15px;
}
.flag em { font-style: normal; font-size: 20px; }
.flag small { color: var(--muted); font-weight: 500; }

/* ------------------------------------------------------------------ prices --- */

.plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; }
.plan {
  border: 2px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  background: var(--bg);
  position: relative;
}
.plan.best { border-color: var(--green); }
.plan .tag {
  position: absolute;
  top: -13px;
  left: 26px;
  background: var(--green);
  color: #fff;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.7px;
  padding: 4px 12px;
  border-radius: 999px;
}
.plan h3 { margin: 0; font-size: 17px; font-weight: 800; }
.price { font-size: 40px; font-weight: 800; letter-spacing: -1.4px; margin: 6px 0 2px; }
.price small { font-size: 15px; font-weight: 600; color: var(--muted); letter-spacing: 0; }
.plan ul { margin: 16px 0 0; padding: 0; list-style: none; }
.plan li { padding: 7px 0 7px 26px; position: relative; color: var(--muted); font-size: 15.5px; }
.plan li::before { content: "✓"; position: absolute; left: 0; color: var(--green); font-weight: 800; }

/* --------------------------------------------------------------------- faq --- */

.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); padding: 20px 0; }
.faq summary { cursor: pointer; font-weight: 700; font-size: 17.5px; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; float: right; color: var(--muted); font-weight: 400; font-size: 24px; line-height: 1; }
.faq details[open] summary::after { content: "–"; }
.faq p { color: var(--muted); margin: 12px 0 0; }

/* ------------------------------------------------------------------ footer --- */

.foot { border-top: 1px solid var(--line); padding: 40px 0; color: var(--muted); font-size: 14.5px; }
.foot .wrap { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.foot a { color: var(--muted); text-decoration: none; margin-right: 20px; }
.foot a:hover { color: var(--ink); }

/* --------------------------------------------------------------- documents --- */

/* Privacy, terms and support are long prose and want a narrower measure than the
   marketing page: past about 70 characters a line the eye loses its place returning. */
.doc { max-width: 720px; padding: 48px 22px 72px; margin: 0 auto; }
.doc h1 { font-size: clamp(28px, 5vw, 40px); letter-spacing: -1px; margin: 0 0 6px; }
.doc .when { color: var(--muted); font-size: 14.5px; margin: 0 0 34px; }
.doc h2 { font-size: 21px; margin: 38px 0 8px; }
.doc p, .doc li { color: var(--muted); }
.doc li { margin: 6px 0; }
.doc strong { color: var(--ink); }
.doc .callout {
  background: var(--green-soft);
  border: 1px solid var(--green);
  border-radius: var(--radius);
  padding: 18px 22px;
  margin: 26px 0;
}
.doc .callout p { color: var(--ink); margin: 0; }


/* ==========================================================================
   Pictures.

   The page was long and grey: nine paragraphs of text in a row with an emoji
   on top of each. Length was the complaint and pictures normally make a page
   longer, so every one of these earns its space by letting the words next to
   it get shorter, and the sections were tightened at the same time.
   ========================================================================== */

.brand img { width: 34px; height: 34px; vertical-align: -9px; margin-right: 2px; }


/* A picture and a paragraph side by side, which reads shorter than either alone. */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; }
.split.reverse .split-art { order: 2; }
.split-art { margin: 0; }
.split-art img {
  width: 100%; height: auto; display: block;
  border-radius: 18px;
  box-shadow: 0 12px 34px rgba(16, 32, 70, .12);
}
.split-words h2 { margin-top: 0; }
.split-words .sub { margin-left: 0; margin-right: 0; max-width: none; }

/* The three device shots were the single biggest cause of the page being long on a
   phone: three 900px-tall images stacked is most of a screen each. Side by side in a
   strip that scrolls, they cost one screen instead of three. */
@media (max-width: 760px) {
  .split { grid-template-columns: 1fr; gap: 22px; }
  .split.reverse .split-art { order: 0; }
  .shots {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 10px;
    margin-inline: -20px;
    padding-inline: 20px;
  }
  .shots .shot { flex: 0 0 62%; scroll-snap-align: center; margin: 0; }
  .shots .shot img { width: 100%; height: auto; }
}


/* --------------------------------------------------------------------------
   Full-bleed banners.

   Three pictures run the whole width of the window with no margin and no
   rounding, at a height worth having. Boxed inside the column they read as
   decoration; edge to edge and tall they read as the page changing subject.
   There were five and two of them were carrying nothing the words did not
   already say, so they went rather than being shrunk.
   -------------------------------------------------------------------------- */
.bleed {
  margin: 0;
  width: 100%;
  line-height: 0;
}
.bleed img {
  /* Full width and NOT cropped. A fixed height with object-fit: cover was cutting the
     tops off heads and losing half of every scene, which is the opposite of showing a
     picture. Height follows the picture's own proportions, so all of it is visible.
     It makes the page taller, and that is the trade being made on purpose. */
  width: 100%;
  height: auto;
  display: block;
}

/* The device shots now sit in their own section under the picture. */
.shots-section { padding-top: 34px; }

/* --------------------------------------------------------------------------
   The device shots.

   Framed in CSS rather than baked into the file: the browser draws a sharper
   corner than a resampled mask, and an attempt at doing it in ImageMagick
   silently produced five black rectangles.
   -------------------------------------------------------------------------- */
.shots {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 18px;
  margin-top: 34px;
  align-items: start;
}
.shots .shot { margin: 0; text-align: center; }
.shots .shot img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 20px;
  border: 5px solid #10203f;
  /* The bezel is navy; the SCREEN behind the picture is not.
     This used to be #10203f as well, which meant that until the picture arrived the frame
     was a solid navy slab the size of a phone. There are five of them and they are all
     lazy-loaded, so on a phone connection the page showed a column of black rectangles.
     That is not a loading state, it reads as a broken page.
     A pale screen looks like a phone that has not woken up yet, which is the truth. */
  background: #eef2f8;
  box-shadow: 0 14px 34px rgba(16, 32, 70, .20);
}
.shots .shot span {
  display: block;
  margin-top: 10px;
  font-size: 13px;
  color: var(--muted);
}

@media (max-width: 900px) {
  /* Five phones stacked is five screens of scrolling. A strip that swipes is one. */
  .shots {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 12px;
    margin-inline: -20px;
    padding-inline: 20px;
  }
  .shots .shot { flex: 0 0 58%; scroll-snap-align: center; }
  .bleed img { height: clamp(230px, 56vw, 340px); }
}

/* ==========================================================================
   The inner pages.

   Twenty-three of them now, all rendered by scripts/build-site.mjs from one
   shell, so the nav is written once. The curriculum pages are generated from
   ALL_OBJECTIVES rather than typed, because a hand-written list of topics is
   out of date the day after it is written, which is precisely what happened to
   the counts on the home page.
   ========================================================================== */

.doc-wide { max-width: 1080px; }

.crumb { font-size: 14px; color: var(--muted); margin: 0 0 8px; }
.crumb a { color: var(--muted); }

/* ------- the six curriculum cards ------- */
.ccards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
  margin: 26px 0 10px;
}
.ccard {
  display: block;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--card);
  text-decoration: none;
  color: inherit;
  transition: border-color .15s ease, transform .15s ease;
}
.ccard:hover { border-color: var(--brand); transform: translateY(-2px); }
.ccard em { font-style: normal; font-size: 32px; display: block; }
.ccard b { display: block; margin-top: 8px; font-size: 19px; }
.ccard small { display: block; color: var(--muted); margin-top: 4px; line-height: 1.4; }
.ccard span { display: block; margin-top: 12px; font-weight: 700; color: var(--brand); }

/* ------- a year, and the subjects inside it ------- */
.yearblock { margin: 34px 0 0; }
.yearblock h2 {
  display: flex;
  align-items: baseline;
  gap: 12px;
  border-bottom: 2px solid var(--line);
  padding-bottom: 8px;
}
.yearblock h2 .count { font-size: 14px; font-weight: 600; color: var(--muted); }

.subj {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 16px;
  margin: 10px 0;
  background: var(--card);
}
.subj > summary {
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: baseline;
  list-style: none;
}
.subj > summary::-webkit-details-marker { display: none; }
.subj > summary::after { content: '+'; color: var(--muted); font-weight: 700; }
.subj[open] > summary::after { content: '−'; }
.subj > summary span { color: var(--muted); font-size: 14px; font-weight: 600; margin-left: auto; margin-right: 14px; }
.subj ul { margin: 12px 0 0; padding-left: 20px; }
.subj li { margin: 6px 0; line-height: 1.5; }
.subj .more { color: var(--muted); font-size: 14px; margin: 10px 0 0; }

/* ------- the comparison table ------- */
.tablewrap { overflow-x: auto; margin: 22px 0; }
.cmp { border-collapse: collapse; width: 100%; min-width: 720px; }
.cmp.small { min-width: 0; }
.cmp th, .cmp td {
  border: 1px solid var(--line);
  padding: 12px 14px;
  text-align: left;
  vertical-align: top;
  font-size: 15px;
  line-height: 1.5;
}
.cmp thead th { background: var(--band); font-size: 15px; }
.cmp tbody th { background: var(--band); width: 190px; font-weight: 700; }
.cmp td:nth-child(2) { background: rgba(49, 104, 234, .05); }

/* ------- the certificate ------- */
.certshot { margin: 24px 0 8px; text-align: center; }
.certshot img {
  max-width: 460px;
  width: 100%;
  height: auto;
  border-radius: 10px;
  box-shadow: 0 14px 40px rgba(16, 32, 70, .18);
}
.certshot figcaption { color: var(--muted); font-size: 14px; margin-top: 12px; }

/* ------- the footer, which now carries every page ------- */
.footlinks { display: flex; flex-wrap: wrap; gap: 8px 18px; justify-content: flex-end; max-width: 620px; }

@media (max-width: 760px) {
  .footlinks { justify-content: flex-start; }
  .cmp tbody th { width: 120px; }
}

/* The FAQ page uses the same question styling as the block on the home page. It was
   styled by section class rather than by element, so a details block anywhere else fell
   back to the browser's default triangle and looked like a different site. */
.doc > details,
.doc details:not(.subj) {
  border-bottom: 1px solid var(--line);
  padding: 18px 0;
}
.doc details:not(.subj) > summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 17px;
  list-style: none;
  padding-right: 30px;
  position: relative;
}
.doc details:not(.subj) > summary::-webkit-details-marker { display: none; }
.doc details:not(.subj) > summary::after {
  content: "+";
  position: absolute;
  right: 0;
  top: -2px;
  color: var(--muted);
  font-weight: 400;
  font-size: 24px;
  line-height: 1;
}
.doc details:not(.subj)[open] > summary::after { content: "–"; }
.doc details:not(.subj) > p { color: var(--muted); margin: 12px 0 0; }

/* Section headings inside a long document need more air above them than below. */
.doc h2 { margin-top: 42px; }
.doc details:not(.subj) + h2 { margin-top: 48px; }

/* ==========================================================================
   Page heroes and the country strip.

   Every inner page opens on an illustration with the title over it, cropped
   from the top so the subject of the picture is what you see. A dark gradient
   sits between the picture and the words, because white text on an
   illustration is unreadable about a third of the time and there is no way to
   know which third in advance.
   ========================================================================== */

.pagehero {
  background-size: cover;
  background-position: center top;
  background-repeat: no-repeat;
  color: #fff;
  padding: 74px 0 62px;
  border-bottom: 1px solid var(--line);
}
.pagehero .wrap { max-width: 900px; }
.pagehero .kicker {
  text-transform: uppercase;
  letter-spacing: 2.4px;
  font-size: 12.5px;
  font-weight: 800;
  margin: 0 0 12px;
  color: #ffd88a;
}
.pagehero h1 {
  margin: 0;
  font-size: clamp(32px, 4.6vw, 52px);
  line-height: 1.06;
  letter-spacing: -1.2px;
  color: #fff;
  text-shadow: 0 2px 22px rgba(6, 14, 32, .45);
}
.pagehero .lede {
  margin: 14px 0 0;
  max-width: 640px;
  color: rgba(255, 255, 255, .93);
  font-size: clamp(16px, 1.9vw, 19px);
  text-shadow: 0 1px 14px rgba(6, 14, 32, .5);
}

/* A page that opens on a hero does not need its own top padding as well. */
.doc.has-hero { padding-top: 34px; }

/* ------- six flags, on every page ------- */
.countrystrip {
  background: var(--band);
  border-top: 1px solid var(--line);
  padding: 44px 0;
}
.countrystrip h2 { margin: 0 0 6px; }
.countrystrip .sub { margin: 0 0 22px; max-width: 640px; }
.cflags {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
}
.cflag {
  display: block;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  text-decoration: none;
  color: inherit;
  transition: border-color .15s ease, transform .15s ease;
}
.cflag:hover { border-color: var(--brand); transform: translateY(-2px); }
.cflag em { font-style: normal; font-size: 26px; display: block; line-height: 1; }
.cflag b { display: block; margin-top: 8px; font-size: 16px; }
.cflag small { display: block; color: var(--muted); margin-top: 3px; font-size: 13px; }

@media (max-width: 760px) {
  .pagehero { padding: 52px 0 44px; }
  .countrystrip { padding: 32px 0; }
}

/* ==========================================================================
   Depth.

   The illustrations are 3D renders and everything around them was flat: one
   hairline border, no shadow, no lift. The page looked like two designs stuck
   together. This gives every surface the same soft, physical depth the
   pictures already have.

   The rules are deliberately restrained. Two shadows on a card, not five: a
   tight one for the edge and a wide soft one for the ground. Anything heavier
   reads as a 2008 website rather than a modern one.
   ========================================================================== */

:root {
  --lift-1: 0 1px 2px rgba(16, 32, 70, .06), 0 6px 18px rgba(16, 32, 70, .07);
  --lift-2: 0 2px 4px rgba(16, 32, 70, .07), 0 14px 34px rgba(16, 32, 70, .11);
  --lift-3: 0 3px 6px rgba(16, 32, 70, .08), 0 24px 56px rgba(16, 32, 70, .14);
  --edge: inset 0 1px 0 rgba(255, 255, 255, .9);
}

/* ------- cards, plans, flags, stats: raised, and they lift on hover ------- */
.card, .plan, .flag, .ccard, .cflag, .subj {
  box-shadow: var(--lift-1), var(--edge);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .9), rgba(255, 255, 255, 0));
  transition: box-shadow .18s ease, transform .18s ease;
}
.card:hover, .plan:hover, .ccard:hover, .cflag:hover {
  box-shadow: var(--lift-2), var(--edge);
  transform: translateY(-3px);
}
.plan.best {
  box-shadow: var(--lift-3), var(--edge);
  transform: translateY(-4px);
}
.plan.best:hover { transform: translateY(-7px); }

/* ------- the stat chips read as objects rather than text ------- */
.stats { gap: 14px; }
.stat {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 20px 18px;
  box-shadow: var(--lift-1), var(--edge);
}

/* ------- buttons that can be pressed ------- */
.cta {
  box-shadow: 0 1px 2px rgba(16, 32, 70, .10), 0 8px 20px rgba(49, 104, 234, .28);
  transition: transform .12s ease, box-shadow .18s ease, filter .18s ease;
}
.cta:hover { transform: translateY(-2px); box-shadow: 0 2px 4px rgba(16, 32, 70, .12), 0 14px 30px rgba(49, 104, 234, .34); }
.cta:active { transform: translateY(1px); box-shadow: 0 1px 2px rgba(16, 32, 70, .16); }
.cta.ghost {
  box-shadow: var(--lift-1), var(--edge);
  background: var(--card);
}
.cta.ghost:hover { box-shadow: var(--lift-2), var(--edge); }

/* ------- the header floats over the page ------- */
.top {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, .82);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  box-shadow: 0 1px 0 rgba(16, 32, 70, .07), 0 8px 24px rgba(16, 32, 70, .05);
}
.brand img { filter: drop-shadow(0 3px 6px rgba(16, 32, 70, .22)); }

/* ------- device shots sit on a surface ------- */
.shots .shot img { box-shadow: var(--lift-3); }

/* ------- the full-width pictures get a soft ground under them ------- */
.bleed { position: relative; }
.bleed::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 60px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0), var(--bg));
  pointer-events: none;
}

/* ------- bands get a gentle gradient rather than a flat fill ------- */
.band, .countrystrip {
  background-image: linear-gradient(180deg, var(--band), rgba(255, 255, 255, .4));
}

/* ------- the certificate is a physical object ------- */
.certshot img { box-shadow: var(--lift-3); }

/* Anybody who has asked their system for less movement gets none of it. */
@media (prefers-reduced-motion: reduce) {
  .card, .plan, .flag, .ccard, .cflag, .cta, .subj { transition: none; }
  .card:hover, .plan:hover, .ccard:hover, .cflag:hover, .cta:hover { transform: none; }
}

/* ==========================================================================
   The home hero: the words sit on the picture.

   The picture is anchored to the TOP of the frame, so the faces are what you
   see, and the words sit along the bottom under a gradient that starts at
   nothing and ends dark. Putting the text down there rather than across the
   middle is not a style choice: the child is on the left of this photograph
   and his mother on the right, and centred text would land on both of them.
   ========================================================================== */

.homehero {
  position: relative;
  min-height: min(88vh, 780px);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: #0a1630;
}
.homehero-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}
/* The scrim. Nothing at the top so the picture is a picture, dark at the
   bottom so the type is readable without fighting it. */
.homehero::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(8, 18, 40, .30) 0%, rgba(8, 18, 40, 0) 26%,
                            rgba(8, 18, 40, .55) 62%, rgba(8, 18, 40, .93) 100%);
  pointer-events: none;
}
.homehero-inner {
  position: relative;
  z-index: 2;
  padding-top: 60px;
  padding-bottom: 54px;
  color: #fff;
  text-align: center;
}

.homehero .eyebrow {
  text-transform: uppercase;
  letter-spacing: 3px;
  font-size: 12.5px;
  font-weight: 800;
  color: #ffd88a;
  margin: 0 0 16px;
  text-shadow: 0 2px 10px rgba(6, 14, 32, .6);
}
.homehero h1 {
  margin: 0;
  font-size: clamp(38px, 6.4vw, 76px);
  line-height: 1.02;
  letter-spacing: -2px;
  font-weight: 900;
  color: #fff;
  text-shadow: 0 3px 30px rgba(6, 14, 32, .55), 0 1px 3px rgba(6, 14, 32, .5);
}
.homehero .lede {
  margin: 18px auto 0;
  max-width: 620px;
  font-size: clamp(17px, 2.1vw, 21px);
  line-height: 1.5;
  font-weight: 500;
  color: rgba(255, 255, 255, .95);
  text-shadow: 0 2px 16px rgba(6, 14, 32, .6);
}
.homehero .ctas { margin-top: 28px; justify-content: center; }
.homehero .note {
  margin: 18px 0 0;
  color: rgba(255, 255, 255, .8);
  font-size: 14px;
  text-shadow: 0 1px 10px rgba(6, 14, 32, .6);
}

/* Four things a parent checks before anything else, said once, in a row. */
.trust {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}
.trust li {
  font-size: 13.5px;
  font-weight: 700;
  color: #fff;
  padding: 8px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .26);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.trust li::before { content: '✓ '; color: #8ff0b5; font-weight: 900; }

@media (max-width: 760px) {
  .homehero { min-height: min(90vh, 680px); }
  .homehero-inner { padding-bottom: 38px; }
  .homehero h1 { letter-spacing: -1.2px; }
  .trust li { font-size: 12.5px; padding: 7px 11px; }
}

/* Readability corrections, all three found by looking at the rendered hero rather than
   the stylesheet:

   1. The gold eyebrow sat directly over the brightest part of the photograph and
      disappeared. It gets its own quiet plate rather than a bigger shadow, because a
      shadow large enough to fix it looks like a mistake.
   2. The ghost button was a white outline on a busy picture and was close to invisible.
      A translucent plate behind it makes it a button again.
   3. The scrim was doing most of its work below the words instead of behind them. */
.homehero::after {
  background:
    linear-gradient(180deg,
      rgba(8, 18, 40, .34) 0%,
      rgba(8, 18, 40, .10) 22%,
      rgba(8, 18, 40, .58) 52%,
      rgba(8, 18, 40, .86) 78%,
      rgba(8, 18, 40, .96) 100%);
}
.homehero .eyebrow {
  display: inline-block;
  padding: 7px 16px;
  border-radius: 999px;
  background: rgba(8, 18, 40, .5);
  border: 1px solid rgba(255, 216, 138, .38);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  text-shadow: none;
}
.homehero .cta.ghost {
  background: rgba(255, 255, 255, .16);
  border: 1px solid rgba(255, 255, 255, .55);
  color: #fff;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 8px 22px rgba(6, 14, 32, .3);
}
.homehero .cta.ghost:hover {
  background: rgba(255, 255, 255, .26);
  box-shadow: 0 12px 28px rgba(6, 14, 32, .36);
}

/* The first picture fills the screen.

   It was capped at 780px, which on a large display left it sitting in the top
   third with white space under it. A hero that does not reach the fold is not
   a hero. 100svh rather than 100vh so that mobile browser chrome does not push
   the bottom of it, and the words with it, below the fold. */
.homehero {
  min-height: 100vh;
  min-height: 100svh;
}
@media (max-width: 760px) {
  .homehero { min-height: 100vh; min-height: 100svh; }
}

/* ==========================================================================
   Feature rows: a picture on one side, the words on the other, on white.

   This replaced a grid of nine cards. The grid put nine paragraphs in a row
   with an emoji on top of each, which asks the eye to work and gives nothing
   its own moment. A row gives each thing a screen, a picture and one link.

   The sides alternate, which is the whole reason it reads easily: the eye
   learns the rhythm after two rows and stops having to search for where the
   next heading starts.
   ========================================================================== */

.feature { background: #fff; padding: 26px 0; }
.feature.alt { background: linear-gradient(180deg, #f7f9fd, #fff); }

.featrow {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
}
.feature.alt .featart { order: 2; }

.featart { margin: 0; }
.featart img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 20px;
  box-shadow: var(--lift-2);
}

.feattext .kicker {
  text-transform: uppercase;
  letter-spacing: 2.4px;
  font-size: 12px;
  font-weight: 800;
  color: var(--brand);
  margin: 0 0 10px;
}
.feattext h2 {
  margin: 0 0 12px;
  font-size: clamp(24px, 2.9vw, 34px);
  line-height: 1.14;
  letter-spacing: -0.8px;
}
.feattext p { margin: 0; color: var(--muted); font-size: 17px; line-height: 1.6; }

.arrow {
  display: inline-block;
  margin-top: 18px;
  font-weight: 700;
  text-decoration: none;
  color: var(--brand);
}
.arrow::after {
  content: ' →';
  transition: transform .15s ease;
  display: inline-block;
}
.arrow:hover::after { transform: translateX(4px); }

@media (max-width: 860px) {
  .featrow { grid-template-columns: 1fr; gap: 22px; }
  /* On one column the picture always comes first, whichever side it was on. A row that
     alternates on a phone just looks like the layout has gone wrong. */
  .feature.alt .featart { order: 0; }
  .feature { padding: 20px 0; }
}

/* ==========================================================================
   Movement.

   Two kinds, both small. Sections rise into place as they come into view, and
   the illustrations breathe very slightly so a still page does not feel dead.

   Everything here is inside a prefers-reduced-motion guard and, more
   importantly, the page is fully readable with the script switched off: the
   reveal starts visible and JavaScript adds the class that hides it. Doing it
   the other way round means a reader with no JavaScript gets a blank page,
   which is a real way sites break and a lazy one.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .js-reveal .reveal {
    opacity: 0;
    transform: translateY(26px);
  }
  .js-reveal .reveal.seen {
    opacity: 1;
    transform: none;
    transition: opacity .7s cubic-bezier(.2, .7, .3, 1), transform .7s cubic-bezier(.2, .7, .3, 1);
  }
  /* The picture arrives a touch after its words, which reads as one movement
     rather than two things happening at once. */
  .js-reveal .reveal .featart { transition-delay: .1s; }

  @keyframes ll-float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-9px); }
  }
  .featart img { animation: ll-float 7s ease-in-out infinite; }
  .feature.alt .featart img { animation-duration: 8.5s; animation-delay: -2s; }
  .certshot img { animation: ll-float 9s ease-in-out infinite; }

  .shots .shot { transition: transform .3s ease; }
  .shots .shot:hover { transform: translateY(-8px); }
}

/* The footer carries the full wordmark rather than a line of small grey text. The header
   mark is served at 160px for a 34px slot so it stays crisp on a retina screen, which the
   128px version did not. */
.footbrand { display: flex; flex-direction: column; gap: 12px; }
.footbrand img { width: 200px; height: auto; display: block; }
.footbrand p { margin: 0; font-size: 14px; color: var(--muted); }
.foot .wrap { align-items: flex-start; }

@media (max-width: 760px) {
  .footbrand img { width: 170px; }
}

/* One of the five figures is a span rather than a number: "Creche → Grade 12". At the size
   a four-digit number wants, it ran out of its box. Words get their own smaller size, and
   every figure wraps rather than overflowing. */
/* Two wrong turns before this one. `overflow-wrap: anywhere` stopped the overflow and
   broke "128,287" into "128,28 / 7". `white-space: nowrap` kept the number whole and let
   "Ages 3 to 18" run straight out of its card.

   Neither was needed. A number has no spaces in it, so ordinary wrapping cannot break one,
   and the only figure made of words wraps at its spaces like any other sentence. The rule
   is simply to leave wrapping alone and size the words to fit. */
.stat b { line-height: 1.1; }
.stat b.words {
  font-size: clamp(19px, 2.1vw, 25px);
  letter-spacing: -0.4px;
}

/* ==========================================================================
   Mobile layout corrections, found by rendering the site at 390px rather than
   by reading the stylesheet.

   These sit at the END of the file on purpose. The responsive rules for .shots
   were written at line 340 and the base `.shots { display: grid }` at line 396,
   so the base rule — later in the file, same specificity — quietly won and the
   mobile layout never applied at all. Cascade order is not a detail.
   ========================================================================== */
@media (max-width: 760px) {
  /* Two across, not one.
     Five phone screenshots stacked one per row is five screens of scrolling before a
     parent reaches the words, and the words are what sells this. Two across halves it and
     still shows the screen clearly enough to be worth showing. */
  .shots {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
    overflow: visible;
  }
  .shots .shot { flex: none; margin: 0; }
  .shots .shot img { border-width: 4px; border-radius: 15px; }
  .shots .shot span { font-size: 12px; margin-top: 8px; }

  /* Full-bleed banners are close to square, so at full width each one eats most of a
     phone screen. Cropping to a wider shape keeps the picture doing its job as a break
     between sections without making it the section. */
  .bleed img {
    height: 52vw;
    max-height: 300px;
    object-fit: cover;
    object-position: center 38%;
  }

  /* The illustrated feature pictures had no height limit either. */
  .split-art img, .featrow img { max-height: 46vh; object-fit: contain; }
}

/* ==========================================================================
   The real certificate, laid over the illustration.

   The illustration says a certificate exists. The certificate itself says what
   it looks like, and that is the thing a child wants and a parent judges. It
   overlaps rather than sitting beside, because side by side reads as two
   unrelated pictures and overlapping reads as one object on top of another.
   ========================================================================== */
.featart-stacked { position: relative; }
.featart-stacked .certlap {
  position: absolute;
  right: -3%;
  bottom: -7%;
  width: 43%;
  height: auto;
  border-radius: 8px;
  /* Two shadows: a tight one so the edge reads as paper, and a wide soft one so it
     lifts off the illustration rather than looking pasted onto it. */
  box-shadow: 0 2px 6px rgba(16, 33, 63, .18), 0 22px 44px rgba(16, 33, 63, .26);
  transform: rotate(3.5deg);
  background: #fff;
}

@media (max-width: 760px) {
  /* Still overlapping, just less of it, and straighter: a 3.5 degree tilt that looks
     relaxed at 500px looks like a mistake at 390px. */
  .featart-stacked .certlap {
    width: 40%;
    right: 0;
    bottom: -5%;
    transform: rotate(2deg);
  }
}

/* ==========================================================================
   The lead sentence of every feature paragraph.

   Each of these paragraphs already opened with a bold sentence carrying the whole
   point, and then rendered in the same colour as the rest, so it did the work of
   a heading with none of the visibility. Colour makes the first line legible at a
   glance to somebody scrolling, which is how this page is actually read.
   ========================================================================== */
.feattext p > b:first-child,
.feature p > b:first-child {
  color: var(--blue);
  font-weight: 800;
}
/* The alternating rows sit on a tinted background; the same blue on it is heavy. */
.feature.alt .feattext p > b:first-child { color: #2456c9; }

/* ==========================================================================
   The six certificates.

   The claim on this site that is hardest to believe is "six national curricula,
   not one with the labels swapped". Six real certificates say it in a way no
   paragraph can: the Nigerian one reads Primary 2 and names NERDC, the English
   one reads Year 2, and each seal carries its own flag.
   ========================================================================== */
.certband { padding: 56px 0; }
.certgrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
  margin-top: 34px;
}
.certgrid figure { margin: 0; }
.certgrid img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 6px;
  background: #fdfaf2;
  /* A tight edge so it reads as paper, and a wide soft one so it lifts off the band. */
  box-shadow: 0 2px 5px rgba(16, 33, 63, .14), 0 16px 34px rgba(16, 33, 63, .16);
}
.certgrid figcaption {
  margin-top: 12px;
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  color: var(--muted);
}

@media (max-width: 900px) { .certgrid { grid-template-columns: repeat(2, 1fr); gap: 18px; } }
@media (max-width: 520px) {
  /* Still two across. One per row would be six screens of scrolling for a point that is
     made by seeing them side by side. */
  .certgrid { gap: 13px; }
  .certgrid figcaption { font-size: 12.5px; margin-top: 8px; }
}
