/*
 * Ratelsoft brand tokens.
 * Derived from NewBrand/Brand2.dc.html and Main2.dc.html.
 *
 * Every colour used anywhere in the app must come from a token here. Never declare a
 * colour only inside a media query or [data-theme] block - the light palette on bare
 * :root is the base, and the dark blocks redefine tokens only.
 */

/*
 * The typefaces, served from this application.
 *
 * Every layout used to link fonts.googleapis.com, which meant every visitor's IP address
 * reached Google on every page view - cross-border, with no consent and no necessity.
 * docs/privacy-notice.md S4 records that as a live data-protection finding and the notice
 * had to name Google as a processor because of it. Self-hosting removes the disclosure,
 * and on a Nigerian mobile connection it also removes a third-party DNS lookup, TLS
 * handshake and round trip from the critical path of every page. Do not put a font host
 * back: tests/Feature/Site/SelfHostedFontsTest.php fails if any surface references one.
 *
 * Both are variable fonts, so one file covers 400/500/600/650/700/750/800 - every weight
 * the stylesheets ask for - instead of seven static files. Provenance, the axis surgery
 * and the subsetting decision are in docs/brand.md; the OFL text sits beside the files in
 * public/fonts, as the licence requires.
 *
 * The version is in the filename, not a query string, so public/.htaccess can cache these
 * for a year as immutable and a future upgrade simply lands on a new URL.
 *
 * format("woff2"), not the older format("woff2-variations"): the variations keyword was a
 * 2017 Safari transitional spelling and browsers that never knew it reject the whole src
 * line, which is a silent fall back to the system sans. Every engine that supports variable
 * fonts reads the axes out of the file itself.
 */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("/fonts/bricolage-grotesque-v1.001.woff2") format("woff2");
  font-weight: 200 800;
  font-stretch: 100%;
  font-style: normal;
  /*
   * swap, not optional: headings are where the brand actually lives, they are few and
   * short, and a reader who never sees the display face has been served a different site.
   * The layouts preload this file so the swap happens as early as the network allows.
   */
  font-display: swap;
}

@font-face {
  font-family: "Instrument Sans";
  src: url("/fonts/instrument-sans-v1.000.woff2") format("woff2");
  font-weight: 400 700;
  font-stretch: 100%;
  font-style: normal;
  /*
   * optional, not swap, and deliberately different from the display face. On a slow
   * Nigerian mobile connection a swap in body copy reflows the paragraph the reader is
   * halfway through; optional gives them stable text immediately in the system sans,
   * fetches the face in the background, and every page after the first in that session is
   * fully branded. The difference between Instrument Sans and a system UI sans in running
   * text is the kind of thing that is not worth a reflow.
   */
  font-display: optional;
}

@font-face {
  font-family: "Instrument Sans";
  src: url("/fonts/instrument-sans-italic-v1.000.woff2") format("woff2");
  font-weight: 400 700;
  font-stretch: 100%;
  font-style: italic;
  font-display: optional;
}

:root {
  /* Core brand */
  --ink:         #0E2A40;   /* deep navy - primary text and dark surfaces */
  --blue:        #1B7FC6;   /* primary action */
  --blue-dark:   #0F6BAB;
  --blue-deeper: #14639C;
  --leaf:        #8DC63F;   /* the flower mark's green */
  --green:       #3FAE49;
  --green-dark:  #2E7D36;
  --gold:        #F6C215;
  --gold-dark:   #8F6B00;

  /* Neutrals - blue-biased, matching the navy rather than pure grey */
  --slate:       #51677A;
  --slate-soft:  #8296A7;
  --slate-faint: #7C93A5;
  --line:        #C9D6E0;
  --line-soft:   #DFE7EE;
  --wash:        #EEF3F7;
  --wash-deep:   #EAF0F5;
  --paper:       #FAFCFE;
  --white:       #FFFFFF;

  /*
   * Semantic - separate from the brand accent.
   *
   * --ok and --warn are each a shade darker than the brand colour they came from
   * (--green-dark #2E7D36 and --gold-dark #8F6B00), and the shade is the whole point: both are
   * used as TEXT on their own wash, in a badge, a pill and a notice, and there they measured
   * 4.29:1 and 4.43:1 — under the 4.5:1 AA asks of body text. On paper they always passed, which
   * is why it survived: the failure is only in the one place the colour sits on its own tint.
   *
   * Lightening the wash instead was the wrong lever. Enough of it to clear 4.5:1 puts the wash
   * within 1.08:1 of the page, so a success badge would have had no visible background left. A
   * 5% and a 3% darkening of the ink is invisible beside the old colour and costs nothing.
   *
   * The brand tokens above are untouched: --green-dark and --gold-dark still mean what
   * CLAUDE.md says they mean. These are the semantic layer, which is what this block is for.
   * SemanticContrastTest measures every pair and is the reason this cannot drift back.
   */
  --ok:          #2C7733;
  --ok-wash:     #E4EFD4;
  --warn:        #8B6800;
  --warn-wash:   #FDF3D3;
  --danger:      #A5301F;
  --danger-wash: #F7DDD8;

  /* Assigned roles */
  --bg:          var(--paper);
  --surface:     var(--white);
  --surface-alt: var(--wash);
  --text:        var(--ink);
  --text-soft:   var(--slate);
  /*
   * The third text tier, and NOT --slate-soft, for the same reason --accent is not --blue.
   *
   * --slate-soft measured 3.06:1 on white and 2.74:1 on --wash. WCAG AA asks 4.5:1 of body text,
   * and this token carries body text in 42 places across four stylesheets: every form-field hint
   * on /register and /account-recovery, the stat labels on the dashboard, table column headers,
   * the words beside an activation code. "Faint" describes the intended weight in the hierarchy;
   * it was never a licence to fall under the floor.
   *
   * Fixed on the token rather than by repainting the 42 surfaces onto --text-soft. Those uses are
   * all correct about wanting the quietest tier — the tier itself was simply too quiet, and
   * moving them would collapse three tiers into two everywhere at once.
   *
   * #5C7082 is 5.13:1 on white, 4.59:1 on --wash and 4.99:1 on --paper: it clears AA on every
   * ground it is used on, with a little headroom on the worst of them. It stays lighter than
   * --text-soft (5.88:1), so the ramp survives — though the gap is narrower than it was, because
   * the floor is where it is and a tier below the floor is not a tier.
   *
   * The dark theme is untouched: #7C93A5 already measures 5.14:1 on --surface and 4.67:1 on
   * --surface-alt. Only the light palette was failing.
   */
  --text-faint:  #5C7082;
  --border:      var(--line);
  --border-soft: var(--line-soft);
  /*
   * The accent is --blue-dark, not --blue, and that is an accessibility fix rather than a taste.
   *
   * --accent is the colour of link text and the background of the primary button under a white
   * --on-accent, so it has to clear 4.5:1 twice over. --blue measures 4.17:1 against --paper and
   * the same against white text — under AA in both directions at once — and dragged the accent
   * pill to 3.85:1 on --wash. --blue-dark is 5.66:1 against paper and 5.06:1 on the wash.
   *
   * --blue is untouched and still right for a large heading or a graphic accent, where 3:1 is
   * the bar. The dark theme audits clean and is not changed.
   *
   * The hover then has to be darker again, and --blue-deeper is: 6.20:1, and still blue, so a
   * link keeps the one cue that says it is a link. Nothing here is a new brand colour.
   *
   * NB: no braces in this comment. BrandPalette reads the tokens out of this file by taking
   * everything between ":root " and the first closing brace, so a CSS example written inside
   * this block truncates the palette — silently, until a mail template asks for a token that
   * came after it and 41 tests fail at once. See BrandPaletteTest.
   */
  --accent:      var(--blue-dark);
  --accent-hover:var(--blue-deeper);
  --on-accent:   var(--white);

  /*
   * Type.
   *
   * Every stack names real families after the webfont, and that is not belt-and-braces:
   * Instrument Sans has no naira sign (U+20A6) at all, so on every price on the site the
   * browser falls through this list glyph by glyph. A stack ending at the bare `sans-serif`
   * keyword would still work, but naming Segoe UI / Roboto / system-ui first is what keeps
   * the naira sign in a face that matches the digits beside it. Bricolage Grotesque does
   * carry U+20A6, which is why prices set in the display face look right today.
   */
  --font-display: "Bricolage Grotesque", "Segoe UI", Roboto, system-ui, "Helvetica Neue", Arial, sans-serif;
  --font-body:    "Instrument Sans", "Segoe UI", Roboto, system-ui, "Helvetica Neue", Arial, sans-serif;
  --font-mono:    ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;

  /* Scale */
  --step--1: clamp(0.83rem, 0.8rem + 0.15vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.09rem);
  --step-1:  clamp(1.2rem, 1.12rem + 0.4vw, 1.45rem);
  --step-2:  clamp(1.5rem, 1.35rem + 0.75vw, 2rem);
  --step-3:  clamp(1.95rem, 1.65rem + 1.5vw, 2.9rem);
  --step-4:  clamp(2.5rem, 1.9rem + 3vw, 4.2rem);

  --radius:    10px;
  --radius-lg: 18px;
  --shadow:    0 1px 2px rgba(14, 42, 64, .06), 0 8px 24px rgba(14, 42, 64, .07);
  --shadow-lg: 0 2px 4px rgba(14, 42, 64, .07), 0 20px 50px rgba(14, 42, 64, .11);

  /*
   * What the BROWSER paints, as opposed to what we paint.
   *
   * Checkboxes, radios, scrollbars, select menus, date pickers and the overscroll gutter are
   * drawn by the user agent, and the only thing it consults is `color-scheme`. Our tokens do
   * not reach them.
   *
   * This was missing entirely, and the page carried only
   * `<meta name="color-scheme" content="light dark">` — which says "either is fine, you
   * decide", so the browser decided from the OS. A reader on a dark system who pressed our
   * light toggle got a light page with DARK checkboxes, because the tokens flipped and the
   * user agent did not. The three blocks below move together for exactly that reason: every
   * place the palette switches, this switches with it.
   */
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Native controls follow the palette. See the note on :root. */
    color-scheme: dark;

    --bg:          #08131D;
    --surface:     #0E2130;
    --surface-alt: #14293A;
    --text:        #E6EEF5;
    --text-soft:   #A6BACA;
    --text-faint:  #7C93A5;
    --border:      #21384B;
    --border-soft: #1A2E3F;
    --accent:      #4FA5E4;
    --accent-hover:#6FB8EE;
    --on-accent:   #04121C;
    --ok:          #7FCB6B;
    --ok-wash:     #16301C;
    --warn:        #E0AE55;
    --warn-wash:   #33270F;
    --danger:      #EC8375;
    --danger-wash: #351914;
  }
}

/*
 * A reader whose SYSTEM is dark but who chose our LIGHT theme.
 *
 * The tokens are already right — the media query is written
 * `:root:not([data-theme="light"])`, so it steps aside — but `color-scheme` set inside it
 * does not step aside on its own. Without this one line the page is light and every
 * checkbox, radio and scrollbar on it stays dark. That is the bug this block exists for.
 */
:root[data-theme="light"] {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg:          #08131D;
  --surface:     #0E2130;
  --surface-alt: #14293A;
  --text:        #E6EEF5;
  --text-soft:   #A6BACA;
  --text-faint:  #7C93A5;
  --border:      #21384B;
  --border-soft: #1A2E3F;
  --accent:      #4FA5E4;
  --accent-hover:#6FB8EE;
  --on-accent:   #04121C;
  --ok:          #7FCB6B;
  --ok-wash:     #16301C;
  --warn:        #E0AE55;
  --warn-wash:   #33270F;
  --danger:      #EC8375;
  --danger-wash: #351914;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}

a { color: var(--accent); }
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------------------
 * The colour-theme control, and the swap.
 *
 * These two rules live in the TOKEN file rather than in any one area's stylesheet because
 * all three areas now carry the toggle — the public site, the accounts area and the admin
 * area — and brand.css is the only stylesheet all three load. Putting them in site.css, as
 * they were, meant a signed-in customer got a button with no styling and a theme change
 * that crossfaded.
 *
 * Both are written entirely in tokens, so they follow the palette they switch.
 * ------------------------------------------------------------------------- */

/* Transitions are muted for one frame around a theme change.
 *
 * Blink does not restart a transition when only the custom property behind it changes, so
 * anything with a transitioned colour kept painting the OLD theme's value: after a toggle
 * the site header's buttons were left in the previous palette, and "Client login" measured
 * about 1.2:1 — near-white on white. The script adds this class across the swap, which also
 * drops a full-page colour crossfade nobody asked for. */
.theme-switching,
.theme-switching *,
.theme-switching *::before,
.theme-switching *::after {
  transition: none !important;
}

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--border);
  /* Round, like the pills either side of it in the site header: one shape family. The
   * accounts topbar and the admin sidebar both put it beside their own controls, and a
   * circle reads as "a setting" rather than as another item in the row. */
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-soft);
  cursor: pointer;
  flex: none;
}

.theme-toggle:hover {
  color: var(--text);
  border-color: var(--accent);
}

/*
 * Public marketing site.
 *
 * Rules for this file:
 *   - No colour literal appears here. Every colour is a token from brand.css, or a
 *     color-mix() of tokens. Mixes are used instead of new tokens so that a tint follows
 *     its base through the light and dark palettes without a second definition.
 *   - Layout is fluid from 360px up. Breakpoints are min-width only.
 *   - Anything that could scroll sideways (tables) does so inside its own container.
 *
 * Sections, in order:
 *   1. Primitives      2. Layout      3. Header / nav      4. Footer
 *   5. Buttons         6. Hero        7. Cards & sections  8. Exam vignette
 *   9. Tables         10. Forms      11. Prose            12. Utilities
 *  13. Late additions
 *
 * Then the k-* language: first the shared block ("The shared language" — the design
 * system every rebuilt page is made of; see docs/design-system.md), then the homepage's
 * own sections, then the examina.io cross-sell and product-state styles.
 */

/* ------------------------------------------------------------------ 1. primitives */

/* Theme switching.
   A transitioned property whose value comes from a custom property does not
   re-transition in Blink when only that custom property changes: the element keeps
   its old computed colour until something else forces a style recalc. That left the
   header's buttons painted in the previous theme's ink after a toggle — "Client
   login" ended up near-white on white, about 1.2:1. The toggle adds this class for
   one frame around the swap, so a theme change lands instantly and nothing is left
   stranded mid-transition. It also drops a full-page colour crossfade nobody asked
   for. */
html {
  scroll-behavior: smooth;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* `clip`, not `hidden`: `overflow-x: hidden` turns the body into a scroll container,
     which silently breaks `position: sticky` on the header. `clip` trims the decorative
     petals that hang past the edge without creating one. */
  overflow-x: clip;
}

img,
svg {
  max-width: 100%;
  height: auto;
}

p {
  margin: 0 0 1em;
}

p:last-child {
  margin-bottom: 0;
}

ul,
ol {
  margin: 0 0 1em;
  padding-inline-start: 1.3em;
}

a {
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

hr {
  border: 0;
  border-top: 1px solid var(--border-soft);
  margin: 0;
}

/* The one thing every keyboard user needs and most sites forget. */
.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -100vh;
  z-index: 100;
  background: var(--accent);
  color: var(--on-accent);
  padding: 0.7rem 1.1rem;
  border-radius: var(--radius);
  font-weight: 600;
  text-decoration: none;
}

.skip-link:focus {
  top: 0.5rem;
}

/* --------------------------------------------------------------------- 2. layout */

.shell {
  width: 100%;
  max-width: 1180px;
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 3rem);
}

.shell--narrow {
  max-width: 760px;
}

main {
  flex: 1 0 auto;
}

.band {
  padding-block: clamp(3rem, 8vw, 5.5rem);
}

.band--tight {
  padding-block: clamp(2rem, 5vw, 3rem);
}

.band--wash {
  background: var(--surface-alt);
}

.band--ink {
  background: var(--ink);
  color: var(--white);
}

.band--ink h2,
.band--ink h3 {
  color: var(--white);
}

/*
 * Body links inside an ink band go white — but NOT buttons, which carry their own
 * background and colour. `.band--ink a` (0,1,1) outranks `.btn--on-ink` (0,1,0), so
 * without the :not() a white-on-ink button renders white text on its own white
 * background and is invisible until hover, where `.btn--on-ink:hover` (0,2,0) finally
 * wins the colour back.
 */
.band--ink a:not(.btn) {
  color: var(--white);
}

.stack > * + * {
  margin-top: var(--stack-gap, 1rem);
}

.stack--loose {
  --stack-gap: clamp(1.5rem, 4vw, 2.5rem);
}

.grid {
  display: grid;
  gap: clamp(1rem, 2.5vw, 1.75rem);
}

@media (min-width: 640px) {
  .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 960px) {
  .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (min-width: 640px) and (max-width: 959.98px) {
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ------------------------------------------------------------------ 3. header/nav */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-soft);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-radius: 999px;
  padding: 0.45rem 0.95rem;
}

.eyebrow--plain {
  background: none;
  padding: 0;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--surface);
  border-bottom: 1px solid var(--border-soft);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 68px;
}

.brandmark {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--text);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.35rem;
  letter-spacing: -0.03em;
}

.brandmark img {
  width: 30px;
  height: 30px;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 1.6rem);
}

.site-nav a {
  color: var(--text-soft);
  text-decoration: none;
  font-weight: 500;
  font-size: 0.97rem;
  padding-block: 0.35rem;
  border-bottom: 2px solid transparent;
}

.site-nav a:hover {
  color: var(--text);
}

.site-nav a[aria-current="page"] {
  color: var(--text);
  border-bottom-color: var(--accent);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* The mobile menu is a <details>: it opens without JavaScript and is reachable from the
   keyboard on its own, which a div-and-onclick menu is not. */
.menu {
  display: none;
}

.menu > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.5rem 0.9rem;
  font-family: var(--font-display);
  font-weight: 650;
  font-size: 0.95rem;
  color: var(--text);
}

.menu > summary::-webkit-details-marker {
  display: none;
}

.menu__panel {
  position: absolute;
  left: 0;
  right: 0;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow);
  padding: 0.75rem clamp(1rem, 4vw, 3rem) 1.25rem;
}

.menu__panel a {
  display: block;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--border-soft);
  color: var(--text);
  text-decoration: none;
  font-weight: 500;
}

.menu__panel a[aria-current="page"] {
  color: var(--accent);
}

@media (max-width: 899.98px) {
  /* Both button classes, deliberately.

     This rule used to name `.btn` alone, because that is what the header's two actions were
     when it was written. The homepage redesign moved them to `.k-btn` so that the pill in
     the bar and the pill in the page body are one shape — and the moment it did, this rule
     stopped matching anything. The header then carried a wordmark, a theme toggle, two pills
     and the Menu pill on a 360px screen, which does not fit: every page of the site scrolled
     64px sideways on a phone. Naming both classes fixes it and keeps working whichever one a
     future edit uses. `.site-header__bar` also gets `min-width: 0` so a long wordmark can
     shrink instead of pushing the row wide again. */
  .site-nav--wide,
  .header-actions .btn,
  .header-actions .k-btn {
    display: none;
  }

  .site-header__bar {
    min-width: 0;
  }

  .menu {
    display: block;
  }
}

/* --------------------------------------------------------------------- 4. footer */

.site-footer {
  background: var(--ink);
  color: color-mix(in srgb, var(--white) 74%, var(--ink));
  padding-block: clamp(2.5rem, 6vw, 4rem) 1.5rem;
  margin-top: auto;
}

.site-footer a {
  color: color-mix(in srgb, var(--white) 80%, var(--ink));
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--white);
  text-decoration: underline;
}

.site-footer h2,
.site-footer h3 {
  color: var(--white);
}

.site-footer__cols {
  display: grid;
  gap: 2rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .site-footer__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 960px) {
  .site-footer__cols { grid-template-columns: 1.6fr repeat(3, minmax(0, 1fr)); }
}

.site-footer__heading {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--white) 60%, var(--ink));
  margin: 0 0 0.9rem;
}

.site-footer ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-footer li + li {
  margin-top: 0.55rem;
}

.site-footer__base {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid color-mix(in srgb, var(--white) 16%, var(--ink));
  font-size: var(--step--1);
}

.site-footer__wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.5rem;
  letter-spacing: -0.03em;
  color: var(--white);
  text-decoration: none;
}

.site-footer__blurb {
  margin-top: 1rem;
}

.site-footer__wordmark img {
  width: 32px;
  height: 32px;
}

/* -------------------------------------------------------------------- 5. buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font: inherit;
  font-weight: 600;
  line-height: 1.2;
  padding: 0.8rem 1.3rem;
  border-radius: var(--radius);
  border: 1.5px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--on-accent);
}

.btn--ghost {
  background: transparent;
  border-color: var(--border);
  color: var(--text);
}

.btn--ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.btn--on-ink {
  background: var(--white);
  border-color: var(--white);
  color: var(--ink);
}

.btn--on-ink:hover {
  background: color-mix(in srgb, var(--white) 88%, var(--ink));
  color: var(--ink);
}

.btn--outline-ink {
  background: transparent;
  border-color: color-mix(in srgb, var(--white) 45%, var(--ink));
  color: var(--white);
}

.btn--outline-ink:hover {
  border-color: var(--white);
  color: var(--white);
}

.btn--small {
  padding: 0.5rem 0.9rem;
  font-size: var(--step--1);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.center .btn-row,
.center .trust-row {
  justify-content: center;
}

.center .eyebrow {
  display: inline-flex;
}

/* ----------------------------------------------------------------------- 6. hero */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: clamp(2.5rem, 7vw, 5rem);
}

/* Two soft petal shapes from the flower mark, as background geometry rather than an
   image. Purely decorative, so they are aria-hidden in the markup. */
.hero__petal {
  position: absolute;
  pointer-events: none;
  opacity: 0.09;
}

.hero__petal--one {
  top: -6rem;
  right: -5rem;
  width: clamp(18rem, 34vw, 30rem);
  color: var(--accent);
}

.hero__petal--two {
  bottom: -4rem;
  left: -6rem;
  width: clamp(12rem, 22vw, 18rem);
  color: var(--leaf);
  transform: rotate(-40deg);
}

.hero__inner {
  position: relative;
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}

@media (min-width: 1000px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  }
}

.hero h1 {
  font-size: var(--step-4);
  font-weight: 700;
  margin: 1.1rem 0 0;
}

.hero h1 em {
  font-style: normal;
  color: var(--accent);
}

.hero__lede {
  font-size: var(--step-1);
  color: var(--text-soft);
  max-width: 34ch;
  margin: 1.1rem 0 1.6rem;
}

.stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2rem;
  margin-top: 2rem;
}

.stat__value {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-2);
  line-height: 1.1;
}

.stat__label {
  font-size: var(--step--1);
  color: var(--text-faint);
}

/* ------------------------------------------------------- 7. cards and sections */

.section-head {
  max-width: 46rem;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

.section-head h2 {
  font-size: var(--step-3);
  margin: 0.9rem 0 0;
}

.section-head p {
  color: var(--text-soft);
  font-size: var(--step-1);
  margin: 0.9rem 0 0;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: clamp(1.25rem, 3vw, 1.75rem);
}

.card--link {
  text-decoration: none;
  color: inherit;
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}

.card--link:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}

.card h3 {
  font-size: var(--step-1);
}

.card p {
  color: var(--text-soft);
}

.card__icon {
  width: 56px;
  height: 56px;
  object-fit: contain;
}

.card__eyebrow {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent);
}

.card__more {
  margin-top: auto;
  padding-top: 0.4rem;
  font-weight: 600;
  color: var(--accent);
}

.checklist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.7rem;
}

.checklist li {
  display: grid;
  grid-template-columns: 1.35rem 1fr;
  gap: 0.65rem;
  align-items: start;
  color: var(--text-soft);
}

.checklist svg {
  width: 1.35rem;
  height: 1.35rem;
  color: var(--ok);
  margin-top: 0.15rem;
}

.band--ink .checklist li {
  color: color-mix(in srgb, var(--white) 78%, var(--ink));
}

.band--ink .checklist svg {
  color: var(--leaf);
}

.split {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}

@media (min-width: 960px) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split--reverse > :first-child { order: 2; }
}

.trust-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem 1.75rem;
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--text-soft);
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: center;
}

.trust-row li {
  display: inline-flex;
  align-items: center;
  gap: 1.75rem;
}

.trust-row li + li::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--border);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--step--1);
  font-weight: 600;
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
  background: color-mix(in srgb, var(--ok) 16%, transparent);
  color: var(--ok);
}

.pill--warn {
  background: var(--warn-wash);
  color: var(--warn);
}

.note {
  border-left: 3px solid var(--warn);
  background: var(--warn-wash);
  color: var(--text);
  padding: 1rem 1.25rem;
  border-radius: 0 var(--radius) var(--radius) 0;
}

/* ------------------------------------------------------------- 8. exam vignette */

/* The hero shows the product doing its job: a real exam question, mid-sitting. */
.vignette {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.vignette__chrome {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.65rem 1rem;
  border-bottom: 1px solid var(--border-soft);
}

.vignette__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--border);
}

.vignette__url {
  margin-left: 0.6rem;
  font-size: var(--step--1);
  color: var(--text-soft);
  background: var(--surface-alt);
  border-radius: 999px;
  padding: 0.15rem 0.8rem;
}

.vignette__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--border-soft);
  font-size: var(--step--1);
  /* Carries the exam's name, so it is content, not chrome: --text-faint measured
     3.06:1 here against the vignette's white ground. */
  color: var(--text-soft);
}

.vignette__body {
  display: grid;
  gap: 1rem;
  padding: 1.1rem;
}

@media (min-width: 560px) {
  .vignette__body { grid-template-columns: minmax(0, 1fr) 9.5rem; }
}

.vignette__counter {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--text-faint);
}

.vignette__question {
  font-weight: 500;
  margin: 0.5rem 0 0.9rem;
}

.option {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 0.6rem 0.85rem;
  margin-bottom: 0.5rem;
}

.option--chosen {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  font-weight: 600;
}

.option__marker {
  width: 1rem;
  height: 1rem;
  flex: none;
  border: 2px solid var(--border);
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.option--chosen .option__marker {
  border-color: var(--accent);
}

.option--chosen .option__marker::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--accent);
}

.palette {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 4px;
  margin: 0.6rem 0 0.9rem;
  padding: 0;
  list-style: none;
}

.palette li {
  height: 22px;
  border-radius: 5px;
  background: var(--surface-alt);
}

.palette li[data-state="done"] {
  background: color-mix(in srgb, var(--leaf) 45%, transparent);
}

.palette li[data-state="current"] {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  box-shadow: inset 0 0 0 2px var(--accent);
}

.floaty {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 0.8rem 1rem;
  margin-top: 1rem;
  font-size: var(--step--1);
}

.floaty__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  flex: none;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--leaf) 22%, transparent);
  color: var(--ok);
}

.floaty strong {
  display: block;
  color: var(--text);
}

.floaty span {
  color: var(--text-faint);
}

/* --------------------------------------------------------------------- 9. tables */

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

table.data {
  width: 100%;
  min-width: 40rem;
  border-collapse: collapse;
  font-size: 0.97rem;
}

table.data th,
table.data td {
  text-align: left;
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: top;
}

table.data thead th {
  background: var(--surface-alt);
  font-family: var(--font-body);
  font-size: var(--step--1);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-soft);
}

table.data tbody tr:last-child td {
  border-bottom: 0;
}

table.data td .muted {
  display: block;
  color: var(--text-faint);
  font-size: var(--step--1);
  margin-top: 0.2rem;
}

/* ---------------------------------------------------------------------- 10. forms */

.field {
  display: grid;
  gap: 0.4rem;
  margin-bottom: 1.1rem;
}

.field label {
  font-weight: 600;
  font-size: 0.95rem;
}

.field .hint {
  font-size: var(--step--1);
  color: var(--text-faint);
}

.field input,
.field textarea,
.field select {
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
  width: 100%;
}

.field textarea {
  min-height: 9rem;
  resize: vertical;
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--text-faint);
}

.field--invalid input,
.field--invalid textarea {
  border-color: var(--danger);
}

.field__error {
  color: var(--danger);
  font-size: var(--step--1);
  font-weight: 600;
}
/* A radio group where the choice itself is the whole decision, so both options are visible
   without opening anything and each one is a full-width target rather than a 16px circle.
   Added for the newsletter's two tracks - the one form on this site that asks a question
   rather than collecting a value - and kept here beside `.field` rather than in a page-level
   style block, so the next form that needs it does not invent a second version.

   No colour is written here: every value is a token from brand.css, so both themes and the
   focus ring come out right without a dark-mode block of its own. */
.choice-group {
  border: 0;
  margin: 0 0 1.1rem;
  padding: 0;
  display: grid;
  gap: 0.6rem;
}

.choice-group > legend {
  font-weight: 600;
  font-size: 0.95rem;
  padding: 0;
  margin-bottom: 0.4rem;
}

.choice {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 0.75rem;
  padding: 0.85rem 1rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
}

.choice:hover {
  border-color: var(--accent);
}

/* The selected state sits on the whole label, so the card reads as chosen rather than only
   the dot. A browser without `:has()` still shows the checked radio, which is the accessible
   state either way. */
.choice:has(input:checked) {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.choice:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.choice input {
  margin-top: 0.2rem;
  accent-color: var(--accent);
}

.choice__body {
  display: grid;
  gap: 0.15rem;
}

/* The subscribe form is one column of short fields, so it is measured rather than stretched
   across the full shell: a 90-character-wide email input reads as an error state. */
.newsletter-form {
  max-width: 34rem;
}

.newsletter-form > .muted {
  margin-top: 1rem;
}


/* Off-screen rather than display:none, so a bot that fills only visible fields still
   finds it, while a screen reader is told to skip it in the markup. */
.honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.alert {
  border-radius: var(--radius);
  padding: 1rem 1.2rem;
  margin-bottom: 1.5rem;
  border: 1px solid transparent;
}

.alert--ok {
  background: var(--ok-wash);
  border-color: color-mix(in srgb, var(--ok) 40%, transparent);
  color: var(--text);
}

.alert--error {
  background: var(--danger-wash);
  border-color: color-mix(in srgb, var(--danger) 40%, transparent);
  color: var(--text);
}

.alert h2 {
  font-size: var(--step-0);
  font-family: var(--font-body);
  margin-bottom: 0.4rem;
}

/* ---------------------------------------------------------------------- 11. prose */

.prose {
  max-width: 68ch;
}

.prose h2 {
  font-size: var(--step-2);
  margin-top: 2.5rem;
  margin-bottom: 0.75rem;
}

.prose h3 {
  font-size: var(--step-1);
  margin-top: 1.75rem;
  margin-bottom: 0.5rem;
}

.prose li {
  margin-bottom: 0.4rem;
}

.prose dt {
  font-weight: 700;
  margin-top: 1.25rem;
}

.prose dd {
  margin: 0.3rem 0 0;
  color: var(--text-soft);
}

.page-head {
  padding-block: clamp(2.5rem, 6vw, 4rem) clamp(1.5rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--border-soft);
  background: var(--surface-alt);
}

.page-head h1 {
  font-size: var(--step-3);
  margin-top: 0.9rem;
}

.page-head p {
  color: var(--text-soft);
  font-size: var(--step-1);
  max-width: 52ch;
  margin: 1rem 0 0;
}

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  margin: 0 0 0.5rem;
  padding: 0;
  font-size: var(--step--1);
  color: var(--text-faint);
}

.breadcrumb a {
  color: var(--text-soft);
  text-decoration: none;
}

.breadcrumb li + li::before {
  content: "/";
  margin-right: 0.5rem;
  color: var(--border);
}

/* ------------------------------------------------------------------ 12. utilities */

.muted { color: var(--text-soft); }
.faint { color: var(--text-faint); }
.lede  { font-size: var(--step-1); color: var(--text-soft); }
.center { text-align: center; }
.mt-2  { margin-top: 2rem; }

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

.product-hero {
  display: grid;
  gap: 1.25rem;
  align-items: start;
}

@media (min-width: 720px) {
  .product-hero { grid-template-columns: 96px minmax(0, 1fr); }
}

.product-hero img {
  width: 96px;
  height: 96px;
  object-fit: contain;
}

/* An error page has no chrome to fall back on, so it centres itself. */
.error-page {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: 1.25rem;
  padding-block: clamp(4rem, 14vh, 8rem);
}

.error-page__code {
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 800;
  line-height: 1;
  color: var(--accent);
}

/* ------------------------------------------------------- 13. late additions */

.vignette-figure {
  margin: 0;
}

.palette li[data-state="todo"] {
  background: var(--surface-alt);
}

/* On the two dark bands the muted body colour is the wrong side of the contrast line,
   so it is lifted against the ink rather than against paper. */
.band--ink p,
.band--ink .muted,
.band--ink .lede {
  color: color-mix(in srgb, var(--white) 80%, var(--ink));
}

.band--ink .card {
  background: color-mix(in srgb, var(--white) 8%, var(--ink));
  border-color: color-mix(in srgb, var(--white) 18%, var(--ink));
}

.band--ink .table-scroll {
  background: color-mix(in srgb, var(--white) 6%, var(--ink));
  border-color: color-mix(in srgb, var(--white) 18%, var(--ink));
}

.band--ink table.data th,
.band--ink table.data td {
  border-bottom-color: color-mix(in srgb, var(--white) 14%, var(--ink));
  color: color-mix(in srgb, var(--white) 84%, var(--ink));
}

.band--ink table.data thead th {
  background: color-mix(in srgb, var(--white) 10%, var(--ink));
  color: color-mix(in srgb, var(--white) 70%, var(--ink));
}

.band--ink .eyebrow {
  background: color-mix(in srgb, var(--white) 12%, var(--ink));
  color: color-mix(in srgb, var(--white) 76%, var(--ink));
}

.band--ink .stat__label {
  color: color-mix(in srgb, var(--white) 62%, var(--ink));
}

.band--ink .stat__value {
  color: var(--white);
}

.band--ink a.btn {
  text-decoration: none;
}

.band--ink :focus-visible {
  outline-color: var(--leaf);
}

.faq {
  border-top: 1px solid var(--border-soft);
}

.faq > details {
  border-bottom: 1px solid var(--border-soft);
}

.faq > details > summary {
  cursor: pointer;
  font-weight: 600;
  padding: 1rem 0;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

.faq > details > summary::-webkit-details-marker {
  display: none;
}

.faq > details > summary::after {
  content: "+";
  color: var(--accent);
  font-weight: 700;
}

.faq > details[open] > summary::after {
  content: "\2212";
}

.faq > details > div {
  padding-bottom: 1.1rem;
  color: var(--text-soft);
  max-width: 62ch;
}

.contact-layout {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}

@media (min-width: 900px) {
  .contact-layout { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
}

/* ---------------------------------------------------------------- WhatsApp

   Every phone contact on the site is a WhatsApp chat, never a dialler, so the link has
   to LOOK like one at a glance — the number alone would read as a switchboard. The small
   pill carries the word, in the --ok pair because that token is a real green defined in
   both themes; the brand's own --green has no dark-mode counterpart and would go muddy.
   No hover-only affordance: the label is always visible. */
.wa-link {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  text-decoration: none;
}

.wa-link__mark {
  flex: none;
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--ok);
  background: var(--ok-wash);
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
}

/* A phone number must never break across lines: "+234 806 159" on one line and "5590" on
   the next reads as two fragments, and in the footer's narrow fourth column that is exactly
   what happened. The pill may wrap away from the number; the digits may not wrap inside
   themselves. */
.wa-link__number {
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}

.wa-link:hover .wa-link__number,
.wa-link:focus-visible .wa-link__number { color: var(--accent-hover); }

.contact-wa {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.6rem;
}

.contact-wa .muted { display: block; font-size: var(--step--1); }

.definition-list {
  margin: 0;
}

.definition-list dt {
  font-weight: 700;
  margin-top: 1rem;
}

.definition-list dd {
  margin: 0.15rem 0 0;
  color: var(--text-soft);
}

address {
  font-style: normal;
  color: var(--text-soft);
}

/* ==========================================================================
   The homepage ("kinetic" redesign). Every class is prefixed k- and scoped to
   the homepage, except the examina band, which must carry
   class="band band--examina" exactly (the copy-discipline tests key on it)
   and is styled through .k-switch inside it.

   Every colour is a brand token or a color-mix() of tokens with transparent.
   Motion is opt-in three times over: the base markup is the complete, still
   page; JS adds .k-motion to <html> only under (prefers-reduced-motion:
   no-preference); and everything animated also sits behind that media query.
   ========================================================================== */

.k-page {
  overflow-x: clip; /* decorative glows may overshoot; the body must never scroll sideways */
}

.k-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  margin: 0;
}

.k-kicker { color: var(--ok); }

.k-h2 {
  font-size: var(--step-3);
  max-width: 24ch;
  margin-top: .6rem;
}

.k-lede {
  color: var(--text-soft);
  max-width: 58ch;
  font-size: var(--step-1);
  line-height: 1.45;
  margin: 1rem 0 0;
}

.k-btn {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--font-display);
  font-weight: 650;
  font-size: var(--step-0);
  line-height: 1.2;
  padding: .9rem 1.5rem;
  border-radius: 999px;
  border: 1.5px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease,
    color .18s ease, border-color .18s ease;
}
.k-btn:hover { transform: translateY(-2px); }
.k-btn:active { transform: translateY(0); }

.k-btn--leaf { background: var(--leaf); color: var(--ink); }
.k-btn--leaf:hover { box-shadow: 0 10px 30px color-mix(in srgb, var(--leaf) 35%, transparent); }

.k-btn--blue { background: var(--accent); color: var(--on-accent); }
.k-btn--blue:hover { box-shadow: 0 10px 30px color-mix(in srgb, var(--accent) 35%, transparent); }

.k-btn--ghost-dark {
  border-color: color-mix(in srgb, var(--paper) 35%, transparent);
  color: var(--paper);
  background: transparent;
}
.k-btn--ghost-dark:hover { border-color: var(--paper); }

.k-btn--ghost {
  border-color: var(--border);
  color: var(--text);
  background: transparent;
}
.k-btn--ghost:hover { border-color: var(--accent); color: var(--accent); }

/* Reveal choreography. Base state = fully visible; only .k-motion pre-hides. */
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-reveal {
    opacity: 0;
    transform: translateY(26px);
    transition: opacity .7s cubic-bezier(.2, .65, .25, 1), transform .7s cubic-bezier(.2, .65, .25, 1);
    transition-delay: var(--kd, 0s);
  }
  .k-motion .k-reveal.is-in {
    opacity: 1;
    transform: none;
  }
}

/* ==========================================================================
   The shared language — everything below is the reusable half of the homepage,
   lifted out so another page can be built in the same voice without copying
   its markup. docs/design-system.md is the manual; this block is the source.

   Rules that hold for every component here:
     - A component never picks its own ground. It reads the --k-* palette that
       the enclosing .k-section (or .k-cover) sets, so the same markup is right
       on paper, on wash and on ink without a second class.
     - Accents come in through --k-tint, set inline on the item (the homepage's
       product cards do the same), never through a colour literal.
     - Base state is fully visible. Only `.k-motion .k-reveal` hides, only under
       prefers-reduced-motion: no-preference, and .k-motion is added by script.
   ========================================================================== */

/* -------------------------------------------------------------- grounds */

/* The section shell. Paper by default; the modifiers change the ground and,
   with it, the palette every component inside reads. */
.k-section {
  --k-text: var(--text);
  --k-soft: var(--text-soft);
  --k-faint: var(--text-faint);
  --k-rule: var(--border);
  --k-rule-soft: var(--border-soft);
  --k-panel: var(--surface);
  --k-kicker: var(--ok);
  --k-hi: var(--accent);
  position: relative;
  padding-block: clamp(3.5rem, 8vw, 6.5rem);
  color: var(--k-text);
}

.k-section--tight { padding-block: clamp(2.5rem, 5vw, 4rem); }

.k-section--wash {
  background: var(--surface-alt);
  border-block: 1px solid var(--border-soft);
}

.k-section--ink,
.k-cover {
  --k-text: var(--white);
  --k-soft: color-mix(in srgb, var(--paper) 78%, var(--ink));
  --k-faint: color-mix(in srgb, var(--paper) 60%, var(--ink));
  --k-rule: color-mix(in srgb, var(--paper) 22%, transparent);
  --k-rule-soft: color-mix(in srgb, var(--paper) 12%, transparent);
  --k-panel: color-mix(in srgb, var(--paper) 7%, transparent);
  --k-kicker: var(--leaf);
  --k-hi: var(--leaf);
  position: relative;
  background: var(--ink);
  color: var(--paper);
  isolation: isolate;
  overflow: hidden;
}

/* The glow: one blurred disc of brand blue, top right, the way the hero and the
   close do it. --k-glow-x / --k-glow-y move it; it never leaves the section. */
.k-section--ink::before,
.k-cover::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: 46rem;
  height: 46rem;
  right: var(--k-glow-x, -14rem);
  top: var(--k-glow-y, -18rem);
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
  background: color-mix(in srgb, var(--blue) 26%, transparent);
}

.k-section--ink h1, .k-section--ink h2, .k-section--ink h3,
.k-cover h1, .k-cover h2, .k-cover h3 { color: var(--white); }

/* Unclassed links inside an ink ground go leaf; anything with a class of its own
   (a button, a ledger row) has already chosen its colour. */
.k-section--ink a:not([class]),
.k-cover a:not([class]) { color: var(--leaf); }

.k-section--ink :focus-visible,
.k-cover :focus-visible { outline-color: var(--leaf); }

.k-lede { color: var(--k-soft, var(--text-soft)); }
.k-kicker { color: var(--k-kicker, var(--ok)); }

/* ---------------------------------------------------------------- heads */

/* Eyebrow, h2, lede — stacked, measured. */
.k-head {
  max-width: 60rem;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

/* Heading on the left, its paragraph on the right, both sitting on the same
   baseline — the composition the Inspector wall opens with. */
.k-head--split {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
  gap: 1.5rem 3rem;
  align-items: end;
  max-width: none;
}
.k-head--split > p {
  margin: 0;
  max-width: 52ch;
  color: var(--k-soft);
}

/* Heading on the left, an action on the right. */
.k-head--bar {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: 1rem;
  max-width: none;
}

.k-head--center {
  text-align: center;
  margin-inline: auto;
}
.k-head--center .k-h2,
.k-head--center .k-lede { margin-inline: auto; }
.k-head--center .k-eyebrow { justify-content: center; display: flex; }

/* ---------------------------------------------------------------- split */

/* The asymmetric two-column. Never 50/50: one side leads. */
.k-split {
  display: grid;
  grid-template-columns: minmax(0, var(--k-a, 1.05fr)) minmax(0, var(--k-b, .95fr));
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
.k-split--start { align-items: start; }
.k-split--lead  { --k-a: 1.15fr; --k-b: .85fr; }
.k-split--trail { --k-a: .85fr;  --k-b: 1.15fr; }
.k-split--even  { --k-a: 1fr;    --k-b: 1fr; }

/* ---------------------------------------------------------------- prose */

/* Measured running text in this language: headings in ink, paragraphs in slate,
   the opening paragraph a size up. It is what About is made of. */
.k-prose {
  max-width: 62ch;
  color: var(--k-text);
}
.k-prose p,
.k-prose ul,
.k-prose ol { color: var(--k-soft); margin: 0; }
.k-prose :is(h2, h3, p, ul, ol) + :is(p, ul, ol) { margin-top: 1em; }
.k-prose :is(p, ul, ol) + :is(h3) { margin-top: 1.8rem; }
.k-prose .k-h2 + :is(p, ul, ol) { margin-top: 1.1rem; }
.k-prose h3 + :is(p, ul, ol) { margin-top: .5rem; }
.k-prose strong { color: var(--k-text); }
.k-prose h3 { font-size: var(--step-1); }
.k-prose .k-lead {
  font-size: var(--step-1);
  line-height: 1.45;
  color: var(--k-text);
}
.k-prose .k-lead em,
.k-prose h3 em {
  font-style: normal;
  color: var(--k-hi);
}

/* ---------------------------------------------------------------- cover */

/* The interior-page opener: the hero's ink, glow and staggered headline, with
   room for a device on the right and a strip along the bottom edge. */
.k-cover {
  padding: clamp(3.2rem, 8vw, 6.5rem) 0 0;
}
.k-cover--plain { padding-bottom: clamp(3.2rem, 8vw, 6.5rem); }

.k-cover__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
.k-cover__grid--solo { grid-template-columns: minmax(0, 1fr); }
.k-cover__grid--solo > div { max-width: 60rem; }

.k-crumbs {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  list-style: none;
  margin: 0 0 1.2rem;
  padding: 0;
  font-size: var(--step--1);
  color: var(--k-faint);
}
.k-crumbs a { color: var(--k-soft); text-decoration: none; }
.k-crumbs a:hover { color: var(--white); }
.k-crumbs li + li::before {
  content: "/";
  margin-right: .5rem;
  color: var(--k-rule);
}

.k-cover .k-eyebrow { color: var(--gold); }

.k-cover h1 {
  font-size: var(--step-4);
  font-weight: 750;
  margin-top: 1rem;
}
.k-cover h1 .k-line { display: block; }
.k-cover h1 em {
  font-style: normal;
  color: var(--leaf);
}

.k-cover__lede {
  color: var(--k-soft);
  font-size: var(--step-1);
  line-height: 1.5;
  max-width: 46ch;
  margin: 1.3rem 0 0;
}

.k-cover__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: .8rem;
  margin-top: 2rem;
}

/* One figure with its provenance, under the buttons. */
.k-cover__truth {
  margin-top: 2.2rem;
  font-size: var(--step--1);
  color: var(--k-faint);
  display: flex;
  align-items: baseline;
  gap: .6rem;
  max-width: 44ch;
}
.k-cover__truth strong { color: var(--gold); font-weight: 600; flex: none; }

/* The strip along the bottom edge — static, because it carries trust content
   that must never scroll away. */
.k-strip {
  margin-top: clamp(2.5rem, 6vw, 4rem);
  border-top: 1px solid var(--k-rule-soft);
  padding: 1.2rem 0 1.4rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .8rem 2rem;
}
.k-strip__label {
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--k-faint);
  white-space: nowrap;
}
.k-strip ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.4rem;
}
/* An item keeps to one line while it fits and wraps when it cannot.
   `white-space: nowrap` was here to stop a two-word platform label ("Windows 10")
   breaking mid-phrase, and it did — but the strip also carries institution names, and
   "Nigerian Navy Centre of Education and Training Technology (NNCETT)" is 448px wide
   against a 343px shell at 375px. A flex item that may not wrap may not shrink either, so
   at that width the name ran past the page edge and was CLIPPED, not scrollable: the
   about page's whole point is naming the fourteen schools, and four of them were
   unreadable on a phone.

   Wrapping is the right behaviour and costs nothing on a wide screen: with `flex-wrap`
   an item is placed on a line by its max-content width, so it only ever wraps its text
   once it is alone on a line and still too wide. `baseline` keeps the ✱ on the first
   line's baseline rather than centred against a two-line block. */
.k-strip li {
  font-size: var(--step--1);
  color: var(--k-soft);
  display: inline-flex;
  align-items: baseline;
  gap: .45rem;
  max-width: 100%;
}
.k-strip .k-dot { color: var(--gold); font-size: .7rem; }
/* A note under the list rather than beside it. `flex-basis: 100%` puts it on a line of its
   own in a strip that is otherwise a single wrapping row, so the platform names keep their
   rhythm and the rule they follow reads as a sentence under them, not as a fifteenth item. */
.k-strip__note {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--step--1);
  color: var(--k-faint);
  max-width: 62ch;
}
.k-strip__note b { color: var(--k-soft); font-weight: 600; }
/* A strip can carry links (the legal pages' most-read clauses): quiet, underlined,
   white on hover — not the leaf that unclassed links take on ink. */
.k-strip a {
  color: var(--k-soft);
  text-decoration-color: var(--k-rule);
  text-underline-offset: .2em;
}
.k-strip a:hover { color: var(--white); text-decoration-color: var(--white); }

/* The cover's entrance: the same stagger as the homepage hero. */
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-cover .k-line,
  .k-motion .k-cover .k-eyebrow,
  .k-motion .k-cover__lede,
  .k-motion .k-cover__ctas,
  .k-motion .k-cover__truth,
  .k-motion .k-cover__aside {
    opacity: 0;
    transform: translateY(22px);
    animation: k-lift .8s cubic-bezier(.2, .65, .25, 1) forwards;
  }
  .k-motion .k-cover .k-eyebrow { animation-delay: .05s; }
  .k-motion .k-cover .k-line:nth-child(1) { animation-delay: .15s; }
  .k-motion .k-cover .k-line:nth-child(2) { animation-delay: .27s; }
  .k-motion .k-cover__lede { animation-delay: .45s; }
  .k-motion .k-cover__ctas { animation-delay: .58s; }
  .k-motion .k-cover__truth { animation-delay: .7s; }
  .k-motion .k-cover__aside { animation-delay: .35s; }
}
@keyframes k-lift {
  to { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------- device */

/* A window onto the software: bar, body, foot. Surface by default, ink when
   the picture is of a console. Put it inside .k-figure to caption it. */
.k-device {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  color: var(--text);
  --k-dev-soft: var(--text-soft);
  --k-dev-faint: var(--text-faint);
  --k-dev-rule: var(--border-soft);
  /* A device is its own ground. Without this, a component dropped inside a white card that
     is itself sitting on navy would still read the navy palette and paint white text on
     white. The rule that "one markup is right on paper, wash and ink" only holds if the
     card resets the palette the way a section does. */
  --k-text: var(--text);
  --k-soft: var(--text-soft);
  --k-faint: var(--text-faint);
  --k-rule: var(--border);
  --k-rule-soft: var(--border-soft);
  --k-panel: var(--surface);
  --k-kicker: var(--ok);
  --k-hi: var(--accent);
}
.k-device--ink {
  background: var(--ink);
  border-color: color-mix(in srgb, var(--paper) 14%, var(--ink));
  color: var(--paper);
  --k-dev-soft: color-mix(in srgb, var(--paper) 62%, transparent);
  --k-dev-faint: color-mix(in srgb, var(--paper) 55%, transparent);
  --k-dev-rule: color-mix(in srgb, var(--paper) 12%, transparent);
  --k-text: var(--white);
  --k-soft: color-mix(in srgb, var(--paper) 78%, transparent);
  --k-faint: color-mix(in srgb, var(--paper) 60%, transparent);
  --k-rule: color-mix(in srgb, var(--paper) 22%, transparent);
  --k-rule-soft: color-mix(in srgb, var(--paper) 12%, transparent);
  --k-panel: color-mix(in srgb, var(--paper) 7%, transparent);
  --k-kicker: var(--leaf);
  --k-hi: var(--leaf);
}

.k-device__bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .8rem;
  padding: .7rem 1rem;
  border-bottom: 1px solid var(--k-dev-rule);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step--1);
}
.k-device__bar > span { color: var(--k-dev-faint); font-weight: 400; }

.k-device__chip {
  display: inline-flex;
  align-items: center;
  gap: .38rem;
  border-radius: 999px;
  padding: .18rem .6rem;
  font-size: .68rem;
  font-weight: 600;
  white-space: nowrap;
  background: color-mix(in srgb, var(--leaf) 18%, transparent);
  color: var(--ok);
}
.k-device--ink .k-device__chip { color: var(--leaf); }
.k-device__chip::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-device__chip--live::before { animation: k-pulse-dot 1.4s ease-in-out infinite; }
}
@keyframes k-pulse-dot {
  50% { opacity: .35; }
}

.k-device__body { padding: 1rem 1.1rem; }

.k-device__foot {
  padding: .65rem 1rem .8rem;
  margin: 0;
  border-top: 1px solid var(--k-dev-rule);
  font-size: .75rem;
  color: var(--k-dev-soft);
}
.k-device__foot b { color: var(--ok); }
.k-device--ink .k-device__foot b { color: var(--leaf); }

/* The lines: a monospaced log inside a device — one entry per row, a key on the
   left, the event on the right, with tones for what went wrong and what held. */
.k-lines {
  list-style: none;
  margin: 0;
  padding: 1rem 1.1rem 1.2rem;
  font-family: var(--font-mono);
  font-size: .8rem;
  line-height: 1.5;
  display: grid;
  gap: .55rem;
}
.k-lines li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .8rem;
  align-items: baseline;
}
.k-lines li > :first-child {
  color: var(--k-dev-faint);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  white-space: nowrap;
}
.k-lines li > span:last-child { color: inherit; }
.k-lines li[data-tone="warn"] > span:last-child { color: var(--warn); }
.k-lines li[data-tone="ok"]   > span:last-child { color: var(--ok); }
.k-lines li[data-tone="mark"] > span:last-child { font-weight: 700; }
.k-device--ink .k-lines li[data-tone="warn"] > span:last-child { color: var(--gold); }
.k-device--ink .k-lines li[data-tone="ok"]   > span:last-child { color: var(--leaf); }
.k-device--ink .k-lines li[data-tone="mark"] > span:last-child { color: var(--white); }

/* Lines land one after another once their reveal is in. --i is the row index. */
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-reveal .k-lines li { opacity: 0; transform: translateY(6px); }
  .k-motion .k-reveal.is-in .k-lines li {
    animation: k-line-in .45s ease forwards;
    animation-delay: calc(.35s + var(--i, 0) * .22s);
  }
}
@keyframes k-line-in {
  to { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------- figure */

.k-figure { margin: 0; }
.k-figure > figcaption {
  margin-top: .75rem;
  font-size: var(--step--1);
  color: var(--k-soft);
}

/* An annotated figure: the device, then a numbered column of notes that read
   against it. Marks inside the device carry the same numerals. */
.k-annotated {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(12rem, 16rem);
  gap: 1.4rem 2rem;
  align-items: start;
}

.k-notes {
  list-style: none;
  counter-reset: k-note;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .9rem;
}
.k-notes > li {
  counter-increment: k-note;
  display: grid;
  grid-template-columns: 1.7rem minmax(0, 1fr);
  gap: .7rem;
  font-size: var(--step--1);
  color: var(--k-soft);
  line-height: 1.5;
}
.k-notes > li::before {
  content: counter(k-note, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--k-hi);
  padding-top: .15em;
}
.k-notes strong {
  display: block;
  font-family: var(--font-display);
  color: var(--k-text);
}

.k-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding-inline: .3rem;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: .68rem;
  font-weight: 600;
  background: var(--accent);
  color: var(--on-accent);
}

/* --------------------------------------------------------------- ledger */

/* Rows ruled like a register. The plain form is a list of names in the display
   face; --rows adds an icon, a term, its description and a destination. */
.k-ledger {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  align-content: start;
  border-top: 1px solid var(--k-rule);
}
.k-ledger > li {
  border-bottom: 1px solid var(--k-rule);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1rem + 1.4vw, 1.9rem);
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--k-text);
}
.k-ledger > li > :not(a) {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 0;
}
.k-ledger small {
  font-size: var(--step--1);
  font-weight: 400;
  color: var(--gold);
}

/*
 * A priced ledger row that can be bought from.
 *
 * The row is `space-between`, which puts a two-child row's price hard right. A third child —
 * the Buy for that tier — would strand the price in the middle of the row, so the label takes
 * the slack instead and price and button travel together at the end. On a phone the button
 * drops under the price rather than squeezing the tier name to two words a line.
 */
.k-ledger__buy {
  flex: 0 0 auto;
  align-self: center;
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0;
  text-decoration: none;
  color: var(--k-bg);
  background: var(--blue);
  border-radius: 999px;
  padding: .38rem 1.05rem;
  transition: background .15s ease, transform .15s ease;
}
.k-ledger__buy:hover,
.k-ledger__buy:focus-visible { background: var(--blue-dark); transform: translateY(-1px); }
.k-ledger > li > div > span:first-child { flex: 1 1 auto; }

@media (max-width: 34rem) {
  .k-ledger > li > :not(a) { flex-wrap: wrap; }
  .k-ledger__buy { margin-left: auto; }
}

.k-ledger__link {
  display: grid;
  grid-template-columns: 3rem minmax(0, .8fr) minmax(0, 1.2fr) auto;
  align-items: center;
  gap: 1rem 1.4rem;
  padding: 1.05rem 0;
  color: inherit;
  text-decoration: none;
  transition: padding-left .2s ease;
}
.k-ledger__link:hover { padding-left: .4rem; }
.k-ledger__link img {
  width: 3rem;
  height: 3rem;
  border-radius: 11px;
  object-fit: contain;
}
.k-ledger__term { font-size: var(--step-1); }
.k-ledger__desc {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--step--1);
  line-height: 1.5;
  color: var(--k-soft);
}
.k-ledger__go {
  font-size: var(--step--1);
  font-weight: 650;
  color: var(--k-hi);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
}
.k-ledger__go::after {
  content: "→";
  transition: transform .2s ease;
}
.k-ledger__link:hover .k-ledger__go::after { transform: translateX(4px); }

/* ------------------------------------------------------------- numbered */

/* Numbered cards: the objection card. A counter in the margin, a tinted left
   edge, a heading whose emphasised phrase takes the tint. Set --k-tint on the li. */
.k-numbered {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  counter-reset: k-num;
}
.k-numbered > li {
  counter-increment: k-num;
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--k-tint, var(--accent));
  border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: var(--shadow);
  padding: 1.1rem 1.2rem 1.2rem 3.4rem;
  color: var(--text);
}
.k-numbered > li::before {
  content: "0" counter(k-num);
  position: absolute;
  left: 1.1rem;
  top: 1.25rem;
  font-family: var(--font-mono);
  font-size: .8rem;
  color: var(--text-faint);
}
.k-numbered h3 { font-size: var(--step-1); }
.k-numbered h3 em {
  font-style: normal;
  color: var(--k-tint, var(--accent));
}
.k-numbered p {
  margin: .55rem 0 0;
  color: var(--text-soft);
  font-size: var(--step--1);
  line-height: 1.55;
}

/* -------------------------------------------------------------- metrics */

/* A figure with its provenance: the note says where the numbers came from, and
   sits above them so it is read first. Set --k-tint per metric. */
.k-metrics {
  border-top: 1px solid var(--k-rule);
  padding-top: 1.4rem;
}
.k-metrics__note {
  margin: 0 0 1.2rem;
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--k-soft);
}
.k-metrics__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: clamp(1.2rem, 3vw, 2.4rem);
}
.k-metric > i {
  display: block;
  width: 2.4rem;
  height: 4px;
  border-radius: 2px;
  margin-bottom: .9rem;
  background: var(--k-tint, var(--accent));
}
.k-metric > b {
  display: block;
  font-family: var(--font-display);
  font-weight: 750;
  font-size: clamp(2.1rem, 1.4rem + 2.6vw, 3.4rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--k-text);
}
.k-metric > span {
  display: block;
  margin-top: .5rem;
  font-size: var(--step--1);
  color: var(--k-soft);
  max-width: 22ch;
}

/* -------------------------------------------------------------- callout */

/* The offer card and the licence note: one thing said in a box with a coloured
   edge. Solid by default; --soft tints its ground with the accent instead. */
.k-callout {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-left: 4px solid var(--k-tint, var(--leaf));
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.1rem 1.3rem;
  color: var(--text);
}
.k-callout > b,
.k-callout > strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-0);
}
.k-callout p {
  margin: .4rem 0 0;
  font-size: var(--step--1);
  color: var(--text-soft);
}
.k-callout--soft {
  --k-tint: var(--gold);
  background: color-mix(in srgb, var(--k-tint) 12%, var(--surface));
  border-left-width: 3px;
  box-shadow: none;
}

/* ---------------------------------------------------------------- lists */

/* Ticked facts, flowing into as many columns as fit. */
.k-checks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: .6rem 1.4rem;
  font-size: var(--step--1);
}
.k-checks--stack { grid-template-columns: minmax(0, 1fr); }
.k-checks li {
  display: flex;
  gap: .55rem;
  align-items: baseline;
  color: var(--k-soft);
}
.k-checks li::before {
  content: "✓";
  color: var(--k-kicker);
  font-weight: 700;
  flex: none;
}

/* A claim and its explanation, stacked. */
.k-points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .8rem;
}
.k-points li { display: grid; gap: .15rem; }
.k-points strong { font-family: var(--font-display); color: var(--k-text); }
.k-points span { color: var(--k-soft); font-size: var(--step--1); }

/* A labelled hairline: structure between two ideas, with the label in the
   eyebrow voice. --left keeps the label at the margin. */
.k-rule {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-block: clamp(2rem, 4vw, 3rem);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--k-soft);
}
.k-rule::before,
.k-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--k-rule);
}
.k-rule--left::before { display: none; }

/* ---------------------------------------------------------------- close */

/* The closing call: centred, on ink, headline with one emphasised phrase. */
/* The close is the one section that breathes wider than the rest: it is the end of the
   argument, and it is the homepage's own closing rhythm, so every page's close matches the
   homepage's rather than sitting a step short of it. */
.k-close {
  text-align: center;
  padding-block: clamp(4rem, 10vw, 7.5rem);
  --k-glow-x: auto;
  --k-glow-y: auto;
}
.k-close::before {
  width: 42rem;
  height: 42rem;
  left: 50%;
  bottom: -30rem;
  top: auto;
  right: auto;
  transform: translateX(-50%);
  filter: blur(100px);
  background: color-mix(in srgb, var(--blue) 30%, transparent);
}
.k-close .k-eyebrow { display: flex; justify-content: center; }
.k-close h2 {
  font-size: var(--step-3);
  max-width: 26ch;
  margin: .8rem auto 0;
}
.k-close h2 em { font-style: normal; color: var(--gold); }
.k-close > .shell > div > p,
.k-close__text {
  margin: 1.2rem auto 0;
  max-width: 52ch;
  color: var(--k-soft);
}
.k-close__row {
  margin-top: 2.2rem;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: .9rem;
}
.k-close__small {
  margin-top: 1.6rem;
  font-size: var(--step--1);
  color: var(--k-faint);
}
.k-close__small a { color: var(--leaf); }

/* ------------------------------------------------------------- document */

/* A long document — the legal pages. Not a marketing composition: a contents
   column beside a measured article of numbered clauses, so a reader who came
   for one answer (data, refunds, liability) can find it, read it and cite it.
   The contents column is a <details>: open by default so it works with no
   script, collapsed on a phone by the small script in site.legal.document,
   sticky beside the article on a wide screen. Lives on paper; reads the
   ground palette like everything else. */
.k-doc {
  display: grid;
  grid-template-columns: minmax(12rem, 15rem) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5.5rem);
  align-items: start;
}

.k-doc__toc {
  position: sticky;
  top: calc(68px + 1.5rem); /* below the sticky header */
  font-size: var(--step--1);
}
.k-doc__toc summary {
  list-style: none;
  cursor: default;
  pointer-events: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding-bottom: .8rem;
  border-bottom: 1px solid var(--k-rule);
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--k-faint);
}
.k-doc__toc summary::-webkit-details-marker { display: none; }
.k-doc__toc summary::after {
  content: "+";
  display: none;
  font-family: var(--font-mono);
  font-size: 1rem;
  font-weight: 400;
  color: var(--k-hi);
}
.k-doc__toc[open] summary::after { content: "−"; }

.k-doc__toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
}
.k-doc__toc a {
  display: grid;
  grid-template-columns: 2.1rem minmax(0, 1fr);
  gap: .5rem;
  align-items: baseline;
  padding: .5rem 0;
  border-bottom: 1px solid var(--k-rule-soft);
  color: var(--k-soft);
  text-decoration: none;
  line-height: 1.35;
  transition: color .15s ease;
}
.k-doc__toc a:hover { color: var(--k-text); }
.k-doc__toc ol ol a {
  padding: .3rem 0 .3rem 2.6rem;
  border-bottom: 0;
  font-size: .8rem;
}
.k-doc__toc ol ol {
  padding-bottom: .3rem;
  border-bottom: 1px solid var(--k-rule-soft);
}
/* The clause in view, marked by the script; nothing without it. */
.k-doc__toc a[aria-current="location"] { color: var(--k-text); font-weight: 600; }
.k-doc__toc a[aria-current="location"] .k-doc__n { color: var(--k-hi); }

/* A clause number in the structure voice. */
.k-doc__n {
  font-family: var(--font-mono);
  font-size: .76rem;
  color: var(--k-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The article: a proper measure, and a rhythm the eye can navigate. */
.k-doc__body {
  max-width: 66ch;
  color: var(--k-text);
}
.k-doc__intro {
  margin: 0;
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--k-text);
}
.k-doc__intro em {
  font-style: normal;
  color: var(--k-hi);
}
.k-doc__stamp {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.6rem;
  margin: 1.4rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--k-rule);
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--k-faint);
}
.k-doc__stamp b { font-weight: 500; color: var(--k-soft); }

.k-clause {
  position: relative;
  margin-top: clamp(2.2rem, 4vw, 3.2rem);
  padding-top: clamp(2rem, 4vw, 2.8rem);
  border-top: 1px solid var(--k-rule);
  scroll-margin-top: calc(68px + 1.5rem);
}
.k-clause h2 {
  position: relative;
  font-size: var(--step-2);
  padding-left: 3.4rem;
}
/* The number is a link to its own clause, so a clause can be cited by URL;
   :target lights it up when someone arrives on that citation. */
.k-clause__num {
  position: absolute;
  left: 0;
  top: .2em;
  display: inline-flex;
  align-items: center;
  padding: .12rem .5rem;
  border: 1px solid var(--k-rule);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: .76rem;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--k-hi);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.k-clause__num:hover,
.k-clause:target .k-clause__num {
  background: var(--k-hi);
  border-color: var(--k-hi);
  color: var(--on-accent);
}
.k-clause h3 {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  margin-top: 1.7rem;
  font-size: var(--step-1);
}
.k-clause h3 .k-doc__n { color: var(--k-hi); }
.k-clause p,
.k-clause ul,
.k-clause ol {
  margin: 0;
  color: var(--k-soft);
  line-height: 1.7;
}
.k-clause h2 + :is(p, ul, ol) { margin-top: 1rem; }
.k-clause h3 + :is(p, ul, ol) { margin-top: .5rem; }
.k-clause :is(p, ul, ol) + :is(p, ul, ol) { margin-top: 1em; }
.k-clause ul,
.k-clause ol { padding-left: 1.4rem; }
.k-clause li + li { margin-top: .45rem; }
.k-clause li::marker { color: var(--k-hi); }
.k-clause strong { color: var(--k-text); }

/* A term and what it means: the retention periods and the data-subject rights.

   Deliberately a <dl> and not a <table>. Both are two-column data, and a two-column
   table of "how long we keep your bank receipt" is unreadable at 375px — the second
   column either wraps to one word a line or forces the page to scroll sideways. A
   description list reflows to a single column for free, and it is the more honest
   markup anyway: these are terms and their explanations, not a grid of values. */
.k-clause dl { margin: 0; }
.k-clause h2 + dl { margin-top: 1rem; }
.k-clause :is(p, ul, ol) + dl,
.k-clause dl + :is(p, ul, ol) { margin-top: 1em; }
.k-clause dt {
  margin-top: 1.2rem;
  color: var(--k-text);
  font-weight: 500;
  line-height: 1.5;
}
.k-clause dl > dt:first-child { margin-top: 0; }
.k-clause dt b { color: var(--k-hi); font-weight: 600; }
.k-clause dd {
  margin: .4rem 0 0;
  padding-left: 1rem;
  border-left: 1px solid var(--k-rule);
  color: var(--k-soft);
  line-height: 1.7;
}

/* A defined term: the first time a word the agreement turns on appears. */
.k-doc dfn {
  font-style: normal;
  font-weight: 600;
  color: var(--k-text);
  text-decoration: underline dotted;
  text-decoration-color: var(--k-hi);
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
}

.k-doc__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: 1.4rem;
  border-top: 1px solid var(--k-rule);
  font-size: var(--step--1);
  color: var(--k-faint);
}

/* Answers in a hurry: a question, the answer as the document gives it, and the
   clause that governs. Cards on the surface; --k-tint colours the top edge. */
.k-answers {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
}
.k-answers > li {
  display: grid;
  align-content: start;
  gap: .55rem;
  padding: 1.15rem 1.25rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-top: 3px solid var(--k-tint, var(--accent));
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: var(--shadow);
  color: var(--text);
}
.k-answers h3 {
  font-size: var(--step-0);
  line-height: 1.3;
}
.k-answers p {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--text-soft);
}
.k-answers a {
  margin-top: .3rem;
  justify-self: start;
  font-family: var(--font-mono);
  font-size: .76rem;
  line-height: 1.5;
  color: var(--accent);
  text-decoration: none;
}
.k-answers a::after {
  content: "→";
  display: inline-block;
  margin-left: .4rem;
  transition: transform .2s ease;
}
.k-answers a:hover { text-decoration: underline; }
.k-answers a:hover::after { transform: translateX(4px); }

@media (max-width: 940px) {
  .k-doc { grid-template-columns: minmax(0, 1fr); }
  .k-doc__toc { position: static; }
  .k-doc__toc summary { cursor: pointer; pointer-events: auto; }
  .k-doc__toc summary::after { display: block; }
  .k-doc__toc ol { padding-top: .3rem; }
  .k-clause h2 { padding-left: 3rem; }
}

/* Printed, a document is the document: no chrome, no ink ground, no contents
   column, and every clause keeps its number. */
@media print {
  .site-header,
  .site-footer,
  .skip-link,
  .k-doc__toc,
  .k-close,
  .k-strip,
  .k-cover__ctas { display: none !important; }
  .k-cover,
  .k-section--ink,
  .k-section--wash {
    background: none;
    color: var(--ink);
    border: 0;
  }
  .k-cover::before,
  .k-section--ink::before { display: none; }
  .k-cover h1,
  .k-cover .k-eyebrow { color: var(--ink); }
  .k-doc__body { max-width: none; }
  .k-clause { break-inside: avoid-page; }
  .k-answers > li { box-shadow: none; }
}

/* ---------------------------------------------------------------- files */

/* A register of downloadable files: the name and what it is for on the left, the
   version, platform and size in mono beside it, the action on the right. The size
   is the loudest fact on the row on purpose — on a metered line it is the decision.
   Rows are static: a reader is checking them against what they came for. */
.k-files {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--k-rule);
  container-type: inline-size;
}
.k-file {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: .5rem 1.6rem;
  align-items: center;
  padding: .95rem 0 1rem;
  border-bottom: 1px solid var(--k-rule);
}
.k-file__name {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-0);
  line-height: 1.25;
  color: var(--k-text);
}
.k-file__tag {
  display: inline-block;
  margin-left: .55rem;
  vertical-align: .12em;
  padding: .14rem .48rem;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--k-hi);
  background: color-mix(in srgb, var(--k-hi) 14%, transparent);
}
.k-file__tag[data-tone="ok"] {
  color: var(--k-kicker);
  background: color-mix(in srgb, var(--k-kicker) 16%, transparent);
}
.k-file__tag[data-tone="warn"] {
  color: var(--warn);
  background: color-mix(in srgb, var(--gold) 22%, transparent);
}
.k-section--ink .k-file__tag[data-tone="warn"] { color: var(--gold); }
.k-file__note {
  display: block;
  margin: .25rem 0 0;
  max-width: 54ch;
  font-size: var(--step--1);
  line-height: 1.5;
  color: var(--k-soft);
}
.k-file__meta {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .3rem 1.1rem;
  font-family: var(--font-mono);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.k-file__meta > div { display: flex; gap: .4rem; align-items: baseline; }
.k-file__meta dt { color: var(--k-faint); }
.k-file__meta dd { margin: 0; color: var(--k-soft); }
.k-file__meta dd.k-file__size {
  font-weight: 700;
  color: var(--k-text);
}
.k-file > .k-btn,
.k-file > .external { justify-self: end; }

/* In a narrow column (a split, a phone) the meta drops under the name; the
   media query below does the same for browsers without container queries. */
@container (max-width: 44rem) {
  .k-file { grid-template-columns: minmax(0, 1fr) auto; }
  .k-file > .k-btn,
  .k-file > .external { grid-column: 2; grid-row: 1; align-self: start; }
  .k-file__meta { grid-column: 1 / -1; grid-row: 2; }
}

/* The pill at a row's size. */
.k-btn--small {
  padding: .55rem 1.05rem;
  font-size: var(--step--1);
}

/* ----------------------------------------------------------------- fold */

/* A disclosure in the language: a display-face summary with a mono key and a
   plus that turns into a minus. For an archive a reader may want and should not
   have to scroll past — earlier releases, old editions. Not for anything the
   page is arguing from; that stays open. */
.k-fold {
  border-bottom: 1px solid var(--k-rule);
}
.k-fold:first-of-type { border-top: 1px solid var(--k-rule); }
.k-fold > summary {
  list-style: none;
  cursor: pointer;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: .4rem 1.1rem;
  align-items: baseline;
  padding: 1rem 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-1);
  line-height: 1.2;
  color: var(--k-text);
}
.k-fold > summary::-webkit-details-marker { display: none; }
.k-fold > summary::after {
  content: "+";
  color: var(--k-hi);
  font-weight: 700;
}
.k-fold[open] > summary::after { content: "\2212"; }
.k-fold > summary:focus-visible {
  outline: 2px solid var(--k-hi);
  outline-offset: 3px;
}
.k-fold__key {
  font-family: var(--font-mono);
  font-size: .8rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  color: var(--k-hi);
}
.k-fold__meta {
  display: block;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--step--1);
  color: var(--k-soft);
}
.k-fold__body { padding: 0 0 1.4rem; }
.k-fold__body > p {
  margin: 0 0 1rem;
  max-width: 62ch;
  font-size: var(--step--1);
  color: var(--k-soft);
}

/* Numbered cards side by side, for three parallel situations a reader picks from. */
.k-numbered--row {
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

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

@media (max-width: 940px) {
  .k-split,
  .k-head--split,
  .k-cover__grid { grid-template-columns: minmax(0, 1fr); }

  .k-split--flip > :last-child { order: -1; }
  .k-annotated { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 620px) {
  .k-metric > span { max-width: none; }

  .k-ledger__link {
    grid-template-columns: 2.4rem minmax(0, 1fr);
    gap: .5rem .9rem;
  }
  .k-ledger__link img { width: 2.4rem; height: 2.4rem; }
  .k-ledger__desc,
  .k-ledger__go { grid-column: 2; }

  .k-lines { font-size: .72rem; }

  .k-file { grid-template-columns: minmax(0, 1fr) auto; }
  .k-file > .k-btn,
  .k-file > .external { grid-column: 2; grid-row: 1; align-self: start; }
  .k-file__meta { grid-column: 1 / -1; grid-row: 2; }
}

/* ---------------------------------------------------------------- 1 · hero */

.k-hero {
  position: relative;
  background: var(--ink);
  color: var(--paper);
  padding: clamp(3.2rem, 8vw, 6.5rem) 0 0;
  isolation: isolate;
}

.k-hero::before,
.k-hero::after {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
}
.k-hero::before {
  width: 46rem; height: 46rem;
  right: -14rem; top: -18rem;
  background: color-mix(in srgb, var(--blue) 26%, transparent);
}
.k-hero::after {
  width: 30rem; height: 30rem;
  left: -12rem; bottom: -8rem;
  background: color-mix(in srgb, var(--leaf) 14%, transparent);
}

.k-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

.k-hero .k-eyebrow { color: var(--gold); }

.k-hero h1 {
  font-size: var(--step-4);
  font-weight: 750;
  margin-top: 1rem;
  color: var(--white);
}
.k-hero h1 .k-line { display: block; }
.k-hero h1 em {
  font-style: normal;
  color: var(--leaf);
}

.k-hero__lede {
  color: color-mix(in srgb, var(--paper) 78%, var(--ink));
  font-size: var(--step-1);
  line-height: 1.5;
  max-width: 46ch;
  margin: 1.3rem 0 0;
}

.k-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: .8rem;
  margin-top: 2rem;
}

.k-hero__truth {
  margin-top: 2.2rem;
  font-size: var(--step--1);
  color: color-mix(in srgb, var(--paper) 62%, var(--ink));
  display: flex;
  align-items: baseline;
  gap: .6rem;
  max-width: 44ch;
}
.k-hero__truth strong { color: var(--gold); font-weight: 600; }

/* staggered line entrance for the headline */
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-hero .k-line,
  .k-motion .k-hero__lede,
  .k-motion .k-hero__ctas,
  .k-motion .k-hero__truth,
  .k-motion .k-hero .k-eyebrow,
  .k-motion .k-exam {
    opacity: 0;
    transform: translateY(22px);
    animation: k-rise .8s cubic-bezier(.2, .65, .25, 1) forwards;
  }
  .k-motion .k-hero .k-eyebrow { animation-delay: .05s; }
  .k-motion .k-hero .k-line:nth-child(1) { animation-delay: .15s; }
  .k-motion .k-hero .k-line:nth-child(2) { animation-delay: .27s; }
  .k-motion .k-hero__lede { animation-delay: .45s; }
  .k-motion .k-hero__ctas { animation-delay: .58s; }
  .k-motion .k-hero__truth { animation-delay: .7s; }
  .k-motion .k-exam { animation-delay: .35s; }
}

@keyframes k-rise {
  to { opacity: 1; transform: none; }
}

/* the exam client vignette */
.k-exam {
  background: color-mix(in srgb, var(--paper) 6%, var(--ink));
  border: 1px solid color-mix(in srgb, var(--paper) 14%, transparent);
  border-radius: var(--radius-lg);
  box-shadow: 0 30px 80px color-mix(in srgb, var(--ink) 60%, transparent);
  overflow: hidden;
  font-size: var(--step--1);
  margin: 0;
}

.k-exam__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .8rem;
  padding: .7rem 1rem;
  border-bottom: 1px solid color-mix(in srgb, var(--paper) 12%, transparent);
  color: color-mix(in srgb, var(--paper) 80%, var(--ink));
  font-family: var(--font-display);
  font-weight: 600;
}

.k-exam__lan {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--leaf);
  white-space: nowrap;
}
.k-exam__lan i {
  width: .55rem; height: .55rem;
  border-radius: 50%;
  background: var(--leaf);
  flex: none;
}
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-exam__lan i { animation: k-pulse 2.4s ease-in-out infinite; }
}
@keyframes k-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--leaf) 55%, transparent); }
  55% { box-shadow: 0 0 0 7px transparent; }
}

.k-exam__meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: .75rem 1rem .1rem;
  color: color-mix(in srgb, var(--paper) 60%, var(--ink));
}
.k-exam__timer {
  font-family: var(--font-mono);
  font-size: .95rem;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

.k-exam__q {
  padding: .5rem 1rem .4rem;
  margin: 0;
  color: var(--paper);
  font-size: var(--step-0);
  font-weight: 500;
  min-height: 3.2em;
}

.k-exam__opts {
  list-style: none;
  margin: 0;
  padding: .2rem 1rem 1rem;
  display: grid;
  gap: .45rem;
}
.k-exam__opts li {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .55rem .8rem;
  border: 1px solid color-mix(in srgb, var(--paper) 14%, transparent);
  border-radius: var(--radius);
  color: color-mix(in srgb, var(--paper) 82%, var(--ink));
  transition: border-color .25s ease, background-color .25s ease;
}
.k-exam__opts .k-opt__key {
  font-family: var(--font-mono);
  font-size: .72rem;
  color: color-mix(in srgb, var(--paper) 55%, var(--ink));
}
.k-exam__opts li.is-picked {
  border-color: var(--leaf);
  background: color-mix(in srgb, var(--leaf) 14%, transparent);
  color: var(--paper);
}
.k-exam__opts li.is-picked .k-opt__key { color: var(--leaf); }

.k-exam__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .7rem 1rem;
  border-top: 1px solid color-mix(in srgb, var(--paper) 12%, transparent);
  color: color-mix(in srgb, var(--paper) 60%, var(--ink));
}
.k-exam__saved {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  color: var(--leaf);
  opacity: 1;
  transition: opacity .4s ease;
}
.k-motion .k-exam__saved[data-idle] { opacity: .35; }

.k-exam__caption {
  margin: .8rem 0 0;
  text-align: center;
  font-size: .8rem;
  color: color-mix(in srgb, var(--paper) 55%, var(--ink));
}

/* the named halls, along the hero's bottom edge — static, on purpose:
   trust content must not scroll away, and it must all be there with motion off */
.k-schools-strip {
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
  border-top: 1px solid color-mix(in srgb, var(--paper) 12%, transparent);
  padding: 1.1rem 0 1.3rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .4rem 1.8rem;
}
.k-schools-strip__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--paper) 56%, var(--ink));
  white-space: nowrap;
}
.k-schools-strip ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1.6rem;
}
.k-schools-strip li {
  display: inline-flex;
  align-items: baseline;
  gap: .55rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step--1);
  letter-spacing: .04em;
  color: color-mix(in srgb, var(--paper) 66%, var(--ink));
  white-space: nowrap;
}
.k-schools-strip .k-dot { color: var(--gold); font-size: .7rem; }

/* -------------------------------------------------- 2 · the hard questions */

.k-fail {
  padding: clamp(3.5rem, 8vw, 6.5rem) 0;
  background: var(--bg);
}

.k-fail__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}

.k-fail__intro .k-log { margin-top: clamp(1.6rem, 3.5vw, 2.4rem); }

/* the invigilator's event log: one bad morning, replayed */
.k-log {
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.k-log__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .8rem;
  padding: .65rem 1rem;
  border-bottom: 1px solid color-mix(in srgb, var(--paper) 12%, transparent);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step--1);
}
.k-log__bar span { color: color-mix(in srgb, var(--paper) 55%, transparent); font-weight: 400; }
.k-log ol {
  list-style: none;
  margin: 0;
  padding: 1rem 1.1rem 1.2rem;
  font-family: var(--font-mono);
  font-size: .8rem;
  line-height: 1.5;
  display: grid;
  gap: .55rem;
}
.k-log li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .8rem;
  align-items: baseline;
}
.k-log time {
  color: color-mix(in srgb, var(--paper) 62%, transparent);
  font-variant-numeric: tabular-nums;
}
.k-log li span { color: color-mix(in srgb, var(--paper) 85%, transparent); }
.k-log li[data-tone="warn"] span { color: var(--gold); }
.k-log li[data-tone="ok"] span   { color: var(--leaf); }
.k-log li[data-tone="mark"] span { color: var(--white); font-weight: 700; }

/* replay: the lines land one after another once the section is on screen */
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-log li { opacity: 0; transform: translateY(6px); }
  .k-motion .k-fail__intro.is-in .k-log li {
    animation: k-logline .45s ease forwards;
    animation-delay: calc(.4s + var(--i) * .4s);
  }
}
@keyframes k-logline {
  to { opacity: 1; transform: none; }
}

/* the numbered objections */
.k-asks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  counter-reset: ask;
}
.k-ask {
  counter-increment: ask;
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: var(--shadow);
  padding: 1.1rem 1.2rem 1.2rem 3.4rem;
}
.k-ask:nth-child(2) { border-left-color: var(--gold); }
.k-ask:nth-child(3) { border-left-color: var(--leaf); }
.k-ask:nth-child(4) { border-left-color: var(--danger); }
.k-ask::before {
  content: "0" counter(ask);
  position: absolute;
  left: 1.1rem;
  top: 1.25rem;
  font-family: var(--font-mono);
  font-size: .8rem;
  color: var(--text-faint);
}
.k-ask h3 {
  font-size: var(--step-1);
}
.k-ask h3 em {
  font-style: normal;
  color: var(--accent);
}
.k-ask:nth-child(2) h3 em { color: var(--warn); }
.k-ask:nth-child(3) h3 em { color: var(--ok); }
.k-ask:nth-child(4) h3 em { color: var(--danger); }
.k-ask p {
  margin: .55rem 0 0;
  color: var(--text-soft);
  font-size: var(--step--1);
  line-height: 1.55;
}

.k-fail__proof {
  margin-top: 2rem;
  font-size: var(--step--1);
  color: var(--text-faint);
  max-width: 62ch;
}
.k-fail__proof a { color: var(--accent); }

/* -------------------------------------------------- 3 · the inspector wall */

.k-hall {
  background:
    radial-gradient(1100px 520px at 85% -10%,
      color-mix(in srgb, var(--blue) 20%, transparent), transparent 60%),
    var(--ink);
  color: var(--paper);
  padding: clamp(3.5rem, 8vw, 6.5rem) 0;
}
.k-hall h2 { color: var(--white); }
.k-hall .k-kicker { color: var(--leaf); }

.k-hall__head {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
  gap: 1.5rem 3rem;
  align-items: end;
  margin-bottom: clamp(1.6rem, 3vw, 2.4rem);
}
.k-hall__head > p {
  margin: 0;
  max-width: 52ch;
  color: color-mix(in srgb, var(--paper) 78%, transparent);
}

.k-hall__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 250px;
  gap: 1.1rem;
}

.k-wall {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: .55rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.k-wall li {
  background: color-mix(in srgb, var(--paper) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--paper) 13%, transparent);
  border-radius: 8px;
  padding: .5rem .55rem .55rem;
  font-size: .68rem;
  display: grid;
  gap: .35rem;
}
.k-wall b {
  font-family: var(--font-mono);
  font-weight: 400;
  color: color-mix(in srgb, var(--paper) 60%, transparent);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.k-wall b::after {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--leaf);
}
.k-wall li[data-state="resume"] b::after { background: var(--gold); }
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-wall li[data-state="resume"] b::after {
    animation: k-pulse 1.4s ease-in-out infinite;
  }
}
.k-wall i {
  font-style: normal;
  display: block;
  height: 4px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--paper) 14%, transparent);
  position: relative;
  overflow: hidden;
}
.k-wall i::after {
  content: "";
  position: absolute;
  inset: 0;
  width: var(--w, 50%);
  border-radius: 4px;
  background: var(--blue);
}
.k-wall li[data-state="resume"] i::after { background: var(--gold); }
.k-wall li span { color: color-mix(in srgb, var(--paper) 62%, transparent); }
.k-wall li[data-state="resume"] span { color: var(--gold); }

.k-hall__side {
  display: grid;
  gap: .8rem;
  align-content: start;
}
.k-tally {
  border: 1px solid color-mix(in srgb, var(--paper) 14%, transparent);
  border-radius: var(--radius);
  padding: .8rem .95rem;
}
.k-tally strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.1;
  color: var(--white);
  font-variant-numeric: tabular-nums;
}
.k-tally span { font-size: var(--step--1); color: color-mix(in srgb, var(--paper) 60%, transparent); }
.k-tally[data-tone="ok"] strong { color: var(--leaf); }
.k-tally[data-tone="warn"] strong { color: var(--gold); }

.k-hall__powers {
  list-style: none;
  margin: 1.8rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: .6rem 1.4rem;
  font-size: var(--step--1);
}
.k-hall__powers li {
  display: flex;
  gap: .55rem;
  align-items: baseline;
  color: color-mix(in srgb, var(--paper) 75%, transparent);
}
.k-hall__powers li::before {
  content: "✓";
  color: var(--leaf);
  font-weight: 700;
  flex: none;
}

/* ------------------------------------------------------- 4 · the results */

.k-results {
  padding: clamp(3.5rem, 8vw, 6.5rem) 0;
  background: var(--surface-alt);
  border-block: 1px solid var(--border-soft);
}

.k-results__grid {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  gap: clamp(1.8rem, 4vw, 3.4rem);
  align-items: center;
}

.k-results__points {
  list-style: none;
  margin: 1.4rem 0 0;
  padding: 0;
  display: grid;
  gap: .8rem;
}
.k-results__points li { display: grid; gap: .15rem; }
.k-results__points strong { font-family: var(--font-display); }
.k-results__points span { color: var(--text-soft); font-size: var(--step--1); }

.k-board {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.k-board__bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .8rem;
  padding: .7rem 1rem;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step--1);
}
.k-board__chip {
  display: inline-flex;
  align-items: center;
  gap: .38rem;
  border-radius: 999px;
  padding: .18rem .6rem;
  font-size: .68rem;
  font-weight: 600;
  white-space: nowrap;
  background: color-mix(in srgb, var(--leaf) 18%, transparent);
  color: var(--ok);
}
.k-board__chip::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ok);
}
.k-board table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
}
.k-board th, .k-board td {
  text-align: left;
  padding: .55rem 1rem;
  border-top: 1px solid var(--border-soft);
}
.k-board thead th {
  border-top: 0;
  font-size: .7rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-soft);
  padding-top: .7rem;
}
.k-board td:last-child { width: 42%; }
.k-board .num {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono);
  font-size: .78rem;
}

.k-bar {
  display: block;
  height: 8px;
  border-radius: 6px;
  background: var(--surface-alt);
  overflow: hidden;
  position: relative;
}
.k-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  width: var(--w);
  background: linear-gradient(90deg, var(--blue), var(--leaf));
  border-radius: 6px;
}
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-reveal .k-bar::after { width: 0; transition: width 1s ease .3s; }
  .k-motion .k-reveal.is-in .k-bar::after { width: var(--w); }
}

.k-board__foot {
  padding: .65rem 1rem .8rem;
  margin: 0;
  font-size: .75rem;
  color: var(--text-soft);
}
.k-board__foot b { color: var(--ok); }

/* --------------------------------------------------------- 5 · the suite */

.k-suite {
  padding: clamp(3.5rem, 8vw, 6.5rem) 0;
}

.k-suite__grid {
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

.k-suite__copy p {
  color: var(--text-soft);
  margin: 1rem 0 0;
  max-width: 48ch;
}
.k-suite__note {
  margin-top: 1.4rem;
  padding: .9rem 1.1rem;
  border-left: 3px solid var(--gold);
  background: var(--warn-wash);
  color: var(--text);
  font-size: var(--step--1);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.k-rack { display: grid; gap: .6rem; }

.k-rack__server {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--radius);
  padding: .9rem 1.2rem;
  font-family: var(--font-display);
  font-weight: 650;
  font-size: var(--step--1);
}
.k-rack__server small {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: .72rem;
  color: var(--leaf);
  white-space: nowrap;
}

.k-rack__wires {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: .6rem;
  height: 1.4rem;
}
.k-rack__wires i {
  justify-self: center;
  width: 2px;
  height: 100%;
  background: var(--accent);
  transform-origin: top;
}
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-rack__wires i {
    transform: scaleY(0);
    transition: transform .5s ease;
    transition-delay: calc(.15s + var(--kw, 0) * .12s);
  }
  .k-motion .k-suite__grid.is-in .k-rack__wires i { transform: scaleY(1); }
}

.k-rack__apps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: .6rem;
}
.k-chip {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: .75rem .8rem;
  min-height: 5.4rem;
}
.k-chip b {
  /* Flex, not block, so the "licensed" badge below can wrap onto its own line.
     A margin is not a soft-wrap opportunity and there is no whitespace between the
     name and a ::after, so as a block the two ran together as one unbreakable word
     and the badge was clipped by the chip's edge. Flex items always break. */
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 .45rem;
  font-family: var(--font-display);
  font-size: .86rem;
  font-weight: 700;
  color: var(--text);
}
.k-chip span {
  display: block;
  margin-top: .25rem;
  font-size: .74rem;
  line-height: 1.4;
  color: var(--text-soft);
}
.k-chip--licensed {
  border-color: color-mix(in srgb, var(--gold) 55%, var(--border-soft));
  background: color-mix(in srgb, var(--gold) 9%, var(--surface));
}
.k-chip--licensed b::after {
  content: "licensed";
  font-size: .62rem;
  font-weight: 650;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--warn);
}
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-chip {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .5s ease, transform .5s ease;
    transition-delay: calc(.3s + var(--kw, 0) * .09s);
  }
  .k-motion .k-suite__grid.is-in .k-chip {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------- 6 · hall / online switch
   Lives inside <section class="band band--examina">, whose background and
   borders are set with the other examina styles above. */

.k-switch__head { text-align: center; }
.k-switch__head .k-h2,
.k-switch__head .k-lede { margin-inline: auto; }
.k-switch__head .k-h2 { max-width: 30ch; }

.k-switch__toggle {
  margin: 2rem auto 0;
  display: flex;
  width: max-content;
  max-width: 100%;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  padding: .3rem;
  gap: .2rem;
}
.k-switch__toggle[hidden] { display: none; }
.k-switch__toggle button {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-soft);
  font-family: var(--font-display);
  font-weight: 650;
  font-size: var(--step--1);
  padding: .6rem 1.4rem;
  border-radius: 999px;
  cursor: pointer;
  transition: color .2s ease, background-color .25s ease;
}
.k-switch__toggle button[aria-pressed="true"] {
  background: var(--ink);
  color: var(--paper);
}

.k-switch__panes {
  margin-top: 2rem;
  display: grid;
  gap: 1.2rem;
}
.k-pane {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: center;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-soft);
  background: var(--surface);
  box-shadow: var(--shadow);
  padding: clamp(1.5rem, 4vw, 2.6rem);
  transition: opacity .45s ease, transform .45s ease;
}
.k-pane[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-pane.is-entering {
    opacity: 0;
    transform: translateY(14px);
  }
}

.k-pane h3 { font-size: var(--step-2); }
.k-pane h3 .k-sub {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  margin-bottom: .5rem;
}
.k-pane--hall h3 .k-sub { color: var(--ok); }
.k-pane--online h3 .k-sub { color: var(--accent); }

.k-pane > div > p { color: var(--text-soft); margin: .9rem 0 0; }

.k-pane--hall ul {
  list-style: none;
  margin: 1.1rem 0 0;
  padding: 0;
  display: grid;
  gap: .55rem;
  color: var(--text-soft);
  font-size: var(--step--1);
}
.k-pane--hall ul li {
  display: flex;
  gap: .6rem;
  align-items: baseline;
}
.k-pane--hall ul li::before {
  content: "✓";
  color: var(--ok);
  font-weight: 700;
  flex: none;
}
.k-pane--online .checklist { margin-top: 1.1rem; }

.k-pane__cta { margin-top: 1.4rem; display: flex; gap: .7rem; flex-wrap: wrap; }

/* the LAN picture inside the hall pane: hub, wires, then a row of desks —
   deliberately a different drawing from the online pane's browser vignette */
.k-net {
  margin: 0;
  border-radius: var(--radius);
  border: 1px solid var(--border-soft);
  background: var(--surface-alt);
  padding: 1.2rem;
  display: grid;
  gap: 0;
  justify-items: center;
  text-align: center;
}
.k-net__hub {
  padding: .5rem 1rem;
  border-radius: var(--radius);
  font-family: var(--font-display);
  font-size: .8rem;
  font-weight: 700;
  background: var(--ink);
  color: var(--paper);
}
.k-net__wires {
  display: flex;
  gap: 1.55rem;
  height: 1.3rem;
  align-items: stretch;
}
.k-net__wires i {
  width: 2px;
  background: var(--accent);
}
.k-net__nodes {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  justify-content: center;
}
.k-net__nodes i {
  width: 2rem; height: 1.4rem;
  border-radius: 4px;
  border: 1.5px solid var(--slate-soft);
  background: var(--surface);
  position: relative;
}
.k-net__nodes i::after {
  content: "";
  position: absolute;
  inset: auto 25% -6px;
  height: 3px;
  border-radius: 2px;
  background: var(--slate-soft);
}
.k-net figcaption {
  margin-top: 1rem;
  font-size: .76rem;
  color: var(--text-soft);
  font-family: var(--font-mono);
}
.k-net figcaption b { color: var(--ok); font-weight: 600; }

.k-switch__note {
  margin: 1.8rem auto 0;
  max-width: 66ch;
  text-align: center;
  font-size: var(--step--1);
  color: var(--text-soft);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 1rem 1.3rem;
}
.k-switch__note strong {
  display: block;
  font-family: var(--font-display);
  color: var(--text);
  margin-bottom: .2rem;
}
.k-switch__note p { margin: 0; }

/* -------------------------------------------------------- 7 · the family */

.k-products {
  padding: clamp(3.5rem, 8vw, 6.5rem) 0;
}

.k-products__head {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: 1rem;
}

.k-products__grid {
  margin-top: clamp(2rem, 4.5vw, 3rem);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2.5vw, 1.5rem);
}

.k-card {
  display: flex;
  flex-direction: column;
  gap: .85rem;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 1.6rem;
  text-decoration: none;
  color: var(--text);
  position: relative;
  overflow: hidden;
  transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.k-card:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-lg);
  border-color: color-mix(in srgb, var(--k-tint, var(--accent)) 45%, var(--border-soft));
}
.k-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 4px;
  background: var(--k-tint, var(--accent));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .35s ease;
}
.k-card:hover::before { transform: scaleX(1); }

.k-card--flag {
  grid-column: span 2;
  background:
    radial-gradient(60rem 30rem at 110% -20%, color-mix(in srgb, var(--blue) 22%, transparent), transparent 60%),
    var(--ink);
  border-color: color-mix(in srgb, var(--paper) 14%, var(--ink));
  color: var(--paper);
  justify-content: flex-start;
  padding: clamp(1.6rem, 3vw, 2.4rem);
}
.k-card--flag h3 { color: var(--white); }
.k-card--flag .k-card__tag { color: color-mix(in srgb, var(--paper) 72%, var(--ink)); }
.k-card--flag:hover { border-color: color-mix(in srgb, var(--blue) 55%, var(--ink)); }

.k-card--more {
  border-style: dashed;
  background: transparent;
  box-shadow: none;
  justify-content: center;
}
.k-card--more::before { display: none; }
.k-card--more:hover { box-shadow: var(--shadow); }

.k-card__top {
  display: flex;
  align-items: center;
  gap: .9rem;
}
.k-card__top img {
  width: 46px; height: 46px;
  border-radius: 11px;
  flex: none;
}
.k-card--flag .k-card__top img { width: 58px; height: 58px; border-radius: 13px; }

.k-card__eyebrow {
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--k-tint, var(--accent));
  margin: 0;
}
.k-card--flag .k-card__eyebrow { color: var(--leaf); }
.k-card h3 {
  font-size: var(--step-1);
  margin-top: .1rem;
}
.k-card--flag h3 { font-size: var(--step-2); }

.k-card__tag {
  color: var(--text-soft);
  font-size: var(--step--1);
  line-height: 1.5;
  margin: 0;
}

.k-card__facts {
  list-style: none;
  margin: .2rem 0 0;
  padding: 0;
  display: grid;
  gap: .45rem;
  font-size: var(--step--1);
  color: var(--text-soft);
}
.k-card--flag .k-card__facts {
  color: color-mix(in srgb, var(--paper) 78%, var(--ink));
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 1.4rem;
}
.k-card__facts li {
  display: flex;
  gap: .55rem;
  align-items: baseline;
}
.k-card__facts li::before {
  content: "";
  flex: none;
  width: .45rem; height: .45rem;
  border-radius: 2px;
  background: var(--k-tint, var(--accent));
  transform: translateY(-.1em) rotate(45deg);
}

.k-card__price {
  margin: .3rem 0 0;
  font-size: .78rem;
  font-weight: 600;
  font-family: var(--font-display);
  letter-spacing: .02em;
  color: var(--k-tint, var(--accent));
  border-top: 1px dashed var(--border);
  padding-top: .7rem;
}
.k-card--flag .k-card__price {
  color: var(--gold);
  border-top-color: color-mix(in srgb, var(--paper) 22%, transparent);
}

.k-card__go {
  margin-top: auto;
  padding-top: .8rem;
  font-family: var(--font-display);
  font-weight: 650;
  font-size: var(--step--1);
  color: var(--k-tint, var(--accent));
  display: inline-flex;
  align-items: center;
  gap: .4rem;
}
.k-card--flag .k-card__go { color: var(--leaf); }
.k-card__go::after {
  content: "→";
  transition: transform .2s ease;
}
.k-card:hover .k-card__go::after { transform: translateX(4px); }

/* ----------------------------------------------------- 8 · trust ledger */

.k-proof {
  background: var(--surface-alt);
  border-block: 1px solid var(--border-soft);
  padding: clamp(3.5rem, 8vw, 6.5rem) 0;
}

.k-proof__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  gap: clamp(2rem, 5vw, 4rem);
}

.k-proof__copy p { color: var(--text-soft); margin: 1rem 0 0; max-width: 44ch; }

.k-proof__schools {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  align-content: start;
}
.k-proof__schools li {
  font-family: var(--font-display);
  font-weight: 700;
  /* Sized for a register of fourteen, not of six. The display face at 1.9rem was right when
     this list was a handful of names; at fourteen it out-shouted the argument beside it and
     turned a proof point into a wall. The type is still the display face and still the
     largest thing in the column — it is simply no longer competing with the h2. */
  font-size: clamp(1.05rem, 0.92rem + 0.7vw, 1.4rem);
  letter-spacing: -0.015em;
  line-height: 1.15;
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.k-proof__schools li:first-child { border-top: 1px solid var(--border); }
/* Name over location. The row is a flex with the mark pushed right, so the two lines of text
   have to be one flex child or the mark lands between them. */
.k-proof__school {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

/* The location is body copy, not display: it is the part a reader acts on rather than the
   part they scan, and setting it in the display face would make every row read as two names. */
.k-proof__where {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--step--1);
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--text-soft);
}

.k-proof__schools li small {
  font-size: var(--step--1);
  color: var(--gold);
}

.k-proof__offer {
  margin-top: 1.8rem;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-left: 4px solid var(--leaf);
  border-radius: var(--radius);
  padding: 1.1rem 1.3rem;
  box-shadow: var(--shadow);
}
.k-proof__offer b {
  font-family: var(--font-display);
  font-size: var(--step-0);
}
.k-proof__offer p {
  margin: .4rem 0 0;
  font-size: var(--step--1);
  color: var(--text-soft);
}

/* the three true counts */
.k-counts {
  margin-top: clamp(2.4rem, 5vw, 3.6rem);
  border-top: 1px solid var(--border);
  padding-top: 1.4rem;
}
.k-counts__note {
  margin: 0 0 1.2rem;
  font-size: var(--step--1);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-soft);
  font-family: var(--font-display);
  font-weight: 600;
}
.k-counts__row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
}
.k-stat b {
  display: block;
  font-family: var(--font-display);
  font-weight: 750;
  font-size: clamp(2.1rem, 1.4rem + 2.6vw, 3.4rem);
  line-height: 1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.k-stat > span {
  display: block;
  margin-top: .5rem;
  color: var(--text-soft);
  font-size: var(--step--1);
  max-width: 22ch;
}
.k-stat > i {
  display: block;
  width: 2.4rem;
  height: 4px;
  border-radius: 2px;
  margin-bottom: .9rem;
}
.k-stat:nth-of-type(1) i { background: var(--blue); }
.k-stat:nth-of-type(2) i { background: var(--leaf); }
.k-stat:nth-of-type(3) i { background: var(--gold); }

/* ------------------------------------------------------------ 9 · close */

.k-cta {
  position: relative;
  background: var(--ink);
  color: var(--paper);
  padding: clamp(4rem, 10vw, 7.5rem) 0;
  overflow: hidden;
  isolation: isolate;
  text-align: center;
}
.k-cta::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: 42rem; height: 42rem;
  left: 50%; bottom: -30rem;
  transform: translateX(-50%);
  border-radius: 50%;
  filter: blur(100px);
  background: color-mix(in srgb, var(--blue) 30%, transparent);
}

.k-cta .k-eyebrow { color: var(--leaf); justify-content: center; display: flex; }
.k-cta h2 {
  font-size: var(--step-3);
  max-width: 26ch;
  margin: .8rem auto 0;
  color: var(--white);
}
.k-cta h2 em { font-style: normal; color: var(--gold); }
.k-cta p {
  margin: 1.2rem auto 0;
  max-width: 52ch;
  color: color-mix(in srgb, var(--paper) 74%, var(--ink));
  font-size: var(--step-0);
}
.k-cta__row {
  margin-top: 2.2rem;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: .9rem;
}
.k-cta__small {
  margin-top: 1.6rem;
  font-size: var(--step--1);
  color: color-mix(in srgb, var(--paper) 55%, var(--ink));
}
.k-cta__small a { color: var(--leaf); }

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

@media (max-width: 940px) {
  .k-hero__grid,
  .k-fail__grid,
  .k-hall__head,
  .k-hall__grid,
  .k-results__grid,
  .k-suite__grid,
  .k-proof__grid,
  .k-pane { grid-template-columns: 1fr; }

  .k-hall__side { grid-template-columns: repeat(3, 1fr); }

  .k-products__grid { grid-template-columns: 1fr 1fr; }
  .k-card--flag { grid-column: 1 / -1; grid-row: auto; }

  .k-pane figure { order: -1; }
}

@media (max-width: 620px) {
  .k-counts__row { grid-template-columns: 1fr; gap: 1.6rem; }
  .k-stat > span { max-width: none; }

  .k-products__grid { grid-template-columns: 1fr; }
  .k-card--flag .k-card__facts { grid-template-columns: 1fr; }

  .k-rack__apps, .k-rack__wires { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .k-rack__wires { height: 1rem; }
  .k-rack__wires i:nth-child(n+3) { display: none; }

  .k-hall__side { grid-template-columns: 1fr; }

  .k-proof__schools li { flex-direction: column; gap: .2rem; align-items: flex-start; }

  .k-switch__toggle { width: 100%; }
  .k-switch__toggle button { flex: 1; padding-inline: .6rem; }

  .k-log ol { font-size: .72rem; }
  .k-exam__bar { flex-wrap: wrap; row-gap: .25rem; }
}

/* ==========================================================================
   13b. The product page — site/products/show.blade.php

   The evaluation page: an exam officer or a head teacher, on a phone, deciding
   whether one product is worth a term's budget. Everything below composes from
   the shared language (cover, split, prose, device, numbered cards, ledger,
   callout, fold) and adds only what a product page has that no other page does:
   a register of claims, a suite of applications served from one machine, a plan
   table six columns wide, and a specification sheet. Prefix k-pd-. Every
   component reads the --k-* palette of the ground it sits on; colour comes only
   from tokens and --k-tint.
   ========================================================================== */

/* ------------------------------------------------------------ the cover */

/* The h1 is the product's name; its tagline is the second line, a size down
   and in the soft voice, with one phrase in leaf. */
.k-cover h1 .k-pd-h1__tag {
  margin-top: .35em;
  font-size: var(--step-2);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: var(--k-soft);
  max-width: 24ch;
}

/* Mono tags: a status a reader must be able to read as words — "Launching
   late 2026", "Not on sale yet." — and never as colour alone. */
.k-pd-tags {
  display: flex;
  flex-wrap: wrap;
  gap: .45rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}
.k-pd-tag {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .22rem .6rem;
  border: 1px solid var(--k-rule);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--k-text);
}
.k-pd-tag--tint {
  border-color: var(--k-tint, var(--gold));
  color: var(--k-tint, var(--gold));
}
.k-ledger__desc .k-pd-tag {
  margin-left: .5rem;
  vertical-align: .15em;
  font-size: .62rem;
  padding: .12rem .45rem;
}

/* The product's real mark, in the bar of the cover's card. */
.k-pd-bar {
  display: flex;
  align-items: center;
  gap: .6rem;
  min-width: 0;
}
.k-pd-bar img {
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 6px;
  object-fit: contain;
  flex: none;
}

.k-pd-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .8rem;
  margin-top: 1.6rem;
}

/* ---------------------------------------------------- the claim register */

/* The features past the first three: a numbered register, ruled by hairlines,
   two columns wide when the screen allows. Not cards — these are claims a
   reader checks one by one, and a grid of shadows would make a list of ten
   look like a brochure. The number is printed in the markup, so the count
   continues from the three cards above it. */
.k-pd-claims {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 0 clamp(2rem, 4vw, 3.5rem);
  border-top: 1px solid var(--k-rule);
}
.k-pd-claims > li {
  display: grid;
  grid-template-columns: 2.2rem minmax(0, 1fr);
  gap: .25rem .6rem;
  padding: 1.05rem 0 1.15rem;
  border-bottom: 1px solid var(--k-rule-soft);
}
.k-pd-claims__n {
  grid-row: 1 / span 2;
  font-family: var(--font-mono);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  color: var(--k-hi);
  padding-top: .3em;
}
.k-pd-claims h3 {
  font-size: var(--step-1);
  color: var(--k-text);
}
.k-pd-claims p {
  grid-column: 2;
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--k-soft);
}

/* --------------------------------------------------------------- the suite */

/* A suite served from one machine: the application server as a full-width card
   at the top, the other applications as cards beneath it. On ink, which is
   where it lives, the cards are white on navy. The licensed one is marked in
   gold — it is the one fact on the picture that costs money. */
.k-pd-suite { display: grid; gap: 0; }

/* The server spans the row above the others: the machine everything else is
   pulled from. */
.k-pd-app--server {
  grid-column: 1 / -1;
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border-soft));
}
.k-pd-app--server p { max-width: 62ch; }
.k-pd-app__where {
  font-family: var(--font-mono);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--accent);
}

.k-pd-suite__apps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: .7rem;
}
.k-pd-app {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: .2rem .6rem;
  align-content: start;
  padding: .9rem 1rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: var(--text);
}
.k-pd-app__n {
  grid-row: 1 / span 2;
  font-family: var(--font-mono);
  font-size: .74rem;
  color: var(--text-faint);
  padding-top: .25em;
}
.k-pd-app b {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 .45rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .95rem;
}
.k-pd-app p {
  grid-column: 2;
  margin: 0;
  font-size: .78rem;
  line-height: 1.45;
  color: var(--text-soft);
}
.k-pd-app--licensed {
  border-color: color-mix(in srgb, var(--gold) 55%, var(--border-soft));
  background: color-mix(in srgb, var(--gold) 9%, var(--surface));
}
.k-pd-app__badge {
  font-size: .62rem;
  font-weight: 650;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--warn);
}

@media (prefers-reduced-motion: no-preference) {
  .k-motion .k-reveal .k-pd-app {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .5s ease, transform .5s ease;
    transition-delay: calc(.35s + var(--i, 0) * .08s);
  }
  .k-motion .k-reveal.is-in .k-pd-app {
    opacity: 1;
    transform: none;
  }
}

/* ---------------------------------------------------------- the plan table */

/* Six columns wide by nature. It scrolls inside itself, the row headings stay
   put while the plans scroll under them, and the prices are set in the display
   face because on this page they are the decision. `table.data` is the old
   language's table and is kept for the test that finds it; everything it
   painted is redeclared here. */
.k-pd-plans {
  margin-top: 1.6rem;
  overflow-x: auto;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.k-pd-plans table.data {
  width: 100%;
  min-width: 54rem;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--step--1);
  color: var(--text);
}
.k-pd-plans table.data th,
.k-pd-plans table.data td {
  text-align: left;
  vertical-align: top;
  padding: .7rem .95rem;
  border-bottom: 1px solid var(--border-soft);
  background: var(--surface);
}
.k-pd-plans table.data thead th {
  vertical-align: bottom;
  padding-top: 1rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-0);
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  border-bottom: 2px solid var(--border);
}
.k-pd-plans__meter {
  display: block;
  margin-top: .2rem;
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: .7rem;
  letter-spacing: .02em;
  color: var(--text-faint);
  white-space: nowrap;
}
.k-pd-plans table.data tbody th {
  font-family: var(--font-body);
  font-weight: 500;
  color: var(--text-soft);
}
/* The first column is the axis; it stays while the plans scroll past it. */
.k-pd-plans table.data th:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  min-width: 11rem;
  box-shadow: 1px 0 0 var(--border-soft);
}
.k-pd-plans table.data tbody tr:last-child :is(th, td) { border-bottom: 0; }

.k-pd-plans__price {
  font-family: var(--font-display);
  font-weight: 750;
  font-size: var(--step-2);
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.k-pd-plans td[data-cell="yes"] { color: var(--ok); font-weight: 600; }
.k-pd-plans td[data-cell="yes"]::before { content: "✓ "; }
.k-pd-plans td[data-cell="no"] { color: var(--text-faint); }
/* The plan with the newer capability — the last column — on a leaf tint. */
.k-pd-plans table.data :is(th, td).k-pd-plans__lead {
  background: color-mix(in srgb, var(--leaf) 9%, var(--surface));
}

.k-pd-footnotes {
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .4rem;
  max-width: 70ch;
  font-size: var(--step--1);
  color: var(--k-soft);
}
.k-pd-footnotes li {
  display: grid;
  grid-template-columns: 1.4rem minmax(0, 1fr);
  gap: .4rem;
}
.k-pd-footnotes li::before {
  content: "✱";
  color: var(--gold);
  font-size: .7rem;
  padding-top: .2em;
}

/* ---------------------------------------------------- the two ways to buy */

/* SmartExaminer's one-off purchase and its annual subscription, side by side
   in a .k-vs. Both devices carry a price register, and this block does one
   thing only: it steps the register down to a device's measure. The shared
   .k-ledger size (up to 1.9rem) is tuned for a full-width column; inside a
   27rem device "Professional" and ₦1,000,000 push each other out of the row
   and the price wraps under its own label, which is exactly the kind of
   sideways drift §6 forbids. Everything else here is the shared language. */
.k-pd-buy .k-pd-buy__ledger > li {
  font-size: clamp(1.05rem, .9rem + .7vw, 1.35rem);
}
.k-pd-buy .k-pd-buy__ledger > li > div { padding: .8rem 0; }
.k-pd-buy .k-pd-buy__ledger .k-pd-plans__price { font-size: var(--step-1); }

/* The rate, above the register: the one number a school multiplies, so it is
   the biggest thing in the device. */
.k-pd-buy__rate { margin: 0 0 .5rem; }
.k-pd-buy__rate .k-pd-plans__price { font-size: var(--step-3); }

/* What the structure means in one sentence — a term that ends, or one that
   does not. Small, because the price above it is the headline. */
.k-pd-buy__term {
  margin: 0 0 1rem;
  font-size: var(--step--1);
  color: var(--k-soft);
}

/* The sign-in note under Buy now. It sits with the button it explains rather
   than in the footnotes, because a reader only needs it in the second before
   they press it. */
.k-pd-buy__note {
  margin: .7rem 0 0;
  max-width: 62ch;
  font-size: var(--step--1);
  color: var(--k-soft);
}

/* --------------------------------------------------------------- the dives */

/* One longer argument: a display-face title and its paragraph on the left,
   the mechanism — ticked points, or the offer — on the right. Ruled apart. */
.k-pd-dive + .k-pd-dive {
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--k-rule);
}
.k-pd-dive__key {
  display: block;
  margin-bottom: .6rem;
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--k-hi);
}
.k-pd-dive h3 {
  font-size: var(--step-2);
  max-width: 22ch;
  color: var(--k-text);
}
.k-pd-dive__body {
  margin: .9rem 0 0;
  max-width: 58ch;
  color: var(--k-soft);
}
.k-pd-dive .k-checks { padding-top: .35rem; }
.k-pd-dive .k-checks li { line-height: 1.55; }

/* ------------------------------------------------------ the specification */

/* A spec sheet inside a device: label in mono, value in the body face. */
.k-pd-spec {
  margin: 0;
  padding: .2rem 1.1rem .4rem;
}
.k-pd-spec > div {
  display: grid;
  grid-template-columns: minmax(7.5rem, 9.5rem) minmax(0, 1fr);
  gap: .2rem 1rem;
  padding: .65rem 0;
  border-bottom: 1px solid var(--k-dev-rule);
}
.k-pd-spec > div:last-child { border-bottom: 0; }
.k-pd-spec dt {
  font-family: var(--font-mono);
  font-size: .74rem;
  line-height: 1.5;
  letter-spacing: .02em;
  color: var(--k-dev-faint);
  padding-top: .15em;
}
.k-pd-spec dd {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.5;
  color: var(--text);
}
.k-pd-spec dd b { font-weight: 700; }

/* ------------------------------------------------------- the cross-sell */

/* The examina.io block keeps the old wrapper class the copy-discipline tests
   key on (`band band--examina`), so this inner frame gives it the paper palette
   the k- components read, and the composition is the ordinary split. */
.k-pd-xsell {
  --k-text: var(--text);
  --k-soft: var(--text-soft);
  --k-faint: var(--text-faint);
  --k-rule: var(--border);
  --k-rule-soft: var(--border-soft);
  --k-panel: var(--surface);
  --k-kicker: var(--ok);
  --k-hi: var(--accent);
  color: var(--k-text);
}
.k-pd-xsell__mark {
  display: flex;
  align-items: center;
  gap: .8rem;
  margin-bottom: .2rem;
}
.k-pd-xsell__mark img {
  width: 2.75rem;
  height: 2.75rem;
  object-fit: contain;
}
.k-pd-xsell__foot {
  margin: 1.2rem 0 0;
  max-width: 58ch;
  font-size: var(--step--1);
  color: var(--k-soft);
}

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

@media (max-width: 620px) {
  .k-pd-claims { grid-template-columns: minmax(0, 1fr); }
  .k-pd-spec > div { grid-template-columns: minmax(0, 1fr); gap: .1rem; }
  .k-pd-plans table.data th:first-child { min-width: 8.5rem; }
}


/* ----------------------------------------------------------------------------
 * Product screenshots.
 *
 * Two shapes from one set of rules, because the two products photograph differently:
 * SmartExaminer is a desktop suite and its captures are wide (1359x725, 1413x1018), while
 * SmartLearn is an Android app and its captures are tall (1312x2560). `auto-fit` with a
 * `minmax` floor handles the first; `--phone` lowers the floor for the second so three
 * portrait screens sit in a row on a desktop instead of each claiming a screen height.
 *
 * The image carries its own width and height attributes in the markup, so the box is the
 * right shape before a byte of it arrives. `height: auto` here keeps that true once CSS
 * takes over: without it the attribute height wins and a 2560px-tall capture is drawn at
 * 2560px.
 *
 * A screenshot is evidence, not decoration, so it keeps a border and a light ground rather
 * than bleeding into the band. On `--wash` the ground and the band would otherwise be the
 * same colour and the picture would appear to float with no edge.
 * ------------------------------------------------------------------------ */
.k-shots {
  list-style: none;
  margin: 2.4rem 0 0;
  padding: 0;
  display: grid;
  gap: 1.8rem;
  grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr));
}
.k-shots--phone {
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1.4rem;
}

.k-shots__figure {
  margin: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: .9rem;
}

.k-shots__img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--k-radius, 14px);
}
/* A phone capture is tall enough to dominate a page on its own. Cap it against the
   viewport so a column of three stays scannable, and let the width follow. */
.k-shots--phone .k-shots__img {
  max-height: 68vh;
  width: auto;
  margin-inline: auto;
}

.k-shots__cap {
  font-size: var(--step--1);
  color: color-mix(in srgb, var(--text) 78%, transparent);
  line-height: 1.55;
  max-width: 46ch;
}
.k-shots__cap b {
  display: block;
  color: var(--text);
  font-family: var(--font-display);
  font-weight: 600;
  margin-bottom: .2rem;
}

/* The white paper offer, under the pictures rather than beside them: it is a different
   kind of thing from a caption and reads as one when it is on its own line. */
.k-shots__paper {
  margin: 2.2rem 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem 1rem;
}
.k-shots__meta {
  font-size: var(--step--1);
  color: color-mix(in srgb, var(--text) 62%, transparent);
}

/* ---------------------------------------------------------------------------
 * SmartExaminer tutorial playlists.
 *
 * Three cards, each a single link: thumbnail, title, one line of what it covers, and a plain
 * statement of where pressing it goes. The whole card is the target — a play button alone would
 * make a 44px hit area out of a 300px card, which on a phone is the difference between useful
 * and fiddly.
 *
 * The thumbnails are 4:3 (480x360, as YouTube serves them), and the ratio is declared so the
 * space is reserved before they load and the text below never jumps.
 * ------------------------------------------------------------------------ */
.k-tut {
  list-style: none;
  margin: 2.4rem 0 0;
  padding: 0;
  display: grid;
  gap: 1.4rem;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.k-tut__card {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  /*
   * Explicit, not `inherit`. This card is a light panel dropped into a band whose own text is
   * light, so inheriting produced a near-white title on a white card — about 1.1:1, invisible.
   * The surface tokens flip with the theme, so the card is legible on both.
   */
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--k-radius, 14px);
  overflow: hidden;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.k-tut__card:hover,
.k-tut__card:focus-visible {
  transform: translateY(-3px);
  border-color: var(--accent);
  box-shadow: 0 12px 30px color-mix(in srgb, var(--ink) 12%, transparent);
}

.k-tut__shot {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  background: var(--border-soft);
  overflow: hidden;
}
.k-tut__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The play affordance. Decorative — the link text names the playlist and says where it goes. */
.k-tut__play {
  position: absolute;
  inset: 50% auto auto 50%;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  width: 3.2rem;
  height: 3.2rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--white) 92%, transparent);
  color: var(--ink);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--ink) 28%, transparent);
  transition: transform .18s ease, background .18s ease;
}
.k-tut__card:hover .k-tut__play,
.k-tut__card:focus-visible .k-tut__play {
  transform: translate(-50%, -50%) scale(1.08);
  background: var(--white);
}
/* The triangle is optically centred, not geometrically: equal padding looks left-heavy. */
.k-tut__play svg { margin-left: 2px; }

.k-tut__meter {
  position: absolute;
  left: .6rem;
  bottom: .6rem;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--white);
  background: color-mix(in srgb, var(--ink) 82%, transparent);
  border-radius: 999px;
  padding: .2rem .7rem;
}

.k-tut__body {
  display: flex;
  flex-direction: column;
  gap: .45rem;
  padding: 1rem 1.1rem 1.2rem;
  flex: 1 1 auto;
}
.k-tut__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-1);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.k-tut__summary { color: var(--text-soft); font-size: var(--step--1); }

/* Pushed to the bottom so three cards of unequal summary length still line their actions up. */
.k-tut__go {
  margin-top: auto;
  padding-top: .5rem;
  font-weight: 600;
  color: var(--accent);
}
.k-tut__go::after { content: " →"; }
.k-tut__card:hover .k-tut__go { text-decoration: underline; }

.k-tut__tail { margin-top: 2rem; display: grid; gap: .5rem; }
.k-tut__note { color: var(--text-soft); margin: 0; max-width: 60ch; }

@media (prefers-reduced-motion: reduce) {
  .k-tut__card,
  .k-tut__play { transition: none; }
  .k-tut__card:hover,
  .k-tut__card:focus-visible { transform: none; }
  .k-tut__card:hover .k-tut__play { transform: translate(-50%, -50%); }
}

/* ------------------------------------------------- 14. examina.io cross-sell */

/*
 * The examina.io sections on the homepage and the SmartExaminer page.
 *
 * Colour rules for this block, same as the rest of the file: no literal, every value a
 * brand.css token or a color-mix() of tokens. The mixes matter more here than elsewhere —
 * Main2.dc.html paints this band a pale green (#F5FAEE on #E4EFD4 borders) which has no
 * token of its own and must not get one, because a fixed pale green is unreadable in the
 * dark palette. Mixing --leaf into --surface reproduces the light band exactly in spirit
 * and lands on a deep green-tinted navy in dark, from the same one declaration.
 */

.band--examina {
  /* The one band left in the old language's wrapper, because the copy-discipline tests key
     on the class. Its rhythm is the shared one, so it does not sit shorter than the sections
     either side of it on the homepage. */
  padding-block: clamp(3.5rem, 8vw, 6.5rem);
  background: color-mix(in srgb, var(--leaf) 9%, var(--surface));
  border-block: 1px solid color-mix(in srgb, var(--leaf) 32%, var(--surface));
}

/* The green eyebrow of the design's "NEW · EXAMINA.IO" band. --ok is the palette's
   readable green in both themes; --leaf is the mark's green and is a background here. */
.eyebrow--leaf {
  color: var(--ok);
  background: color-mix(in srgb, var(--leaf) 18%, transparent);
}

/*
 * "This is an addition, not a replacement." The one panel on the page whose job is to stop
 * a reader concluding that SmartExaminer has moved online. It is deliberately quiet — a
 * surface card, not an alert — because it is a clarification, not a warning.
 */
.callout {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--ok);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: clamp(1rem, 3vw, 1.35rem);
}

.callout h3 {
  font-size: var(--step-1);
}

.callout p {
  color: var(--text-soft);
  margin: 0.5rem 0 0;
}

/* --------------------------------------------------- outbound links */

/*
 * Anything leaving ratelsoft.com. The arrow is decorative and the partial pairs it with a
 * visually-hidden note, so the icon never has to carry the meaning on its own.
 */
.external__icon {
  flex: none;
  opacity: 0.75;
}

a.external:hover .external__icon,
a.external:focus-visible .external__icon {
  opacity: 1;
}

/*
 * The footer's one outbound entry — examina.io, which is listed as a product and has no page
 * of its own on this site. It is a list item beside four internal links, so it takes the
 * footer's own colour and weight and adds only the arrow; anything more would make one
 * product in the list look like an advertisement.
 */
.site-footer__external {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

/* The vignette's address bar, which is a real outbound link rather than a label. */
.vignette__url--link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--text-soft);
  text-decoration: none;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.vignette__url--link:hover {
  color: var(--accent);
}

/* --------------------------------------------------- the exam-builder vignette */

/* Single column: this vignette is a list, not the hero's question-plus-palette pair. The
   rule sits after the hero's 560px breakpoint on purpose, so it wins by source order. */
.vignette__body--stack {
  grid-template-columns: minmax(0, 1fr);
}

.builder {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.builder li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 0.6rem 0.8rem;
  font-size: var(--step--1);
}

.builder li > span:first-child {
  flex: 1 1 10rem;
  min-width: 0;
}

.builder__add {
  justify-content: center;
  border-style: dashed;
  border-color: var(--border);
  color: var(--text-soft);
  font-weight: 600;
}

.pill--accent {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}

/* Two of the three switches are on, as in the design. Purely a picture of the product:
   nothing here is a control, so nothing here is focusable. */
.toggles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.25rem;
  border-top: 1px solid var(--border-soft);
  padding-top: 0.9rem;
  font-size: var(--step--1);
  color: var(--text-soft);
}

.toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}

.toggle__track {
  position: relative;
  width: 1.9rem;
  height: 1.05rem;
  flex: none;
  border-radius: 999px;
  background: var(--border);
}

.toggle__track::after {
  content: "";
  position: absolute;
  top: 0.15rem;
  left: 0.15rem;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background: var(--surface);
  transition: transform .18s ease;
}

.toggle[data-on="yes"] .toggle__track {
  background: var(--accent);
}

.toggle[data-on="yes"] .toggle__track::after {
  transform: translateX(0.85rem);
  background: var(--on-accent);
}

.band--examina figcaption {
  margin-top: 0.75rem;
  font-size: var(--step--1);
  /* --text-faint measures 2.74:1 on this band's tint in the light theme; the
     next token up clears AA for the wiring diagram's caption. */
  color: var(--text-soft);
}

/* --------------------------------------------------- product-page cross-sell */

.cross-sell {
  display: grid;
  gap: clamp(1rem, 3vw, 1.75rem);
  align-items: start;
}

@media (min-width: 640px) {
  .cross-sell { grid-template-columns: 4rem minmax(0, 1fr); }
}

.cross-sell__icon {
  width: 4rem;
  height: 4rem;
}

.cross-sell h2 {
  font-size: var(--step-2);
}

/* --------------------------------------------------- product states */

/*
 * A product is either on sale, announced, or somewhere else entirely, and each of those has
 * to be legible before a reader has read a word of the copy. These are the marks that carry
 * that: a row of pills for the two dates a forthcoming product has, and the same row sized
 * for the homepage card.
 *
 * The dates are two separate pills rather than one sentence because they answer two
 * different questions — when can I buy it, and which sitting is it for — and a candidate
 * needs both. Colour is never the only signal: each pill reads as words on its own.
 */
.status-line {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.75rem 0 0;
}

.k-card__coming {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.55rem 0 0;
}

.k-card__coming .pill {
  font-size: 0.72rem;
  padding: 0.2rem 0.55rem;
}

/*
 * The forthcoming panel heads itself with an h2, because it is a section of the page rather
 * than a card inside one. `.callout` was written for an h3; this keeps the two the same size
 * so the panel does not shout over the section headings around it.
 */
.callout h2 {
  font-size: var(--step-1);
  margin: 0;
}

/* ==========================================================================
   The products index — resources/views/site/products/index.blade.php.

   Everything below is the index's own compositions, built on the shared block
   above and reading the same --k-* palette. Nothing here is used by the
   homepage or by a product page except the tint per product, which the family
   card at the tail of a product page repeats through the homepage's .k-card.
   ========================================================================== */

/* ----------------------------------------------------- the finder (cover) */

/* The cover's device is a log keyed by who is asking. Each line opens with the
   product's name as a jump link into the register: accent on the white card,
   not the leaf that unclassed links take on ink, which would be unreadable on
   a white ground. */
.k-finder__link {
  color: var(--accent);
  font-weight: 700;
  text-decoration: none;
  text-underline-offset: .2em;
}
.k-finder__link:hover,
.k-finder__link:focus-visible { text-decoration: underline; }
.k-lines li[data-tone="ok"]   > span:last-child .k-finder__link,
.k-lines li[data-tone="mark"] > span:last-child .k-finder__link { color: var(--accent); }

/* ---------------------------------------------------------- the picks */

/* The links at the foot of a reader's numbered card: one per product that
   reader is being pointed at, in the card's tint, with the register arrow. */
.k-picks {
  list-style: none;
  margin: .9rem 0 0;
  padding: 0;
  display: grid;
  gap: .35rem;
}
.k-picks a {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-family: var(--font-display);
  font-weight: 650;
  font-size: var(--step--1);
  color: var(--k-tint, var(--accent));
  text-decoration: none;
}
.k-picks a::after {
  content: "→";
  transition: transform .2s ease;
}
.k-picks a:hover::after { transform: translateX(4px); }

/* ---------------------------------------------------- hall vs anywhere */

/* Two devices side by side: the hall on ink, the online product on surface.
   The difference in ground is the argument — one is a room, one is a site. */
.k-vs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr));
  gap: clamp(1.5rem, 4vw, 2.75rem);
  align-items: start;
}
.k-vs--solo { grid-template-columns: minmax(0, 1fr); max-width: 44rem; }
.k-vs figcaption a:not(.external) { color: var(--accent); }

/* The outbound link inside the online device's caption: inline, quiet, with
   the arrow the external-link partial adds. */
.k-vs__out {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  color: var(--accent);
  font-weight: 600;
}

/* -------------------------------------------------------- the register */

/* The catalogue itself: one ruled entry per listed product, the way About's
   ledger rules its rows, but with the whole record — tagline, summary, the
   checked facts, who it is for, and the actions. Never inside a reveal. */
.k-register {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--k-rule);
}
.k-register > li { border-bottom: 1px solid var(--k-rule); }

.k-entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.1rem;
  padding-block: clamp(1.9rem, 4vw, 2.9rem);
  scroll-margin-top: 5rem;
}
/* Narrow is the default; the two-column register is the wide screen's opt-in,
   so every breakpoint this block adds is min-width. */
@media (min-width: 941px) {
  .k-entry {
    grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
    gap: 1.5rem clamp(2rem, 5vw, 4rem);
  }
}

.k-entry__id {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto auto;
  column-gap: 1rem;
  row-gap: .15rem;
  align-content: start;
}
.k-entry__num {
  grid-column: 1 / -1;
  font-family: var(--font-mono);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  color: var(--k-faint);
  margin-bottom: .6rem;
}
.k-entry:target .k-entry__num { color: var(--k-tint, var(--accent)); font-weight: 700; }
.k-entry__id img {
  grid-row: 2 / span 3;
  width: 52px;
  height: 52px;
  border-radius: 12px;
  object-fit: contain;
}
@media (min-width: 941px) {
  .k-entry__id img { width: 64px; height: 64px; border-radius: 14px; }
}
.k-entry__eyebrow {
  grid-column: 2;
  margin: 0;
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--k-tint, var(--accent));
}
.k-entry h3 {
  grid-column: 2;
  font-size: var(--step-2);
  color: var(--k-text);
}
.k-entry__state {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: .55rem 0 0;
}
.k-entry__state .pill {
  font-size: .72rem;
  padding: .2rem .55rem;
}

.k-entry__body { max-width: 62ch; }
.k-entry__body > p { margin: 0; color: var(--k-soft); }
.k-entry__body > p + p { margin-top: .8rem; }
.k-entry__tag {
  font-size: var(--step-1);
  line-height: 1.4;
  color: var(--k-text) !important;
}
.k-entry__body .k-checks { margin-top: 1.1rem; }
.k-entry__for {
  margin-top: 1.1rem !important;
  font-size: var(--step--1);
}
.k-entry__for strong {
  display: block;
  font-family: var(--font-display);
  color: var(--k-text);
}
.k-entry__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin-top: 1.4rem;
}
