/* ════════════════════════════════════════════════════════════════
   NAADI AI — PUBLIC WEBSITE STYLESHEET  (site.css)
   ─────────────────────────────────────────────────────────────────
   For site/ ONLY. Never ships inside the Capacitor bundle, never
   loads next to styles-mobile.css.

   CONTRACT
     • Section 1 is COPIED VERBATIM from mobile/styles-mobile.css
       :root. Values are not invented here. The additions are
       namespaced --site-*.
     • Every class is prefixed nd- (or mk- for product mockups), so
       nothing can collide with the app's cs2- / ph- / pt- / tc- /
       ad- / hm- / nia- vocabularies.
     • The ECG pulse is the site's signature. Geometry comes from
       --ecg-trace and login.html's .lg2-pulse.

   ─────────────────────────────────────────────────────────────────
   FULL-VIEWPORT SECTIONS — how the two pages differ, and why

   LANDING uses .nd-vp: min-height 100svh, contents vertically
   centred, and y-proximity scroll snapping above 900px. Each landing
   section is one self-contained pitch, so landing mid-section is a
   defect. Proximity, never mandatory — a section that outgrows the
   viewport on a short laptop must still scroll freely.

   FEATURES uses .nd-feat: the same 100svh floor and centring, but NO
   snapping. Its sections carry #anchors from the sub-nav, and the
   scroll-margin-top those need (to clear two sticky bars) fights
   scroll-snap-align — the margin opens a gap at every snap point.
   Anchors win there; snapping wins on landing.

   Both gated at ≥900px. Below that the content is genuinely taller
   than a phone screen and a forced viewport height would crop it.
   ════════════════════════════════════════════════════════════════ */

/* ════ 1. TOKENS ════ */
:root {
    --font-display: 'Sora', sans-serif;
    --font-body: 'DM Sans', sans-serif;
    --font-mono: 'JetBrains Mono', monospace;

    --g50: #eef4fb;
    --g100: #dce8f6;
    --g200: #bcd2ec;
    --g400: #5d92cf;
    --g500: #2f6cb3;
    --g600: #1f5896;
    --g700: #173f6f;

    --s50: #f8fafc;
    --s100: #f1f5f9;
    --s200: #e2e8f0;
    --s300: #cbd5e1;
    --s400: #94a3b8;
    --s500: #64748b;
    --s600: #475569;
    --s700: #334155;
    --s800: #1e293b;
    --s900: #0f172a;

    --indigo: #0f6f8c;
    --indigo-bg: #e7f2f5;
    --amber: #c07c12;
    --amber-bg: #faf2e2;
    --red: #c43d3d;
    --red-bg: #f9ebeb;
    --purple: #155e63;
    --purple-bg: #e3f0f0;
    --green-600: #16a34a;

    /* ── marketing-only ── */
    --site-ink: #0B1220;
    --site-sky: #7db3ec;
    --site-max: 1180px;
    --site-gut: 22px;
    --site-nav: 66px;
    --site-rail: 28px;
    --site-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 8px 24px -12px rgba(15, 23, 42, .12);
    --site-shadow-lift: 0 14px 40px -16px rgba(15, 23, 42, .28);
    --site-ease: cubic-bezier(.22, .61, .36, 1);
}

/* ════ 2. BASE ════ */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

body {
    font-family: var(--font-body);
    background: #fff;
    color: var(--s700);
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

img,
svg {
    max-width: 100%;
    display: block;
}

a {
    color: var(--g600);
    text-decoration: none;
}

button {
    font-family: var(--font-body);
    cursor: pointer;
}

:focus-visible {
    outline: 2px solid var(--g500);
    outline-offset: 3px;
    border-radius: 4px;
}

.nd-ink :focus-visible {
    outline-color: var(--site-sky);
}

.nd-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.nd-skip {
    position: absolute;
    left: 12px;
    top: -60px;
    z-index: 300;
    background: var(--g600);
    color: #fff;
    padding: 10px 16px;
    border-radius: 10px;
    font-weight: 700;
    font-size: .84rem;
    transition: top .18s;
}

.nd-skip:focus {
    top: 12px;
}

/* ════ 3. TYPE ════ */
.nd-h0,
.nd-h1,
.nd-h2,
.nd-h3 {
    font-family: var(--font-display);
    color: var(--s900);
    line-height: 1.14;
}

.nd-h0 {
    font-size: clamp(2.3rem, 5.6vw, 4.3rem);
    font-weight: 800;
    letter-spacing: -.034em;
}

.nd-h1 {
    font-size: clamp(1.6rem, 3.3vw, 2.5rem);
    font-weight: 800;
    letter-spacing: -.026em;
    line-height: 1.16;
}

.nd-h2 {
    font-size: clamp(1.05rem, 1.8vw, 1.26rem);
    font-weight: 700;
    letter-spacing: -.012em;
    line-height: 1.32;
}

.nd-h3 {
    font-size: .97rem;
    font-weight: 700;
    line-height: 1.35;
}

.accent {
    color: var(--g500);
}

.nd-ink .nd-h0,
.nd-ink .nd-h1,
.nd-ink .nd-h2,
.nd-ink .nd-h3 {
    color: #fff;
}

.nd-ink .accent {
    color: var(--site-sky);
}

.nd-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .67rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--g500);
    margin-bottom: 13px;
}

.nd-eyebrow i {
    font-size: .76rem;
}

.nd-ink .nd-eyebrow {
    color: var(--g400);
}

.nd-lead {
    font-size: clamp(1rem, 1.32vw, 1.17rem);
    line-height: 1.62;
    color: var(--s600);
    max-width: 60ch;
}

.nd-ink .nd-lead {
    color: rgba(255, 255, 255, .74);
}

.nd-body {
    font-size: .91rem;
    line-height: 1.68;
    color: var(--s600);
    max-width: 64ch;
}

.nd-ink .nd-body {
    color: rgba(255, 255, 255, .7);
}

.nd-cap {
    font-size: .75rem;
    line-height: 1.6;
    font-weight: 500;
    color: var(--s500);
}

.nd-ink .nd-cap {
    color: rgba(255, 255, 255, .5);
}

.nd-mono {
    font-family: var(--font-mono);
    font-size: .82em;
    letter-spacing: -.01em;
}

/* ════ 4. LAYOUT ════ */
.nd-wrap {
    width: 100%;
    max-width: var(--site-max);
    margin: 0 auto;
    padding: 0 var(--site-gut);
    position: relative;
    z-index: 2;
}

.nd-band {
    position: relative;
    padding: clamp(54px, 7vw, 92px) 0;
}

.nd-band.tint {
    background: var(--g50);
}

.nd-band.wash {
    background: var(--s50);
}

/* full-viewport section (landing)

   `safe center` is load-bearing, not a nicety. Plain `align-content:
   center` overflows in BOTH directions when the content is taller
   than the box, which slides the top of the section up underneath the
   fixed header — the heading looks truncated even though the markup
   is intact. `safe` falls back to start-alignment the moment content
   would overflow, so a tall section begins flush under the nav and
   scrolls normally. The unprefixed `center` above it is the fallback
   for engines that do not parse the `safe` keyword. */
.nd-vp {
    min-height: 100vh;
    min-height: 100svh;
    display: grid;
    align-content: center;
    align-content: safe center;
    padding-top: calc(var(--site-nav) + 32px);
    padding-bottom: clamp(38px, 6vh, 68px);
}

@media (min-width: 900px) {
    html.nd-snap {
        scroll-snap-type: y proximity;
    }

    .nd-vp {
        scroll-snap-align: start;
        padding-top: calc(var(--site-nav) + 42px);
    }
}

/* ink band */
/* position:relative is LOAD-BEARING, not cosmetic.
   ::before below is position:absolute with inset:-60px — a grid that
   deliberately bleeds past every edge and is meant to be trimmed by the
   overflow:hidden here. But `overflow` does not clip a descendant whose
   CONTAINING BLOCK lies outside the clipping element, and without a
   positioned ancestor that containing block is the initial one. So the
   grid escaped the section entirely and stuck 60px past the right edge
   of the viewport, which is precisely the 60px of horizontal overflow
   measured on an iPhone.

   Index never showed it because every .nd-ink there is paired with
   .nd-hero or .nd-band, both of which are positioned. The interior
   pages use `class="nd-vp nd-ink"`, and .nd-vp is not — so the anchor
   existed on exactly the page nobody was complaining about.

   Same failure the pricing.html header comment records for the hero
   pulse SVG, which .nd-photo-head fixed for the six photo heads. This
   is that fix generalised to the class that actually owns the ::before. */
.nd-ink {
    position: relative;
    background: var(--site-ink);
    color: rgba(255, 255, 255, .78);
    overflow: hidden;
}

.nd-ink::before {
    content: '';
    position: absolute;
    inset: -60px;
    z-index: 0;
    opacity: .5;
    background-image:
        linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
    background-size: var(--site-rail) var(--site-rail);
    animation: ndDrift 26s linear infinite;
    pointer-events: none;
}

@keyframes ndDrift {
    to {
        transform: translate(var(--site-rail), var(--site-rail));
    }
}

.nd-ink::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: radial-gradient(110% 80% at 82% 0%, rgba(47, 108, 179, .22) 0%, rgba(11, 18, 32, 0) 58%);
}

.nd-sec-head {
    max-width: 700px;
    margin-bottom: clamp(24px, 3.2vw, 42px);
}

.nd-sec-head .nd-lead {
    margin-top: 13px;
}

.nd-sec-head.center {
    margin-left: auto;
    margin-right: auto;
    text-align: center;
}

.nd-sec-head.center .nd-lead {
    margin-left: auto;
    margin-right: auto;
}

.nd-split {
    display: grid;
    gap: clamp(26px, 3.6vw, 52px);
    align-items: center;
}

.nd-grid {
    display: grid;
    gap: 14px;
}

.nd-foot-note {
    margin-top: clamp(20px, 2.8vw, 32px);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 18px;
}

/* ════ 5. ECG RULE ════ */
.nd-rule {
    display: flex;
    align-items: center;
    color: var(--s200);
}

.nd-rule i {
    flex: 1;
    height: 1px;
    background: currentColor;
}

.nd-rule i:first-child {
    flex: 0 0 clamp(20px, 8vw, 96px);
}

.nd-rule svg {
    flex: 0 0 132px;
    width: 132px;
    height: 26px;
    overflow: visible;
}

.nd-rule svg path {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

.nd-rule.blue {
    color: var(--g200);
}

.nd-rule.blue svg path {
    stroke: var(--g500);
}

.nd-ink .nd-rule {
    color: rgba(255, 255, 255, .14);
}

.nd-ink .nd-rule svg path {
    stroke: var(--g400);
}

/* ════ 6. BUTTONS ════ */
.nd-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    min-height: 48px;
    padding: 0 22px;
    border: 0;
    border-radius: 12px;
    font-family: var(--font-body);
    font-weight: 700;
    font-size: .89rem;
    line-height: 1;
    white-space: nowrap;
    transition: transform .14s var(--site-ease), box-shadow .2s, background .2s, color .2s;
}

/* .nd-btn was written for <a>. The pricing page now uses real <button>
   elements for the two checkout CTAs, because they run JavaScript
   rather than navigating — and a <button> brings defaults an anchor
   never had: an arrow cursor instead of a pointer, and iOS Safari's
   native chrome, which survives `border: 0` alone. */
button.nd-btn {
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

button.nd-btn:disabled {
    opacity: .55;
    cursor: default;
}

.nd-btn.primary {
    background: var(--g600);
    color: #fff;
    box-shadow: 0 8px 20px -10px rgba(23, 63, 111, .7);
}

.nd-btn.primary:hover {
    background: var(--g700);
    transform: translateY(-1px);
    box-shadow: 0 14px 28px -12px rgba(23, 63, 111, .8);
}

.nd-btn.ghost {
    background: #fff;
    color: var(--s700);
    box-shadow: inset 0 0 0 1.5px var(--s200);
}

.nd-btn.ghost:hover {
    box-shadow: inset 0 0 0 1.5px var(--s300);
    background: var(--s50);
}

.nd-btn.dark {
    background: var(--s900);
    color: #fff;
}

.nd-btn.dark:hover {
    background: var(--site-ink);
    transform: translateY(-1px);
}

.nd-ink .nd-btn.ghost {
    background: transparent;
    color: #fff;
    box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .26);
}

.nd-ink .nd-btn.ghost:hover {
    background: rgba(255, 255, 255, .07);
    box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .42);
}

.nd-btn.sm {
    min-height: 40px;
    padding: 0 16px;
    font-size: .82rem;
}

.nd-cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 24px;
}

.nd-tlink {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
    font-size: .86rem;
    color: var(--g600);
}

.nd-tlink i {
    font-size: .73rem;
    transition: transform .18s var(--site-ease);
}

.nd-tlink:hover i {
    transform: translateX(4px);
}

.nd-ink .nd-tlink {
    color: var(--site-sky);
}

/* ════ 7. HEADER ════ */
.nd-nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 120;
    height: var(--site-nav);
    background: rgba(255, 255, 255, .92);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid transparent;
    transition: border-color .2s, box-shadow .2s, background .2s;
}

.nd-nav.scrolled {
    border-bottom-color: var(--s200);
    box-shadow: 0 1px 12px rgba(15, 23, 42, .05);
}

/* Over an ink hero the bar starts transparent and inverted, then
   resolves to white once the reader leaves the hero. Without this a
   white bar sits on the navy hero like a sticker. */
.nd-nav.over-ink:not(.scrolled) {
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

.nd-nav.over-ink:not(.scrolled) .nd-wordmark-text {
    color: #fff;
}

.nd-nav.over-ink:not(.scrolled) .nd-wordmark-text span {
    color: var(--site-sky);
}

.nd-nav.over-ink:not(.scrolled) .nd-wordmark-underline path {
    stroke: #fff;
}

.nd-nav.over-ink:not(.scrolled) .nd-link {
    color: rgba(255, 255, 255, .82);
}

.nd-nav.over-ink:not(.scrolled) .nd-link:hover,
.nd-nav.over-ink:not(.scrolled) .nd-link.on {
    color: #fff;
    background: rgba(255, 255, 255, .1);
}

.nd-nav.over-ink:not(.scrolled) .nd-nav-cta {
    border-left-color: rgba(255, 255, 255, .2);
}

.nd-nav.over-ink:not(.scrolled) .nd-burger {
    background: rgba(255, 255, 255, .12);
    color: #fff;
}

.nd-nav-in {
    max-width: var(--site-max);
    height: 100%;
    margin: 0 auto;
    padding: 0 var(--site-gut);
    display: flex;
    align-items: center;
    gap: 10px;
}

.nd-brand {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
}

.nd-wordmark {
    position: relative;
    display: inline-block;
}

.nd-wordmark-text {
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.12rem;
    color: var(--s900);
    letter-spacing: .2px;
    line-height: 1;
    transition: color .2s;
}

.nd-wordmark-text span {
    color: var(--g500);
    transition: color .2s;
}

.nd-wordmark-underline {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -8px;
    width: 100%;
    height: 9px;
    overflow: visible;
}

.nd-wordmark-underline path {
    fill: none;
    stroke: var(--g500);
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
    transition: stroke .2s;
}

.nd-foot .nd-wordmark-text,
.nd-menu .nd-wordmark-text {
    color: #fff;
}

.nd-foot .nd-wordmark-text span,
.nd-menu .nd-wordmark-text span {
    color: var(--site-sky);
}

.nd-foot .nd-wordmark-underline path,
.nd-menu .nd-wordmark-underline path {
    stroke: #fff;
}

.nd-links {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
}

.nd-link {
    padding: 9px 12px;
    border-radius: 9px;
    font-size: .85rem;
    font-weight: 600;
    color: var(--s600);
    transition: color .16s, background .16s;
}

.nd-link:hover,
.nd-link.on {
    color: var(--g600);
    background: var(--g50);
}

.nd-nav-cta {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: 14px;
    padding-left: 14px;
    border-left: 1px solid var(--s200);
    transition: border-color .2s;
}

.nd-burger {
    display: none;
    margin-left: auto;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: 11px;
    background: var(--s100);
    color: var(--s800);
    font-size: 1.02rem;
    transition: background .2s, color .2s;
}

.nd-menu {
    position: fixed;
    inset: 0;
    z-index: 200;
    background: var(--site-ink);
    display: flex;
    flex-direction: column;
    padding: 0 var(--site-gut) calc(24px + env(safe-area-inset-bottom, 0px));
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .22s var(--site-ease), transform .22s var(--site-ease), visibility .22s;
    overflow-y: auto;
}

.nd-menu.open {
    opacity: 1;
    visibility: visible;
    transform: none;
}

.nd-menu-top {
    display: flex;
    align-items: center;
    height: var(--site-nav);
    flex: 0 0 auto;
}

.nd-menu-x {
    margin-left: auto;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: 11px;
    background: rgba(255, 255, 255, .1);
    color: #fff;
    font-size: 1.05rem;
}

.nd-menu-links {
    display: flex;
    flex-direction: column;
    padding: 18px 0 8px;
}

.nd-menu-links a {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.4rem;
    color: #fff;
    padding: 12px 0;
    letter-spacing: -.02em;
}

.nd-menu-links a.on {
    color: var(--site-sky);
}

.nd-menu-foot {
    margin-top: auto;
    padding-top: 22px;
    display: grid;
    gap: 10px;
}

.nd-menu-foot .nd-btn {
    width: 100%;
}

/* ════ 8. FOOTER ════ */
.nd-foot {
    background: var(--site-ink);
    color: rgba(255, 255, 255, .62);
    padding: clamp(46px, 6vw, 72px) 0 0;
    position: relative;
    overflow: hidden;
}

.nd-foot::before {
    content: '';
    position: absolute;
    inset: -40px;
    opacity: .38;
    background-image:
        linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
    background-size: var(--site-rail) var(--site-rail);
    pointer-events: none;
}

.nd-foot-grid {
    display: grid;
    gap: 32px;
    grid-template-columns: 1fr;
    position: relative;
    z-index: 2;
}

.nd-foot-brandcol .nd-brand {
    margin-bottom: 20px;
}

.nd-foot-tag {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: .86rem;
    color: rgba(255, 255, 255, .7);
}

.nd-foot-tag i {
    color: var(--g400);
}

.nd-social {
    display: flex;
    gap: 9px;
    margin-top: 18px;
}

.nd-social a {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: rgba(255, 255, 255, .07);
    color: rgba(255, 255, 255, .78);
    display: grid;
    place-items: center;
    font-size: .92rem;
    transition: background .16s, color .16s;
}

.nd-social a:hover {
    background: var(--g600);
    color: #fff;
}

.nd-foot-col h4 {
    font-family: var(--font-display);
    font-size: .67rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .42);
    margin-bottom: 13px;
}

.nd-foot-col ul {
    list-style: none;
    display: grid;
    gap: 10px;
}

.nd-foot-col a {
    font-size: .86rem;
    color: rgba(255, 255, 255, .68);
    transition: color .16s;
}

.nd-foot-col a:hover {
    color: #fff;
}

.nd-foot-bar {
    position: relative;
    z-index: 2;
    margin-top: clamp(32px, 4vw, 52px);
    border-top: 1px solid rgba(255, 255, 255, .1);
    padding: 18px 0 calc(22px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-wrap: wrap;
    gap: 8px 18px;
    align-items: center;
    font-size: .75rem;
    color: rgba(255, 255, 255, .44);
}

.nd-foot-bar .sep {
    opacity: .4;
}

/* ════ 9. COMPONENTS ════ */
.nd-card {
    position: relative;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 16px;
    padding: 22px;
    transition: transform .16s var(--site-ease), box-shadow .2s, border-color .2s;
}

a.nd-card:hover,
.nd-card.hover:hover {
    transform: translateY(-2px);
    box-shadow: var(--site-shadow-lift);
    border-color: var(--s300);
}

.nd-card.raised {
    box-shadow: var(--site-shadow);
}

.nd-card.edge {
    border-left: 3px solid var(--acc, var(--g500));
}

.nd-ink .nd-card {
    background: rgba(255, 255, 255, .045);
    border-color: rgba(255, 255, 255, .12);
}

.nd-ink .nd-card p,
.nd-ink .nd-card .nd-body {
    color: rgba(255, 255, 255, .68);
}

.nd-ico {
    width: 40px;
    height: 40px;
    flex: 0 0 40px;
    border-radius: 11px;
    display: grid;
    place-items: center;
    font-size: .95rem;
    background: var(--acc-bg, var(--g50));
    color: var(--acc, var(--g500));
}

.nd-ico.sm {
    width: 32px;
    height: 32px;
    flex-basis: 32px;
    border-radius: 9px;
    font-size: .78rem;
}

.nd-ink .nd-ico {
    background: rgba(255, 255, 255, .09);
    color: var(--site-sky);
}

.nd-points {
    list-style: none;
    display: grid;
    gap: 16px;
}

.nd-point {
    display: flex;
    gap: 13px;
    align-items: flex-start;
}

.nd-point-txt strong {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .92rem;
    color: var(--s900);
    margin-bottom: 3px;
    line-height: 1.35;
}

.nd-point-txt span {
    display: block;
    font-size: .86rem;
    line-height: 1.56;
    color: var(--s600);
}

.nd-ink .nd-point-txt strong {
    color: #fff;
}

.nd-ink .nd-point-txt span {
    color: rgba(255, 255, 255, .66);
}

/* stat — the scope caption is structural, not optional */
.nd-stat-num {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(3.4rem, 9vw, 6.2rem);
    line-height: .92;
    letter-spacing: -.045em;
    color: var(--g600);
}

.nd-ink .nd-stat-num {
    color: #fff;
}

.nd-stat-label {
    font-size: clamp(.95rem, 1.3vw, 1.08rem);
    line-height: 1.55;
    color: var(--s700);
    margin-top: 14px;
    max-width: 32ch;
}

.nd-ink .nd-stat-label {
    color: rgba(255, 255, 255, .8);
}

.nd-stat-scope {
    font-size: .74rem;
    line-height: 1.62;
    color: var(--s500);
    margin-top: 16px;
    padding-top: 15px;
    border-top: 1px solid var(--s200);
    max-width: 54ch;
}

.nd-ink .nd-stat-scope {
    color: rgba(255, 255, 255, .46);
    border-top-color: rgba(255, 255, 255, .12);
}

.nd-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 11px;
    border-radius: 999px;
    font-size: .7rem;
    font-weight: 700;
    background: var(--acc-bg, var(--g50));
    color: var(--acc, var(--g600));
    white-space: nowrap;
}

.nd-ink .nd-chip {
    background: rgba(255, 255, 255, .1);
    color: rgba(255, 255, 255, .82);
}

.nd-callout {
    position: relative;
    background: var(--acc-bg, var(--g50));
    border-radius: 4px 16px 16px 4px;
    border-left: 3px solid var(--acc, var(--g500));
    padding: 18px 20px;
    font-size: .89rem;
    line-height: 1.66;
    color: var(--s700);
}

.nd-cmp-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--s200);
    border-radius: 16px;
    background: #fff;
}

.nd-cmp {
    width: 100%;
    min-width: 620px;
    border-collapse: collapse;
    font-size: .84rem;
}

.nd-cmp th,
.nd-cmp td {
    padding: 11px 16px;
    text-align: left;
    border-bottom: 1px solid var(--s100);
}

.nd-cmp thead th {
    font-family: var(--font-display);
    font-size: .7rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--s500);
    background: var(--s50);
    border-bottom: 1px solid var(--s200);
}

.nd-cmp tbody th {
    font-weight: 600;
    color: var(--s800);
}

.nd-cmp td {
    text-align: center;
    color: var(--s600);
}

.nd-cmp td.y {
    color: var(--green-600);
}

.nd-cmp td.n {
    color: var(--s300);
}

.nd-cmp tr:last-child th,
.nd-cmp tr:last-child td {
    border-bottom: 0;
}

.nd-cmp-group th {
    background: var(--g50);
    font-family: var(--font-display);
    font-size: .69rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--g600);
}

.nd-seg {
    display: flex;
    gap: 4px;
    padding: 5px;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 14px;
    overflow-x: auto;
    scrollbar-width: none;
    margin-bottom: 22px;
}

.nd-seg::-webkit-scrollbar {
    display: none;
}

.nd-seg button {
    flex: 1 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 18px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--s500);
    font-size: .85rem;
    font-weight: 600;
    white-space: nowrap;
    transition: background .16s, color .16s;
}

.nd-seg button:hover {
    color: var(--s800);
}

.nd-seg button.on {
    background: var(--g600);
    color: #fff;
}

.nd-panel[hidden] {
    display: none;
}

.nd-ladder {
    display: grid;
    gap: 8px;
    position: relative;
    z-index: 2;
}

.nd-rung {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 15px;
    border-radius: 12px;
    background: rgba(255, 255, 255, .05);
    border: 1px solid rgba(255, 255, 255, .1);
}

.nd-rung i {
    width: 32px;
    height: 32px;
    flex: 0 0 32px;
    border-radius: 9px;
    background: rgba(255, 255, 255, .08);
    color: var(--g400);
    display: grid;
    place-items: center;
    font-size: .82rem;
}

.nd-rung b {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .89rem;
    color: #fff;
}

.nd-rung em {
    margin-left: auto;
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .72rem;
    color: rgba(255, 255, 255, .48);
}

.nd-rung.last i {
    background: var(--g600);
    color: #fff;
}

.nd-acc {
    border: 1px solid var(--s200);
    border-radius: 14px;
    background: #fff;
    overflow: hidden;
}

.nd-acc+.nd-acc {
    margin-top: 10px;
}

.nd-acc summary {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 17px 20px;
    cursor: pointer;
    list-style: none;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .95rem;
    color: var(--s900);
}

.nd-acc summary::-webkit-details-marker {
    display: none;
}

.nd-acc summary::after {
    content: '\f078';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    margin-left: auto;
    font-size: .72rem;
    color: var(--s400);
    transition: transform .2s var(--site-ease);
}

.nd-acc[open] summary::after {
    transform: rotate(180deg);
}

.nd-acc-body {
    padding: 0 20px 20px;
    font-size: .88rem;
    line-height: 1.7;
    color: var(--s600);
}

.nd-acc-body>*+* {
    margin-top: 12px;
}

/* ════ 10. METHOD STEPS — numbered, because it IS a sequence ════ */
.nd-steps {
    display: grid;
    gap: 12px;
}

.nd-step {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 15px;
    align-items: start;
    padding: 18px 20px;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 15px;
}

.nd-step-n {
    width: 32px;
    height: 32px;
    border-radius: 9px;
    display: grid;
    place-items: center;
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: .73rem;
    background: var(--g50);
    color: var(--g600);
}

.nd-step h3 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .96rem;
    color: var(--s900);
    line-height: 1.3;
    margin-bottom: 5px;
}

.nd-step p {
    font-size: .855rem;
    line-height: 1.58;
    color: var(--s600);
}

/* Move four is the one nobody else makes. Give it the edge. */
.nd-step.key {
    border-color: var(--purple);
    background: var(--purple-bg);
}

.nd-step.key .nd-step-n {
    background: var(--purple);
    color: #fff;
}

.nd-step.key p {
    color: var(--s700);
}

/* ── step hook: the one-line thesis above each step body ── */
.nd-step-hook {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .85rem;
    color: var(--g600);
    margin-bottom: 5px;
    line-height: 1.35;
}

.nd-step.key .nd-step-hook {
    color: var(--purple);
}

/* ── flow chain ──────────────────────────────────────────────────
   The six modules are a loop, not a menu, and a grid of cards can't
   say that. One wrapped row of chips with arrows between them; the
   last node is filled because that is where the loop closes and the
   record gets written back. */
.nd-chain {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 7px;
    margin-top: clamp(16px, 2.2vw, 26px);
    padding-top: 16px;
    border-top: 1px solid var(--s200);
}

/* On desktop the chain stays on ONE line — wrapping to two costs ~45px
   and that was the difference between the modules section fitting a
   1080p laptop and not. It scrolls sideways if the viewport is narrow,
   which reads correctly for a flow anyway. Below 900px it wraps, since
   a six-node horizontal scroll on a phone is worse than two rows. */
@media (min-width: 900px) {
    .nd-chain {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        padding-bottom: 2px;
    }

    .nd-chain::-webkit-scrollbar {
        display: none;
    }

    .nd-chain b {
        flex: 0 0 auto;
    }
}

.nd-chain b {
    display: inline-flex;
    align-items: center;
    padding: 6px 11px;
    border-radius: 8px;
    background: #fff;
    border: 1px solid var(--s200);
    font-family: var(--font-display);
    font-weight: 600;
    font-size: .74rem;
    color: var(--s700);
    white-space: nowrap;
}

.nd-chain b.end {
    background: var(--g600);
    border-color: var(--g600);
    color: #fff;
}

.nd-chain i {
    color: var(--s300);
    font-size: .6rem;
}

.nd-band.tint .nd-chain {
    border-top-color: var(--g100);
}

/* ── module card: one job per module ── */
.nd-mod-job {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .93rem;
    color: var(--acc, var(--g600));
    line-height: 1.3;
}

.nd-mod-purpose {
    font-size: .73rem;
    line-height: 1.5;
    color: var(--s500);
    padding-top: 9px;
    border-top: 1px solid var(--s100);
}

.nd-mod-purpose b {
    color: var(--s700);
    font-weight: 700;
}

/* ── audience: question-first tabs ── */
.nd-aud-q {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.15rem, 2.1vw, 1.55rem);
    letter-spacing: -.022em;
    color: var(--s900);
    line-height: 1.26;
    margin-bottom: 10px;
}

.nd-aud-q::before {
    content: '\201C';
}

.nd-aud-q::after {
    content: '\201D';
}

.nd-checks {
    list-style: none;
    display: grid;
    gap: 9px;
}

.nd-checks li {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    font-size: .875rem;
    line-height: 1.5;
    color: var(--s600);
}

.nd-checks li::before {
    content: '\f00c';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    font-size: .68rem;
    color: var(--acc, var(--g500));
    margin-top: 4px;
    flex: 0 0 auto;
}

.nd-aud-close {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--s200);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .95rem;
    line-height: 1.4;
    color: var(--acc, var(--g600));
}

/* one record, four views */
.nd-views {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 7px 9px;
    margin-top: 16px;
}

.nd-views b,
.nd-views span {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 12px;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 600;
    white-space: nowrap;
}

.nd-views b {
    background: var(--g600);
    color: #fff;
    font-family: var(--font-display);
}

.nd-views span {
    background: #fff;
    border: 1px solid var(--s200);
    color: var(--s600);
}

.nd-views i {
    color: var(--s400);
    font-size: .62rem;
}

/* ── ladder rungs now carry a meaning, not just a threshold ── */
.nd-rung div b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .89rem;
    color: #fff;
    line-height: 1.25;
}

.nd-rung div span {
    display: block;
    font-size: .74rem;
    line-height: 1.4;
    color: rgba(255, 255, 255, .55);
}

/* ── pricing preview ── */
.nd-price-mini .nd-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.nd-price-tag {
    position: absolute;
    top: -10px;
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--g600);
    color: #fff;
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.nd-price-term {
    margin-top: auto;
    padding-top: 12px;
    font-family: var(--font-mono);
    font-size: .68rem;
    color: var(--s500);
}

/* ════ 11. LANDING ════ */
.nd-hero {
    position: relative;
    background: var(--site-ink);
    overflow: hidden;
}

/* opacity was .46, tuned for a bright photo that needed knocking back.
   The current asset is the opposite problem: hero-journey.jpg has a mean
   luma of 26/255 and its left 40% sits at 5/255. Multiply that by .46 and
   composite it over #0B1220 and the image is mathematically darker than
   the band behind it — it disappears, and you are back to the flat navy
   this was supposed to fix. It is shot dark, so it is shown undimmed and
   the scrim below does all the protecting.

   object-position 78% 24% puts the doctor — the brightest mass in the
   frame, peaking at x=81% y=20% — just inside the right edge, and holds
   both faces above the vertical centre where cover crops least. */
.nd-hero-photo {
    position: absolute;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 78% 24%;
    opacity: 1;

    /* Pushing the subject right.

       object-position alone cannot do this on desktop: the photo is 16:9
       and any viewport wider than that crops vertically only, so the
       horizontal percentage stops having anything to move. Scaling past
       cover and then translating is what actually shifts the frame — the
       1.12 buys 6% of overhang on each edge, and the 5% nudge spends less
       than that, so no bare navy is ever exposed at the left edge.

       Keep translate under half of (scale - 1) x 100 if either number is
       retuned, or the left edge tears. */
    /* The comment above describes a 1.12 scale with a 5% nudge, but the
       values had drifted to 1.1 / 0% — i.e. the push was scaled up and then
       never applied, which is why the subjects still sat under the copy.
       Restored to what the note documents: 1.12 gives 6% of overhang each
       edge and the 5% spend stays inside it, so the left edge never tears. */
    transform: scale(1.1) translateX(-2.5%);
    transform-origin: center;
}

/* Two jobs, one per gradient.

   The radial keeps the headline column readable, and its reach is set by
   one hard constraint. The photo is 16:9; any viewport wider than that
   crops only vertically, so object-position stops moving the frame
   sideways and the student's lit shoulder is pinned at ~55% of the
   viewport — right where the h1 column ends. Stops that faded out by 62%
   put white text on that shoulder at 2.8:1, which is a fail.

   Holding .42 out to 55% and not clearing until 80% measures 8.4:1 across
   1280-2560 wide. That is not a trade against the photo either: because
   the whole image is now shown undimmed, the subject side reads at luma
   31 versus 24 under the old opacity .46 — the picture got brighter and
   the text got safer at the same time.

   Re-measure both if the asset changes.

   The linear does the edges: a little weight at the top so the fixed nav
   has something to sit on, and a hard landing into --site-ink at the
   bottom so the photo's lower edge is never visibly cut off against the
   next section. That bottom stop is load-bearing — without it you see the
   seam on any viewport shorter than the image's crop. */
.nd-hero-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        radial-gradient(145% 110% at 0% 20%, rgba(11, 18, 32, .96) 0%, rgba(11, 18, 32, .78) 30%, rgba(11, 18, 32, .42) 45%, rgba(11, 18, 32, 0) 60%),
        linear-gradient(180deg, rgba(11, 18, 32, .5) 0%, rgba(11, 18, 32, .06) 26%, rgba(11, 18, 32, .58) 82%, var(--site-ink) 100%);
}

/* Below 900px the hero grid collapses and the copy stops sitting beside
   the photo — it sits ON it. Two changes follow from that and neither is
   optional.

   The image is 16:9 and the band is now taller than it is wide, so cover
   scales to height and crops hard horizontally: at 78% the window lands
   squarely on the doctor's face, and the h1 gets set across it. Pulling
   to 88% rides the frame's right edge, where the falloff has already
   taken the mean luma back down to 27 — a lit shoulder and coat rather
   than a face under the text.

   And the radial is off here. It is anchored at 0% 14%, which on a narrow
   viewport protects a left column that no longer exists. A plain vertical
   wash is the only thing that helps once the text is centred over the
   image, and the photo drops back to .62 to buy the contrast the radial
   was buying on desktop. */
@media (max-width: 899px) {
    .nd-hero-photo {
        object-position: 88% 18%;
        opacity: .80;
        /* The band is taller than it is wide here, so cover crops
           horizontally and object-position works on its own again. The
           desktop scale+translate would only push the subject off-frame. */
        transform: none;
    }

    .nd-hero-scrim {
        background: linear-gradient(180deg,
                rgba(11, 18, 32, .88) 0%,
                rgba(11, 18, 32, .68) 38%,
                rgba(11, 18, 32, .8) 72%,
                var(--site-ink) 100%);
    }
}

.nd-hero-pulse {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 11%;
    z-index: 1;
    width: 100%;
    height: 84px;
    opacity: .32;
    pointer-events: none;
}

.nd-hero-pulse polyline {
    fill: none;
    stroke: var(--g400);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 1200;
    stroke-dashoffset: 1200;
    animation: ndDraw 1.7s var(--site-ease) .3s forwards;
}

@keyframes ndDraw {
    to {
        stroke-dashoffset: 0;
    }
}

.nd-hero-in {
    display: grid;
    gap: clamp(30px, 4vw, 54px);
    align-items: center;
}

.nd-kicker {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: .79rem;
    font-weight: 600;
    color: rgba(255, 255, 255, .6);
    margin-bottom: 15px;
}

.nd-kicker i {
    color: var(--g400);
}

.nd-hero-copy .nd-lead {
    margin-top: 18px;
    max-width: 48ch;
}

.nd-hero-note {
    margin-top: 15px;
    font-size: .765rem;
    color: rgba(255, 255, 255, .5);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.nd-hero-note i {
    color: var(--g400);
}

/* Trust row — four scannable claims under the CTAs. A parent's eye
   goes here before it goes to the paragraph, so every item has to be
   a fact, not an adjective. */
.nd-trust {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 10px;
    margin-top: 22px;
}

.nd-trust span {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 12px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .07);
    border: 1px solid rgba(255, 255, 255, .12);
    font-size: .765rem;
    font-weight: 600;
    color: rgba(255, 255, 255, .84);
    white-space: nowrap;
}

.nd-trust i {
    color: var(--g400);
    font-size: .7rem;
}

/* Credibility band — the NCERT claim and the paper audit, together,
   directly under the hero. Two halves of one argument: this is what
   we built, and here is it checked against the real paper. */
.nd-cred {
    background: var(--s50);
    border-bottom: 1px solid var(--s200);
    padding: clamp(34px, 4.5vw, 56px) 0;
}

.nd-cred-in {
    display: grid;
    gap: clamp(24px, 3.4vw, 46px);
    align-items: center;
}

.nd-cred-line {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.2rem, 2.3vw, 1.7rem);
    letter-spacing: -.024em;
    line-height: 1.24;
    color: var(--s900);
    max-width: 22ch;
}

.nd-cred-sub {
    margin-top: 12px;
    font-size: .89rem;
    line-height: 1.62;
    color: var(--s600);
    max-width: 46ch;
}

.nd-cred-sub b {
    font-family: var(--font-mono);
    font-size: .88rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--g600);
}

/* the audit panel */
.nd-audit {
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 16px;
    box-shadow: var(--site-shadow);
    padding: 20px 22px;
}

.nd-audit-head {
    display: flex;
    align-items: center;
    gap: 9px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .68rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--g600);
    margin-bottom: 14px;
}

.nd-audit-rows {
    display: grid;
    gap: 9px;
}

.nd-audit-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
}

.nd-audit-row b {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.5rem;
    letter-spacing: -.03em;
    line-height: 1;
    flex: 0 0 46px;
    color: var(--g600);
}

.nd-audit-row.hit b {
    color: var(--green-600);
}

.nd-audit-row.miss b {
    color: var(--s400);
}

.nd-audit-row span {
    font-size: .84rem;
    line-height: 1.5;
    color: var(--s600);
}

.nd-audit-scope {
    margin-top: 15px;
    padding-top: 13px;
    border-top: 1px solid var(--s200);
    font-size: .725rem;
    line-height: 1.58;
    color: var(--s500);
}

/* .nd-collage is gone. It was the hero's right column — three mockups
   stacked and offset behind the h1 — and it went out when the hero went
   photo-led. The cards themselves survive in index.html #surfaces, laid
   out by the rule below. If you are here looking for .nd-collage, this
   is where it went. */

/* Three mockups across, on a dark band. No offsets and no stagger: the
   hero version leaned them because they were scenery, but here they are
   three parallel answers to one question and a straight row is what says
   "parallel". align-items:start stops the two short cards stretching to
   the height of the Arena card and going hollow at the bottom. */
.nd-surfaces {
    display: grid;
    gap: 16px;
    align-items: start;
    position: relative;
    z-index: 2;
    margin-top: clamp(22px, 3vw, 34px);
}

.nd-surfaces-cap {
    margin-top: 18px;
    font-size: .735rem;
    line-height: 1.55;
    color: rgba(255, 255, 255, .46);
    max-width: 62ch;
}

/* proof */
.nd-proof-in {
    display: grid;
    gap: clamp(26px, 4vw, 52px);
    align-items: center;
}

.nd-method {
    display: grid;
    gap: 10px;
}

.nd-method-row {
    display: flex;
    align-items: center;
    gap: 13px;
    padding: 14px 16px;
    border-radius: 12px;
    background: rgba(255, 255, 255, .05);
    border: 1px solid rgba(255, 255, 255, .1);
}

.nd-method-row div b {
    font-family: var(--font-display);
    font-size: .87rem;
    color: #fff;
    display: block;
    margin-bottom: 2px;
}

.nd-method-row div span {
    font-size: .77rem;
    color: rgba(255, 255, 255, .6);
    line-height: 1.45;
    display: block;
}

/* modules */
.nd-mods {
    display: grid;
    gap: 13px;
}

.nd-mod {
    display: flex;
    flex-direction: column;
    gap: 11px;
    padding: 20px;
}

.nd-mod-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.01rem;
    color: var(--s900);
    letter-spacing: -.012em;
}

/* "OPD" means nothing to a first-time visitor, so the module leads
   with what it does and carries the name as a tag. Drop the tag once
   the term is doing its own work. */
.nd-tm {
    font-family: var(--font-mono);
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: 0;
    color: var(--acc, var(--g600));
    background: var(--acc-bg, var(--g50));
    padding: 3px 6px;
    border-radius: 6px;
    vertical-align: middle;
    margin-left: 5px;
    white-space: nowrap;
}

.nd-mod p {
    font-size: .84rem;
    line-height: 1.56;
    color: var(--s600);
    flex: 1;
}

.nd-mod .nd-tlink {
    font-size: .79rem;
    color: var(--acc, var(--g600));
}

/* audience */
.nd-aud-hook {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.22rem, 2.2vw, 1.62rem);
    letter-spacing: -.022em;
    color: var(--s900);
    line-height: 1.24;
    margin-bottom: 11px;
}

.nd-aud-list {
    list-style: none;
    display: grid;
    gap: 10px;
    margin-bottom: 18px;
}

.nd-aud-list li {
    position: relative;
    padding-left: 20px;
    font-size: .865rem;
    line-height: 1.56;
    color: var(--s600);
}

.nd-aud-list li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 8px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--acc, var(--g500));
}

.nd-aud-list li b {
    color: var(--s900);
    font-weight: 700;
}

/* pricing preview */
.nd-price-mini {
    display: grid;
    gap: 13px;
}

.nd-price-mini .nd-card {
    text-align: center;
    padding: 24px 20px;
}

.nd-price-mini h3 {
    font-family: var(--font-display);
    font-size: .72rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--s500);
    font-weight: 700;
}

.nd-price-mini b {
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 2rem;
    color: var(--s900);
    letter-spacing: -.03em;
    margin: 9px 0 5px;
}

.nd-price-mini p {
    font-size: .78rem;
    color: var(--s500);
    line-height: 1.5;
}

.nd-price-mini .nd-card.pick {
    border-color: var(--g500);
    box-shadow: var(--site-shadow);
}

/* ════ 12. FEATURES PAGE ════ */
.nd-page-head {
    position: relative;
    background: var(--site-ink);
    overflow: hidden;
    padding: calc(var(--site-nav) + clamp(46px, 6vw, 80px)) 0 clamp(44px, 6vw, 70px);
}

.nd-page-head .nd-lead {
    margin-top: 16px;
}

/* ════ 12b. PHOTO HEADS ════
   The same three-part contract .nd-hero uses on index.html — photo, scrim,
   copy lifted above both — packaged as one opt-in class so the interior
   pages can share it instead of each growing their own copy.

   Used by:
     · features.html    .nd-page-head.nd-photo-head → hero-modules.jpg
     · protocol.html    #protocol-head              → hero-protocol.jpg
     · nia.html         #nia-head                   → hero-nia.jpg
     · parents.html     #parents-head               → hero-parents.jpg
     · teachers.html    #teachers-head              → hero-teachers.jpg
     · institutes.html  #institutes-head            → hero-institutes.jpg
     · pricing.html     #pricing-head               → hero-pricing.jpg

   The six .nd-vp heads carry ids purely so their crops can differ: a plain
   .nd-vp.nd-photo-head selector hits all six, and they will not all want
   the same numbers once the real photos land. Shared defaults live on that
   selector; the ids override.

   That is now every page on the site except index.html, which keeps its
   own .nd-hero — it is a two-column grid with the copy beside the photo
   rather than over it, so it does not fit this pattern and should not be
   folded into it.

   The copy needs no rule of its own: .nd-wrap is already position:relative
   z-index:2 site-wide, so it sits above the scrim automatically. That is
   also why every photo head must put its copy inside a .nd-wrap.

   Both assets are shot dark (near-black left third) like hero-journey.jpg,
   so both are shown undimmed on desktop for the same reason the landing
   hero is: dimming an already-dark photo over #0B1220 makes it darker than
   the band behind it and the picture disappears. The scrim does all the
   protecting.

   Per-image crops live in the two blocks below this one. Everything here
   is shared and should stay image-agnostic. */
.nd-photo-head {
    position: relative;
    overflow: hidden;
}

.nd-photo-head .nd-head-photo {
    position: absolute;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 1;
    transform-origin: center;
}

/* Radial holds the copy column, linear does the edges — weight at the top
   for the fixed nav to sit on, and a hard landing into --site-ink at the
   bottom so the photo's lower edge never shows a seam against the sticky
   sub-nav that follows on both pages. That bottom stop is load-bearing.

   The radial clears later here than on the landing hero (65% vs 60%)
   because on both these pages the copy is a single unpaired column — there
   is no second grid track pulling it in, so it runs further right than the
   hero's h1 column does. */
.nd-photo-head .nd-head-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        radial-gradient(150% 115% at 0% 35%, rgba(11, 18, 32, .96) 0%, rgba(11, 18, 32, .8) 32%, rgba(11, 18, 32, .44) 50%, rgba(11, 18, 32, 0) 65%),
        linear-gradient(180deg, rgba(11, 18, 32, .55) 0%, rgba(11, 18, 32, .08) 24%, rgba(11, 18, 32, .55) 80%, var(--site-ink) 100%);
}

/* The lead's default 60ch ends at roughly 58% of the wrap, past where the
   radial has faded to nothing. Capping it keeps every line of copy inside
   the protected left half instead of asking the scrim to reach further
   right and wash the photo out. */
@media (min-width: 900px) {

    .nd-photo-head .nd-lead,
    .nd-photo-head .nd-cap {
        max-width: 46ch;
    }
}

/* Below 900px both heads are taller than they are wide, so cover flips to
   cropping horizontally and object-position works on its own again — the
   desktop translate would only push the subject out of frame.

   The radial is dropped for the same reason it is on the landing hero: it
   is anchored to a left column that no longer exists once the copy is set
   across the full width. A plain vertical wash plus a knocked-back photo
   is the only thing that helps there. */
@media (max-width: 899px) {
    .nd-photo-head .nd-head-photo {
        opacity: .78;
    }

    .nd-photo-head .nd-head-scrim {
        background: linear-gradient(180deg,
                rgba(11, 18, 32, .88) 0%,
                rgba(11, 18, 32, .7) 38%,
                rgba(11, 18, 32, .82) 74%,
                var(--site-ink) 100%);
    }
}

/* ── crop · features.html · hero-modules.jpg (1672x941, 16:9) ──
   68% 38% holds the module labels (the top third of the frame, and the
   only reason the image is on this page) inside the band while keeping the
   student off the text column. Do not raise the vertical figure past ~45%
   or the CONCEPT STUDIO and LIBRARY cards crop away.

   Note the horizontal figure only bites on viewports NARROWER than 16:9,
   where cover crops sideways. Wider than that and the crop goes vertical
   and 68% has nothing left to move — the same geometry documented at
   length on .nd-hero-photo.

   ⚠ scale(1) with a translate exposes bare navy: with nothing scaled past
   cover there is no overhang to spend, so -0.5% leaves a ~7px strip of
   --site-ink down the right edge. It is under the linear scrim's darkest
   region so it is close to invisible, but if that edge ever reads as a
   seam the fix is scale(1.02) — not a smaller translate. */
.nd-page-head.nd-photo-head .nd-head-photo {
    object-position: 68% 38%;
    transform: scale(1) translateX(-0.5%);
}

/* transform is unset here rather than in the shared mobile block above:
   the per-page desktop rule is a two-class selector and would out-specify
   a single-class `transform: none`, leaking the desktop push onto phones. */
@media (max-width: 899px) {
    .nd-page-head.nd-photo-head .nd-head-photo {
        object-position: 72% 34%;
        transform: none;
    }
}

/* ── default crop · every full-height (.nd-vp) photo head ──
   Six pages now share this pattern, so the safe values live here once and
   each page only declares what it actually differs on.

   transform:none is the default on purpose. Every .nd-vp head is a
   full-bleed 100vh band, which is the worst case for an undersized source
   — see the sharpness note on #protocol-head below for the full reasoning.
   A page only earns a scale() by shipping a big enough asset, and it then
   opts in explicitly (as #nia-head does).

   66% 46% keeps a right-third subject clear of the copy column and sits
   just above centre, which is where these frames carry their subject.
   Override per page once the real asset lands. */
.nd-vp.nd-photo-head .nd-head-photo {
    object-position: 66% 46%;
    transform: none;
}

@media (max-width: 899px) {
    .nd-vp.nd-photo-head .nd-head-photo {
        object-position: 72% 40%;
    }
}

/* ── crop · protocol.html · hero-protocol.jpg (1672x941, 16:9) ──
   ⚠ TRANSFORM IS none HERE ON PURPOSE — do not put a scale() back.

   This band is a full .nd-vp, so it is 100vh and full-bleed. The source is
   only 1672px wide, which means on a 1920 viewport the browser is already
   upscaling it ~1.15x before any CSS of ours runs, and on a 2560 display
   ~1.5x. Worse, a 100vh band on a 1920x1080 screen is almost exactly the
   image's own 16:9, so cover crops nothing at all and every pixel on
   screen is an interpolated one. That is what reads as out of focus.

   Any scale() multiplies straight into that. Even the identity
   scale(1.0) translateX(0%) this used to carry is worth removing rather
   than neutralising: a transform — identity or not — can promote the img
   to its own composited layer, where some engines rasterise at the
   pre-transform size and resample a second time. `none` avoids the layer
   entirely.

   The cost is the subject push. At exactly 16:9 object-position has no
   slack left to move the frame sideways, so on a maximised 1080p window
   the framing is whatever the photo already is. It still bites on any
   window narrower than 16:9 — 1440x900, and every laptop once browser
   chrome takes its cut — which is most real sessions. That trade is the
   right way round while the source is this small.

   THE ACTUAL FIX IS UPSTREAM: re-export at ~2600px wide. CSS cannot add
   detail that is not in the file. Once it is re-exported, scale() becomes
   affordable again if the framing needs it. */
#protocol-head .nd-head-photo {
    object-position: 62% 50%;
    transform: none;
}

@media (max-width: 899px) {
    #protocol-head .nd-head-photo {
        object-position: 70% 42%;
        transform: none;
    }
}

/* ── crop · nia.html · hero-nia.jpg (1672x941, 16:9) ──
   This block used to assume a ~2600px export and carried a scale(1.06) to
   push the subject right. The asset shipped at 1672 like the other three,
   so that assumption is gone and with it the scale: this head has exactly
   the same upscale exposure as #protocol-head, and the long sharpness note
   above applies to it word for word.

   ⚠ The interim value here was scale(1) translateX(-1.5%), which is the
   one combination to avoid. A translate with nothing scaled past cover has
   no overhang to spend, so it slides the photo off its own box and leaves
   a bare --site-ink strip down the right edge — about 29px on a 1920
   screen, which is wide enough to read as a mistake rather than a shadow.

   So: no transform. If the subject push is wanted back, the minimum safe
   form is scale(1.04) translateX(-1.5%) — 2% of overhang per edge against
   1.5% spent — and it costs a little more softness on this already
   upscaled file. Re-export at ~2600px and that cost disappears. */
#nia-head .nd-head-photo {
    object-position: 66% 46%;
    transform: none;
}

/* ── crop · parents / teachers / institutes ──
   Grouped rather than split three ways because they are all still on the
   inherited default, and grouping makes that fact visible: one place says
   "these three are untuned". Split each one out the moment its asset lands
   and the frame wants its own numbers — #pricing-head below is the worked
   example of what that split looks like.

   No transform on any of them, per the default above: all three are
   full-bleed 100vh bands, so a scale() is only affordable once the asset
   ships at ~2600px. Read the #protocol-head note before adding one.

   ⚠ Placeholder values. Nothing here has been checked against a real file.
   The note on .nd-hero-photo explains what to measure. */
#parents-head .nd-head-photo,
#teachers-head .nd-head-photo,
#institutes-head .nd-head-photo {
    object-position: 66% 46%;
    transform: none;
}

@media (max-width: 899px) {

    #parents-head .nd-head-photo,
    #teachers-head .nd-head-photo,
    #institutes-head .nd-head-photo {
        object-position: 72% 40%;
    }
}

/* ── crop · pricing.html · hero-pricing.jpg ──
   ▓▓ THIS IS THE BLOCK TO EDIT TO MOVE OR ZOOM THE PRICING HERO. ▓▓

   Two dials, and they do different jobs:

   · object-position X% Y%  — WHICH PART OF THE PHOTO SHOWS.
       X: higher = show more of the RIGHT of the frame (subject moves left
          on screen). Lower = show more of the left.
       Y: higher = show more of the BOTTOM. Lower = more of the top.
       Free. No quality cost at all — it only chooses the crop window.
       ⚠ But it can only move along the axis `cover` is actually cropping.
       The file is 16:9, so on a window wider than 16:9 the crop goes
       vertical and X stops doing anything. If nudging X seems to do
       nothing, that is why — narrow the window and it will move again.

   · transform: scale(N) — ZOOM IN.
       1.06 = 6% closer. Costs sharpness: the source is already being
       upscaled by this full-bleed band, and scale() multiplies into that.
       Keep it off unless the framing really needs it.

   · transform: scale(N) translateX(-P%) — ZOOM AND SHOVE SIDEWAYS.
       This is the only way to push the subject on a window wider than
       16:9, where object-position has run out of slack.
       ⚠ HARD RULE: P must stay under half of (N - 1) x 100, or the photo
       slides off its own box and you get a bare navy strip down the right
       edge. scale(1.06) allows up to 3%. scale(1) allows NOTHING — a
       translate with no scale always tears.

   Starting values below are placeholders; nothing has been measured
   against a real file yet.

   ── MOVING THE PHOTO DOWN · the Y in object-position ──

   hero-pricing.jpg carries its own headline across the top of the frame
   ("HIGH-QUALITY NEET PREPARATION SHOULDN'T BE A LUXURY"), and at the
   default crop that line lands level with the fixed nav and reads as if it
   were part of it. The fix is to slide the photo down inside the band.

   Y is the whole dial, and it is the cheapest one there is — it changes
   nothing about scale or quality, it only picks which slice of the image
   the band shows:

       Y: 0%   photo sits as LOW as the crop allows (its top edge meets the
               band's top edge — nothing is cut off the top)
          50%  centred; equal amounts cut from top and bottom
          100% photo sits as HIGH as it can (its bottom edge meets the
               band's bottom edge)

   So LOWERING Y moves the picture DOWN the screen. 0% is the end stop.

   How far that actually travels depends on the window, and it is worth
   knowing the number. This band is 100vh; at 1920x940 of viewport, cover
   scales the 16:9 file to 1920x1080, so 140px hangs off vertically — 70px
   above and 70px below at Y:50%. Going to Y:0% recovers all 70px and puts
   the photo's own headline that much clear of the nav. On a taller or
   narrower window there is more overhang and more travel; on a window
   narrower than 16:9 the crop flips to horizontal and Y stops moving
   anything at all.

   ⚠ If 70px is not enough, do NOT reach for translateY on its own — a
   translate with no scale slides the photo off its box and leaves a bare
   navy strip along the top edge. Scale first, then translate, and keep the
   translate under half of (N - 1) x 100:

       transform: scale(1.12) translateY(4%);

   That buys 6% of vertical overhang and spends 4%, and costs a little
   sharpness on this already-upscaled file.

   ── previously tried: object-fit: contain ──
   Rejected. It does show the whole frame, but the band is not the photo's
   exact 16:9, so the picture floats with flat navy gaps all round it. The
   blurred-backdrop trick that normally hides those gaps was more machinery
   than this needed — the real problem was never zoom, it was vertical
   position, which Y solves for free. */
#pricing-head .nd-head-photo {
    object-position: 66% 25%;
    transform: none;
}

/* Phones are the opposite case and need the opposite fix.

   A phone band is far TALLER than 16:9, so cover crops horizontally, not
   vertically — there is no vertical overhang left, and Y has nothing to
   travel through. The desktop 0% does nothing here.

   Which means the photo's own headline cannot be slid clear of the nav at
   this width. It does not need to be: below 900px the scrim drops the
   radial for a full vertical wash that starts at .88 alpha, and the photo
   itself drops to .78 opacity, so the top of the frame is already knocked
   back far enough that its text does not compete.

   X is the live dial here instead — higher shows more of the right of the
   frame. 72% keeps the students' faces off the h1. */
@media (max-width: 899px) {
    #pricing-head .nd-head-photo {
        object-position: 72% 40%;
    }
}

/* The intro gets a screen of its own. When it was only ~600px tall the
   sub-nav and the top of the first module landed together mid-viewport,
   with the module heading sliced by the fold — which is what made the
   gaps read as arbitrary rather than deliberate. */
@media (min-width: 900px) {
    .nd-page-head {
        min-height: 100vh;
        min-height: 100svh;
        display: grid;
        align-content: center;
        align-content: safe center;
        padding-top: calc(var(--site-nav) + 40px);
        padding-bottom: clamp(40px, 6vh, 72px);
        scroll-snap-align: start;
    }
}

.nd-subnav {
    position: sticky;
    top: var(--site-nav);
    z-index: 90;
    background: rgba(255, 255, 255, .94);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--s200);
}

.nd-subnav-in {
    max-width: var(--site-max);
    margin: 0 auto;
    padding: 0 var(--site-gut);
    display: flex;
    gap: 2px;
    overflow-x: auto;
    scrollbar-width: none;
}

.nd-subnav-in::-webkit-scrollbar {
    display: none;
}

.nd-subnav a {
    flex: 0 0 auto;
    padding: 14px 13px;
    font-size: .81rem;
    font-weight: 600;
    color: var(--s500);
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    transition: color .16s, border-color .16s;
}

.nd-subnav a:hover {
    color: var(--s800);
}

.nd-subnav a.on {
    color: var(--g600);
    border-bottom-color: var(--g600);
}

/* One module section per screen.

   The padding-top absorbs BOTH sticky bars (66px nav + ~50px sub-nav),
   which is what lets snapping and #anchors coexist here. Earlier this
   used scroll-margin-top instead — and scroll-margin offsets the snap
   position too, opening a gap at every snap point. With the clearance
   moved into padding, `scroll-snap-align: start` and a sub-nav anchor
   both land the section's top edge at the viewport top, and the content
   sits below the bars either way. Do not reintroduce scroll-margin-top. */
.nd-feat {
    padding: calc(var(--site-nav) + 60px) 0 clamp(44px, 6vw, 70px);
    border-bottom: 1px solid var(--s200);
}

.nd-feat.tint {
    background: var(--g50);
    border-bottom-color: var(--g100);
}

.nd-feat.wash {
    background: var(--s50);
}

@media (min-width: 900px) {
    .nd-feat {
        min-height: 100vh;
        min-height: 100svh;
        display: grid;
        align-content: center;
        align-content: safe center;
        padding-top: calc(var(--site-nav) + 56px);
        padding-bottom: clamp(36px, 4.5vh, 58px);
        scroll-snap-align: start;
    }
}

.nd-feat-head {
    max-width: 620px;
    margin-bottom: clamp(22px, 3vw, 36px);
}

.nd-feat-head .nd-lead {
    margin-top: 13px;
}

.nd-feat-body {
    display: grid;
    gap: clamp(26px, 3.6vw, 46px);
    align-items: center;
}

.nd-feat-art {
    display: grid;
    gap: 13px;
}

.nd-feat .mk {
    border-color: var(--s200);
    box-shadow: var(--site-shadow);
}

.nd-feat-limit {
    margin-top: clamp(22px, 3vw, 32px);
    padding-top: 15px;
    border-top: 1px dashed var(--s300);
    display: flex;
    gap: 11px;
    align-items: flex-start;
    font-size: .815rem;
    line-height: 1.6;
    color: var(--s500);
    max-width: 76ch;
}

.nd-feat-limit i {
    color: var(--s400);
    margin-top: 4px;
    font-size: .78rem;
}

.nd-feat-limit b {
    color: var(--s700);
    font-weight: 700;
}

.nd-phases {
    display: grid;
    gap: 7px;
    margin-top: 20px;
}

.nd-phase {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 15px;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 12px;
}

.nd-phase b {
    font-family: var(--font-display);
    font-size: .86rem;
    color: var(--s900);
}

.nd-phase em {
    font-style: normal;
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: .7rem;
    color: var(--s500);
    text-align: right;
}

.nd-phase-dot {
    width: 9px;
    height: 9px;
    flex: 0 0 9px;
    border-radius: 50%;
    background: var(--g200);
}

.nd-phase:nth-child(2) .nd-phase-dot {
    background: var(--g400);
}

.nd-phase:nth-child(3) .nd-phase-dot {
    background: var(--g500);
}

.nd-phase:nth-child(4) .nd-phase-dot {
    background: var(--g600);
}

.nd-phase:nth-child(5) .nd-phase-dot {
    background: var(--purple);
}

.nd-phase:nth-child(6) .nd-phase-dot {
    background: var(--amber);
}

.nd-portal {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.nd-portal-q {
    list-style: none;
    display: grid;
    gap: 9px;
}

.nd-portal-q li {
    display: flex;
    gap: 12px;
    align-items: baseline;
    font-size: .85rem;
    line-height: 1.55;
    color: var(--s600);
    padding-bottom: 9px;
    border-bottom: 1px solid var(--s100);
}

.nd-portal-q li:last-child {
    border-bottom: 0;
    padding-bottom: 0;
}

.nd-portal-q b {
    flex: 0 0 78px;
    font-family: var(--font-display);
    font-size: .81rem;
    color: var(--s900);
}

/* ── concept anatomy ─────────────────────────────────────────────
   A faithful rendering of the app's "THIS CONCEPT" rail: the seven
   layers every concept carries, in the order they're meant to be
   read, with the real minute estimates. This is the most persuasive
   thing on the Features page, because it is just the product. */
.mk-anat {
    display: grid;
    gap: 6px;
}

.mk-anat-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 11px;
    border-radius: 11px;
    background: #fff;
    border: 1px solid var(--s200);
}

.mk-anat-row .nd-ico {
    width: 30px;
    height: 30px;
    flex-basis: 30px;
    border-radius: 8px;
    font-size: .72rem;
    background: var(--s100);
    color: var(--s500);
}

.mk-anat-row div {
    min-width: 0;
}

.mk-anat-row b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .79rem;
    color: var(--s900);
    line-height: 1.25;
}

.mk-anat-row span {
    display: block;
    font-size: .67rem;
    line-height: 1.35;
    color: var(--s500);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mk-anat-row em {
    margin-left: auto;
    flex: 0 0 auto;
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .64rem;
    color: var(--s400);
}

.mk-anat-row.on {
    background: var(--g50);
    border-color: var(--g200);
}

.mk-anat-row.on .nd-ico {
    background: var(--g600);
    color: #fff;
}

.mk-anat-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 17px;
    height: 17px;
    padding: 0 5px;
    margin-left: 6px;
    border-radius: 999px;
    background: var(--s200);
    color: var(--s600);
    font-family: var(--font-mono);
    font-size: .58rem;
    font-weight: 700;
    vertical-align: 1px;
}

/* ── what's actually inside each layer ── */
.nd-inside {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 20px;
    padding-top: 15px;
    border-top: 1px solid var(--s200);
}

.nd-inside b {
    flex: 0 0 100%;
    font-family: var(--font-display);
    font-size: .67rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--s500);
    margin-bottom: 3px;
}

.nd-inside span {
    padding: 5px 10px;
    border-radius: 7px;
    background: #fff;
    border: 1px solid var(--s200);
    font-size: .705rem;
    font-weight: 600;
    color: var(--s600);
    white-space: nowrap;
}

.nd-feat.tint .nd-inside {
    border-top-color: var(--g100);
}

/* ── screenshot slot ─────────────────────────────────────────────
   Drop a real PNG into site/assets/ and it takes over; until then the
   hand-built mockup underneath shows instead. The onerror handler adds
   .no-img, so a missing file degrades to something presentable rather
   than to a broken-image icon. Filenames are listed in ASSETS.md. */
.nd-shot {
    margin: 0;
    position: relative;
}

.nd-shot img {
    width: 100%;
    height: auto;
    border-radius: 15px;
    border: 1px solid var(--s200);
    box-shadow: 0 1px 2px rgba(15, 23, 42, .05), 0 22px 50px -22px rgba(23, 63, 111, .32);
}

/* A screenshot must never be the reason a section overflows. 52vh leaves
   room for the head, the points and the limit line on any laptop. */
@media (min-width: 900px) {

    .nd-shot img,
    .nd-feat-art>.mk {
        max-height: 52vh;
    }

    /* The screenshot-led sections can afford more, because their left column
       is only four short points. */
    .nd-feat-body.wide .nd-shot img {
        max-height: 58vh;
    }

    .nd-shot img {
        object-fit: contain;
        object-position: center top;
    }
}

.nd-shot .nd-shot-alt {
    display: none;
}

.nd-shot.no-img img {
    display: none;
}

.nd-shot.no-img .nd-shot-alt {
    display: block;
}

/* ── Home dashboard mockup ───────────────────────────────────────
   Mirrors the real Home screen: greeting band, Progress to Doctor with
   its segmented rail, the resume cards, and Focus areas. */
.mk-home {
    padding: 0;
    overflow: hidden;
}

.mk-home-band {
    background: var(--site-ink);
    padding: 14px 15px 15px;
    position: relative;
    overflow: hidden;
}

.mk-home-band::before {
    content: '';
    position: absolute;
    inset: 0;
    opacity: .5;
    background-image:
        linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
    background-size: 22px 22px;
    pointer-events: none;
}

.mk-home-greet {
    position: relative;
    z-index: 1;
    display: block;
    font-family: var(--font-display);
    font-size: .58rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--g400);
}

.mk-home-name {
    position: relative;
    z-index: 1;
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: .95rem;
    color: #fff;
    letter-spacing: -.01em;
    margin-top: 2px;
}

.mk-home-prog {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 12px;
}

.mk-home-prog .nd-ico {
    width: 30px;
    height: 30px;
    flex-basis: 30px;
    border-radius: 9px;
    font-size: .74rem;
    background: var(--g600);
    color: #fff;
}

.mk-home-prog span {
    display: block;
    font-family: var(--font-display);
    font-size: .55rem;
    font-weight: 700;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .5);
}

.mk-home-prog b {
    display: block;
    font-family: var(--font-display);
    font-size: .82rem;
    color: #fff;
    line-height: 1.2;
}

.mk-home-pct {
    margin-left: auto;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.35rem;
    letter-spacing: -.03em;
    color: #fff;
    line-height: 1;
}

.mk-home-pct i {
    font-size: .62rem;
    font-style: normal;
    color: rgba(255, 255, 255, .6);
}

.mk-home-rail {
    position: relative;
    z-index: 1;
    height: 5px;
    border-radius: 99px;
    background: rgba(255, 255, 255, .14);
    margin-top: 11px;
    overflow: hidden;
}

.mk-home-rail i {
    display: block;
    height: 100%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--g600), var(--g400));
}

.mk-home-next {
    position: relative;
    z-index: 1;
    display: block;
    font-size: .6rem;
    color: rgba(255, 255, 255, .55);
    margin-top: 8px;
}

.mk-home-body {
    padding: 13px 15px 15px;
}

.mk-lbl {
    font-family: var(--font-display);
    font-size: .55rem;
    font-weight: 700;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--s500);
    margin-bottom: 7px;
}

.mk-lbl+.mk-lbl,
.mk-home-body>*+.mk-lbl {
    margin-top: 12px;
}

.mk-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border: 1px solid var(--s200);
    border-radius: 10px;
}

.mk-row+.mk-row {
    margin-top: 6px;
}

.mk-row .nd-ico {
    width: 28px;
    height: 28px;
    flex-basis: 28px;
    border-radius: 8px;
    font-size: .68rem;
}

.mk-row div {
    min-width: 0;
}

.mk-row b {
    display: block;
    font-family: var(--font-display);
    font-size: .74rem;
    color: var(--s900);
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mk-row span {
    display: block;
    font-size: .62rem;
    color: var(--s500);
}

.mk-row em {
    margin-left: auto;
    flex: 0 0 auto;
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .66rem;
    font-weight: 700;
    color: var(--s600);
}

.mk-row .dot {
    width: 7px;
    height: 7px;
    flex: 0 0 7px;
    border-radius: 50%;
    background: var(--red);
}

/* ── interactive Concept Studio demo ─────────────────────────────
   A working miniature of the real Studio. Visual grammar is lifted from
   concept-studio-desktop.css: the --csd-grad edge on a definition, the
   red danger channel, the numbered step rail, the flip card. Classes
   are nd-cs- so nothing can collide with the app's csd- rules.

   TWO HARD CONSTRAINTS, both learned the expensive way:

   1. NO INTERNAL SCROLL. A scrollbar inside a product demo reads as a
      cramped iframe, not as software.
   2. The LAYER STRIP IS HORIZONTAL. As a vertical rail its seven items
      wrapped to two lines each — ~450px — and the rail, not the pane,
      set the section height. Horizontal, it costs one row.

   The pane is min-height, and every layer's content is written to sit
   inside it. Revealed answers use opacity, not [hidden], so the pane
   cannot grow when someone clicks and push the section past the fold. */
.nd-cs {
    background: linear-gradient(180deg, #fbfcfe 0%, #f5f7fb 100%);
    border: 1px solid var(--s200);
    border-radius: 18px;
    padding: 6px;
    box-shadow: 0 1px 2px rgba(15, 23, 42, .05), 0 18px 44px -20px rgba(23, 63, 111, .28);
}

.nd-cs-bar {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 12px 14px 13px;
}

.nd-cs-bar .nd-ico {
    width: 34px;
    height: 34px;
    flex-basis: 34px;
    border-radius: 10px;
    font-size: .8rem;
    background: linear-gradient(135deg, var(--g600) 0%, var(--indigo) 100%);
    color: #fff;
}

.nd-cs-bar b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .95rem;
    color: var(--s900);
    line-height: 1.2;
    letter-spacing: -.012em;
}

.nd-cs-bar>span>span {
    display: block;
    font-size: .7rem;
    color: var(--s500);
    margin-top: 1px;
}

.nd-cs-bar em {
    margin-left: auto;
    flex: 0 0 auto;
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .66rem;
    color: var(--s400);
    padding: 5px 10px;
    border-radius: 999px;
    background: #fff;
    box-shadow: inset 0 0 0 1px var(--s200);
}

/* ── horizontal layer strip ── */
.nd-cs-tabs {
    display: flex;
    gap: 4px;
    padding: 0 6px 8px;
    overflow-x: auto;
    scrollbar-width: none;
}

.nd-cs-tabs::-webkit-scrollbar {
    display: none;
}

.nd-cs-tab {
    flex: 1 1 0;
    min-width: 108px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 7px;
    padding: 10px 12px;
    border: 1px solid transparent;
    border-radius: 12px;
    background: transparent;
    text-align: left;
    transition: background .16s, border-color .16s, box-shadow .16s;
}

.nd-cs-tab:hover {
    background: #fff;
    border-color: var(--s200);
}

.nd-cs-tab i {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    font-size: .7rem;
    background: var(--s200);
    color: var(--s500);
    transition: background .16s, color .16s;
}

.nd-cs-tab b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .77rem;
    color: var(--s700);
    line-height: 1.2;
    white-space: nowrap;
}

.nd-cs-tab em {
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .62rem;
    color: var(--s400);
}

.nd-cs-tab.on {
    background: #fff;
    border-color: var(--s200);
    box-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 8px 18px -10px rgba(23, 63, 111, .3);
}

.nd-cs-tab.on i {
    background: linear-gradient(135deg, var(--g600) 0%, var(--indigo) 100%);
    color: #fff;
}

.nd-cs-tab.on b {
    color: var(--s900);
}

/* ── pane ── */
.nd-cs-pane {
    background: #fff;
    border-radius: 14px;
    padding: 20px 22px 22px;
    min-height: 336px;
    box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
}

.nd-cs-view[hidden] {
    display: none;
}

.nd-cs-title {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-bottom: 15px;
}

.nd-cs-title i {
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
    border-radius: 10px;
    display: grid;
    place-items: center;
    font-size: .85rem;
    color: var(--g600);
    background: linear-gradient(135deg, rgba(31, 88, 150, .08), rgba(15, 111, 140, .08));
}

.nd-cs-title.danger i {
    color: var(--red);
    background: var(--red-bg);
}

.nd-cs-title h4 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.06rem;
    color: var(--s900);
    line-height: 1.2;
    letter-spacing: -.015em;
}

.nd-cs-title>span>span {
    display: block;
    font-size: .74rem;
    color: var(--s500);
    margin-top: 1px;
}

/* content channels */
.nd-cs-lbl {
    font-family: var(--font-display);
    font-size: .6rem;
    font-weight: 700;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--s400);
    margin: 15px 0 7px;
}

.nd-cs-lbl:first-child {
    margin-top: 0;
}

.nd-cs-def {
    position: relative;
    font-size: .89rem;
    line-height: 1.6;
    color: var(--s800);
    background: #fff;
    border-radius: 12px;
    padding: 13px 16px 13px 20px;
    box-shadow: inset 0 0 0 1px var(--s200);
}

.nd-cs-def::before {
    content: '';
    position: absolute;
    left: 0;
    top: 11px;
    bottom: 11px;
    width: 4px;
    border-radius: 4px;
    background: linear-gradient(135deg, var(--g600) 0%, var(--indigo) 100%);
}

.nd-cs-danger {
    background: var(--red-bg);
    border-radius: 12px;
    padding: 12px 15px;
    font-size: .85rem;
    line-height: 1.55;
    color: #7a2b2b;
}

.nd-cs-danger ul {
    list-style: none;
    display: grid;
    gap: 7px;
}

.nd-cs-danger li {
    display: flex;
    gap: 9px;
}

.nd-cs-danger li::before {
    content: '\f071';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    font-size: .66rem;
    color: var(--red);
    margin-top: 3px;
    flex: 0 0 auto;
}

.nd-cs-good {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    background: var(--indigo-bg);
    border-radius: 12px;
    padding: 12px 15px;
    font-size: .85rem;
    line-height: 1.5;
    color: #0c5064;
    font-weight: 500;
}

.nd-cs-good::before {
    content: '\f00c';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    font-size: .7rem;
    color: var(--indigo);
    margin-top: 3px;
    flex: 0 0 auto;
}

.nd-cs-p {
    font-size: .87rem;
    line-height: 1.58;
    color: var(--s600);
}

.nd-cs-p strong {
    color: var(--s900);
}

.nd-cs-src {
    margin-top: 13px;
    font-family: var(--font-mono);
    font-size: .66rem;
    color: var(--s400);
}

/* reserved reveal — opacity, never display, so the pane cannot grow */
.nd-cs-hold {
    opacity: 0;
    transition: opacity .22s var(--site-ease);
}

.nd-cs-hold.shown {
    opacity: 1;
}

.nd-cs-reveal {
    margin-top: 11px;
    padding: 8px 15px;
    border-radius: 10px;
    border: 1px solid var(--g200);
    background: var(--g50);
    color: var(--g700);
    font-size: .78rem;
    font-weight: 700;
    transition: background .16s;
}

.nd-cs-reveal:hover {
    background: var(--g100);
}

.nd-cs-reveal[hidden] {
    display: none;
}

/* numbered steps */
.nd-cs-steps {
    display: grid;
    gap: 2px;
    margin-top: 12px;
}

.nd-cs-step {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr);
    gap: 12px;
}

.nd-cs-step .rail {
    display: grid;
    justify-items: center;
    gap: 3px;
}

.nd-cs-step .rail b {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .68rem;
    color: #fff;
    background: linear-gradient(135deg, var(--g600) 0%, var(--indigo) 100%);
}

.nd-cs-step .rail s {
    width: 2px;
    height: 100%;
    min-height: 8px;
    background: var(--s200);
}

.nd-cs-step:last-of-type .rail s {
    display: none;
}

.nd-cs-step p {
    font-size: .85rem;
    line-height: 1.55;
    color: var(--s600);
    padding: 2px 0 11px;
}

/* concept map */
.nd-cs-map {
    display: grid;
    justify-items: center;
    gap: 5px;
}

.nd-cs-node {
    padding: 8px 14px;
    border-radius: 10px;
    background: #fff;
    box-shadow: inset 0 0 0 1px var(--s200);
    font-size: .8rem;
    font-weight: 600;
    color: var(--s700);
    text-align: center;
}

.nd-cs-node.root {
    background: linear-gradient(135deg, var(--g600) 0%, var(--indigo) 100%);
    color: #fff;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .9rem;
    box-shadow: none;
}

.nd-cs-link {
    width: 2px;
    height: 12px;
    background: var(--s200);
}

.nd-cs-fan {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 5px;
}

.nd-cs-fan .nd-cs-node {
    background: var(--g50);
    box-shadow: none;
    color: var(--g700);
    font-size: .76rem;
}

.nd-cs-rel {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 9px 13px;
    border-radius: 10px;
    background: var(--s50);
    font-size: .8rem;
    color: var(--s700);
}

.nd-cs-rel+.nd-cs-rel {
    margin-top: 5px;
}

.nd-cs-rel b {
    font-weight: 700;
    color: var(--s900);
}

.nd-cs-rel span {
    padding: 3px 9px;
    border-radius: 7px;
    background: var(--g100);
    color: var(--g700);
    font-size: .68rem;
    font-weight: 600;
}

/* flip card */
.nd-cs-fc {
    perspective: 1200px;
    cursor: pointer;
}

.nd-cs-fc-inner {
    position: relative;
    transform-style: preserve-3d;
    transition: transform .55s var(--site-ease);
    min-height: 186px;
}

.nd-cs-fc.flipped .nd-cs-fc-inner {
    transform: rotateY(180deg);
}

.nd-cs-fc-face {
    position: absolute;
    inset: 0;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    border-radius: 14px;
    padding: 22px 26px;
    display: grid;
    align-content: center;
    text-align: center;
    font-size: .95rem;
    line-height: 1.5;
}

.nd-cs-fc-face.front {
    background: var(--site-ink);
    color: #fff;
    font-family: var(--font-display);
    font-weight: 700;
}

.nd-cs-fc-face.back {
    background: var(--g50);
    color: var(--s800);
    transform: rotateY(180deg);
    box-shadow: inset 0 0 0 1px var(--g200);
    text-align: left;
    font-size: .84rem;
    align-content: center;
}

.nd-cs-fc-hint {
    text-align: center;
    font-size: .68rem;
    color: var(--s400);
    margin-top: 11px;
}

/* assertion–reason + options */
.nd-cs-ar .row {
    display: flex;
    gap: 10px;
    padding: 10px 13px;
    border-radius: 10px;
    background: var(--s50);
    font-size: .83rem;
    line-height: 1.5;
    color: var(--s700);
}

.nd-cs-ar .row+.row {
    margin-top: 5px;
}

.nd-cs-ar .row b {
    flex: 0 0 20px;
    font-family: var(--font-display);
    color: var(--g600);
}

.nd-cs-opts {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin-top: 11px;
}

.nd-cs-opt {
    display: flex;
    gap: 9px;
    align-items: flex-start;
    text-align: left;
    padding: 9px 12px;
    border-radius: 10px;
    border: 1px solid var(--s200);
    background: #fff;
    font-size: .79rem;
    line-height: 1.4;
    color: var(--s700);
    transition: border-color .15s, background .15s;
}

.nd-cs-opt:hover {
    border-color: var(--g400);
}

.nd-cs-opt b {
    flex: 0 0 auto;
    font-family: var(--font-display);
    color: var(--s400);
}

.nd-cs-opt.right {
    border-color: var(--green-600);
    background: #f0fdf4;
    color: #14532d;
}

.nd-cs-opt.right b {
    color: var(--green-600);
}

.nd-cs-opt.wrong {
    border-color: var(--red);
    background: var(--red-bg);
    color: #7a2b2b;
}

.nd-cs-opt.wrong b {
    color: var(--red);
}

.nd-cs-verdict {
    margin-top: 10px;
    font-size: .8rem;
    line-height: 1.5;
    color: var(--s600);
    min-height: 38px;
}

.nd-cs-verdict b {
    color: var(--s900);
}

/* recap */
.nd-cs-recap {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 7px;
}

.nd-cs-recap div {
    padding: 11px 14px;
    border-radius: 11px;
    background: var(--s50);
    font-size: .8rem;
    line-height: 1.5;
    color: var(--s600);
}

.nd-cs-recap div b {
    display: block;
    font-family: var(--font-display);
    font-size: .72rem;
    color: var(--s900);
    margin-bottom: 3px;
}

@media (max-width: 899px) {
    .nd-cs-tab {
        min-width: 132px;
    }

    .nd-cs-opts,
    .nd-cs-recap {
        grid-template-columns: 1fr;
    }

    .nd-cs-pane {
        min-height: 0;
    }
}

/* ════ 13. PRODUCT MOCKUPS ════ */
.mk {
    background: #fff;
    border-radius: 15px;
    border: 1px solid rgba(255, 255, 255, .12);
    box-shadow: 0 22px 56px -24px rgba(0, 0, 0, .65);
    padding: 15px;
    font-size: .8rem;
}

.mk-head {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 12px;
}

/* .mk-head span (below) would otherwise out-specify .nd-ico's own
   colour rule and paint every mockup icon slate-500. Restated at
   matching specificity rather than by weakening the generic rule. */
.mk-head .nd-ico {
    width: 32px;
    height: 32px;
    flex-basis: 32px;
    border-radius: 9px;
    font-size: .78rem;
    color: var(--acc, var(--g500));
}

.mk-head b {
    font-family: var(--font-display);
    font-size: .82rem;
    color: var(--s900);
    display: block;
    line-height: 1.2;
}

.mk-head span {
    font-size: .66rem;
    color: var(--s500);
}

.mk-ladder {
    display: flex;
    align-items: center;
    gap: 6px;
}

.mk-v {
    flex: 1;
    text-align: center;
    padding: 8px 4px;
    border-radius: 10px;
    font-family: var(--font-mono);
    font-size: .68rem;
    font-weight: 700;
    background: var(--s100);
    color: var(--s500);
}

.mk-v.bad {
    background: var(--red-bg);
    color: var(--red);
}

.mk-v.now {
    background: var(--purple-bg);
    color: var(--purple);
    box-shadow: inset 0 0 0 1.5px var(--purple);
}

.mk-v.wait {
    background: var(--s50);
    color: var(--s400);
    border: 1px dashed var(--s300);
}

.mk-arrow {
    color: var(--s300);
    font-size: .6rem;
}

.mk-note {
    margin-top: 10px;
    font-size: .68rem;
    line-height: 1.5;
    color: var(--s500);
    padding-top: 9px;
    border-top: 1px solid var(--s100);
}

.mk-ring-row {
    display: flex;
    align-items: center;
    gap: 15px;
}

.mk-ring {
    width: 76px;
    height: 76px;
    flex: 0 0 76px;
    position: relative;
}

.mk-ring svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.mk-ring circle {
    fill: none;
    stroke-width: 8;
    stroke-linecap: round;
}

.mk-ring .bg {
    stroke: var(--s100);
}

.mk-ring .fg {
    stroke: var(--g500);
}

.mk-ring-mid {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    text-align: center;
}

.mk-ring-mid b {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: .98rem;
    color: var(--s900);
    line-height: 1;
}

.mk-ring-mid span {
    font-size: .54rem;
    color: var(--s500);
    letter-spacing: .04em;
}

.mk-bars {
    flex: 1;
    display: grid;
    gap: 7px;
}

.mk-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .65rem;
    color: var(--s600);
}

.mk-bar span:first-child {
    flex: 0 0 44px;
}

.mk-bar i {
    flex: 1;
    height: 6px;
    border-radius: 99px;
    background: var(--s100);
    overflow: hidden;
    display: block;
}

.mk-bar i em {
    display: block;
    height: 100%;
    border-radius: 99px;
    background: var(--bar, var(--g500));
}

.mk-rail {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}

.mk-rail span {
    padding: 5px 9px;
    border-radius: 8px;
    background: var(--s100);
    color: var(--s500);
    font-size: .655rem;
    font-weight: 600;
}

.mk-rail span.on {
    background: var(--g600);
    color: #fff;
}

.mk-rail span.next {
    background: var(--g50);
    color: var(--g600);
}

.mk-nia {
    display: grid;
    gap: 9px;
}

.mk-sel {
    padding: 9px 11px;
    border-radius: 10px;
    background: var(--amber-bg);
    color: var(--s700);
    font-size: .71rem;
    line-height: 1.52;
    border-left: 3px solid var(--amber);
}

.mk-ask {
    justify-self: flex-end;
    max-width: 82%;
    padding: 8px 12px;
    border-radius: 13px 13px 4px 13px;
    background: var(--g600);
    color: #fff;
    font-size: .72rem;
}

.mk-say {
    display: flex;
    gap: 9px;
    align-items: flex-start;
}

.mk-say-mark {
    width: 22px;
    height: 22px;
    flex: 0 0 22px;
    border-radius: 50%;
    background: var(--indigo);
    display: grid;
    place-items: center;
}

.mk-say-mark::after {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #fff;
    opacity: .9;
}

.mk-say p {
    background: var(--s100);
    border-radius: 4px 13px 13px 13px;
    padding: 9px 12px;
    font-size: .72rem;
    line-height: 1.56;
    color: var(--s700);
}

.mk-foot {
    font-size: .62rem;
    color: var(--s400);
    text-align: center;
    padding-top: 3px;
}

/* ── ambient mockup motion ──────────────────────────────────────
   Slow, looping, low-contrast. The point is that the page looks
   alive, not that anything demands attention: nothing moves position,
   nothing flashes, and every cycle is long enough to read past.
   All of it is killed under prefers-reduced-motion at the bottom of
   this file. */

/* v1 → v2 → v3 walks the ladder, one stage lit at a time. */
.mk-anim-ladder .mk-v {
    animation: mkStep 6.6s var(--site-ease) infinite;
}

.mk-anim-ladder .mk-v:nth-of-type(1) {
    animation-delay: 0s;
}

.mk-anim-ladder .mk-v:nth-of-type(2) {
    animation-delay: 2.2s;
}

.mk-anim-ladder .mk-v:nth-of-type(3) {
    animation-delay: 4.4s;
}

@keyframes mkStep {
    0% {
        transform: scale(1);
        filter: none;
    }

    4% {
        transform: scale(1.07);
        filter: brightness(1.04);
    }

    29% {
        transform: scale(1.07);
        filter: brightness(1.04);
    }

    34%,
    100% {
        transform: scale(1);
        filter: none;
    }
}

/* Concept Studio tabs walk the reading order. */
.mk-anim-rail span {
    animation: mkTab 8.4s linear infinite;
}

.mk-anim-rail span:nth-child(1) {
    animation-delay: 0s;
}

.mk-anim-rail span:nth-child(2) {
    animation-delay: 1.2s;
}

.mk-anim-rail span:nth-child(3) {
    animation-delay: 2.4s;
}

.mk-anim-rail span:nth-child(4) {
    animation-delay: 3.6s;
}

.mk-anim-rail span:nth-child(5) {
    animation-delay: 4.8s;
}

.mk-anim-rail span:nth-child(6) {
    animation-delay: 6s;
}

.mk-anim-rail span:nth-child(7) {
    animation-delay: 7.2s;
}

@keyframes mkTab {

    0%,
    12% {
        background: var(--g600);
        color: #fff;
    }

    15%,
    100% {
        background: var(--s100);
        color: var(--s500);
    }
}

/* The Arena ring fills once when it scrolls into view; site.js adds
   .run and counts the number up to match. */
.mk-ring .fg {
    stroke-dasharray: 129 227;
}

.mk-ring.run .fg {
    animation: mkRing 1.5s var(--site-ease) forwards;
}

@keyframes mkRing {
    from {
        stroke-dasharray: 0 227;
    }

    to {
        stroke-dasharray: 129 227;
    }
}

/* ════ 14. MOTION ════ */
.nd-rv {
    opacity: 0;
    transform: translateY(14px);
}

.nd-rv.in {
    opacity: 1;
    transform: none;
    transition: opacity .5s var(--site-ease), transform .5s var(--site-ease);
}

/* ── controlled headline breaks ──────────────────────────────────
   Only above 900px. On a phone, forced breaks produce ragged widows;
   there the spans stay inline and the text wraps naturally. */
.nd-brk {
    display: inline;
}

@media (min-width: 900px) {
    .nd-brk {
        display: block;
    }
}

/* ── short viewports ─────────────────────────────────────────────
   A 1080p laptop with browser chrome and a taskbar leaves roughly
   860–900px of viewport, not 1080. Without these, a section that
   fits the designer's monitor overflows the buyer's. Type, gaps and
   section padding all step down together so the proportions hold. */
@media (min-width: 900px) and (max-height: 940px) {
    .nd-h0 {
        font-size: clamp(2.05rem, 3.9vw, 3.35rem);
    }

    .nd-h1 {
        font-size: clamp(1.5rem, 2.7vw, 2.1rem);
    }

    .nd-lead {
        font-size: .96rem;
        line-height: 1.6;
    }

    .nd-vp {
        padding-top: calc(var(--site-nav) + 26px);
        padding-bottom: 34px;
    }

    .nd-sec-head {
        margin-bottom: 26px;
    }

    .nd-cta-row {
        margin-top: 20px;
    }

    .nd-trust {
        margin-top: 18px;
    }

    .nd-points {
        gap: 13px;
    }

    .nd-step {
        padding: 15px 17px;
    }

    .nd-card {
        padding: 18px;
    }

    .nd-mod {
        gap: 8px;
        padding: 16px;
    }

    /* The six-module grid is the tallest section on the page: a head, two
       rows of cards, and the chain. Squeeze the card internals rather than
       the type, so the cards stay readable and only the air goes.
       Measured against a 1920x1080 Chrome window (~920px viewport): the
       section lands ~90px under, which is the margin it needs on a 13"
       laptop too. */
    .nd-mods {
        gap: 10px;
    }

    .nd-mod {
        gap: 7px;
        padding: 15px;
    }

    .nd-mod .nd-ico {
        width: 32px;
        height: 32px;
        flex-basis: 32px;
        border-radius: 9px;
        font-size: .78rem;
    }

    .nd-mod p {
        font-size: .8rem;
        line-height: 1.48;
    }

    .nd-mod-name {
        font-size: .94rem;
    }

    .nd-mod-job {
        font-size: .86rem;
    }

    /* The rule above Purpose costs 10px a card, 20px a section. The label
       is bold enough to separate itself without it. */
    .nd-mod-purpose {
        padding-top: 0;
        border-top: 0;
        font-size: .7rem;
    }

    .nd-chain {
        margin-top: 12px;
        padding-top: 11px;
    }

    .nd-chain b {
        padding: 5px 10px;
        font-size: .72rem;
    }

    .mk {
        padding: 13px;
    }

    .nd-surfaces {
        gap: 10px;
    }

    .nd-rung {
        padding: 9px 14px;
    }

    .nd-feat {
        padding-top: calc(var(--site-nav) + 58px);
        padding-bottom: 40px;
    }

    .nd-feat-head {
        margin-bottom: 20px;
    }

    /* The seven-row anatomy card is the tallest single element on the
       Features page. Seven rows x 3px is 21px back, invisible per row. */
    .mk-anat {
        gap: 5px;
    }

    .mk-anat-row {
        padding: 7px 10px;
    }

    .nd-inside {
        margin-top: 16px;
        padding-top: 13px;
    }

    .nd-inside span {
        padding: 4px 9px;
        font-size: .69rem;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    .nd-h0 {
        font-size: clamp(1.9rem, 3.4vw, 2.85rem);
    }

    .nd-h1 {
        font-size: clamp(1.4rem, 2.4vw, 1.85rem);
    }

    .nd-lead {
        font-size: .92rem;
    }

    .nd-vp,
    .nd-feat {
        padding-top: calc(var(--site-nav) + 20px);
        padding-bottom: 26px;
    }

    .nd-mod p {
        font-size: .8rem;
    }

    .nd-step p {
        font-size: .82rem;
    }
}

/* ════ RESPONSIVE ════ */

/* Phone: the six modules become a swipeable rail rather than a
   six-card column nobody reaches the bottom of. */
@media (max-width: 639px) {
    .nd-mods {
        grid-auto-flow: column;
        grid-auto-columns: 80%;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
        margin-inline: calc(var(--site-gut) * -1);
        padding-inline: var(--site-gut);
        padding-bottom: 6px;
    }

    .nd-mods::-webkit-scrollbar {
        display: none;
    }

    .nd-mods>* {
        scroll-snap-align: center;
    }
}

@media (min-width: 640px) {

    .nd-mods,
    .nd-price-mini,
    .nd-grid.g2,
    .nd-steps.s2 {
        grid-template-columns: repeat(2, 1fr);
    }

    .nd-foot-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 32px 28px;
    }
}

@media (min-width: 900px) {
    :root {
        --site-gut: 40px;
    }

    .nd-mods,
    .nd-grid.g3 {
        grid-template-columns: repeat(3, 1fr);
    }

    .nd-price-mini {
        grid-template-columns: repeat(3, 1fr);
    }

    .nd-grid.g4 {
        grid-template-columns: repeat(2, 1fr);
    }

    .nd-split.s55 {
        grid-template-columns: 1.05fr .95fr;
    }

    .nd-split.s60 {
        grid-template-columns: 1.18fr .82fr;
    }

    .nd-split.s50 {
        grid-template-columns: 1fr 1fr;
    }

    /* The second column is empty — the photo is full-bleed behind the whole
       band, not a grid cell. This track exists purely to stop the copy from
       running out across the subjects. At 1.1fr the h1's longest line
       ("Personal Learning Path.") reached ~55% of the viewport, which is
       exactly where the middle student's lit face sits, so the text landed
       on top of him. Pulling the copy to .92fr ends that line before the
       figures start. */
    .nd-hero-in {
        grid-template-columns: .92fr 1.08fr;
    }

    /* A hard ceiling as well as a ratio: past ~1600px the fr track keeps
       growing and the line creeps back over the subjects, because the photo
       crops vertically at those widths and the figures stay pinned to the
       same horizontal percentage. */
    .nd-hero-copy {
        max-width: 620px;
    }

    .nd-proof-in {
        grid-template-columns: .92fr 1.08fr;
    }

    .nd-cred-in {
        grid-template-columns: 1fr .85fr;
    }

    .nd-surfaces {
        grid-template-columns: repeat(3, 1fr);
        gap: clamp(14px, 1.6vw, 20px);
    }

    .nd-feat-body {
        grid-template-columns: 1.02fr .98fr;
    }

    /* Screenshot-led sections. The app UI is dense, so a 520px column
       renders it postage-stamp small; 1.34fr gives ~640px, which is the
       point where the sidebar labels and card titles stay legible. */
    .nd-feat-body.wide {
        grid-template-columns: .72fr 1.48fr;
        gap: clamp(22px, 2.4vw, 34px);
    }

    .nd-feat-body.flip .nd-feat-art {
        order: -1;
    }

    .nd-foot-grid {
        grid-template-columns: 1.5fr 1fr 1fr 1fr;
        gap: 40px;
    }
}

@media (min-width: 1024px) {
    :root {
        --site-gut: 48px;
    }

    .nd-grid.g4 {
        grid-template-columns: repeat(4, 1fr);
    }
}

@media (max-width: 1023px) {

    .nd-links,
    .nd-nav-cta {
        display: none;
    }

    .nd-burger {
        display: grid;
        place-items: center;
    }
}

@media (min-width: 1024px) {
    .nd-menu {
        display: none;
    }
}

/* ════ REDUCED MOTION ════ */
@media (prefers-reduced-motion: reduce) {

    html {
        scroll-behavior: auto;
    }

    html.nd-snap {
        scroll-snap-type: none;
    }

    .nd-ink::before,
    .nd-foot::before {
        animation: none;
    }

    .nd-hero-pulse polyline {
        animation: none;
        stroke-dashoffset: 0;
    }

    .mk-anim-ladder .mk-v,
    .mk-anim-rail span,
    .mk-ring.run .fg {
        animation: none;
    }

    .mk-anim-rail span:nth-child(1) {
        background: var(--g600);
        color: #fff;
    }

    .nd-rv {
        opacity: 1;
        transform: none;
    }

    .nd-rv.in {
        transition: none;
    }

    .nd-btn,
    .nd-card,
    .nd-tlink i {
        transition: none;
    }

    .nd-btn:hover,
    a.nd-card:hover,
    .nd-card.hover:hover {
        transform: none;
    }
}

@media print {

    .nd-nav,
    .nd-subnav,
    .nd-menu {
        display: none;
    }
}

/* ════ 15. PROTOCOL PAGE ═══════════════════════════════════════════
   Ten full-viewport sections. Every one of them must fit a 900x800
   laptop viewport with nothing hanging below the fold, which is the
   whole constraint this page is built against — so the components
   here are budgeted, not just styled. Where a component could grow
   unboundedly (the pipeline panels, the phase list) it is capped and
   the cap is documented next to it.
   ════════════════════════════════════════════════════════════════ */

/* ── shared: the one admitted limit that closes most sections ──
   Same dashed-rule treatment as .nd-feat-limit on the Features page,
   restated here because the Protocol sections are not .nd-feat and
   inheriting that selector would couple two unrelated layouts. */
.nd-admit {
    margin-top: clamp(16px, 2.4vw, 26px);
    padding-top: 13px;
    border-top: 1px dashed var(--s300);
    display: flex;
    gap: 11px;
    align-items: flex-start;
    font-size: .8rem;
    line-height: 1.58;
    color: var(--s500);
    max-width: 82ch;
}

.nd-admit i {
    color: var(--s400);
    margin-top: 3px;
    font-size: .76rem;
}

.nd-admit b {
    color: var(--s700);
    font-weight: 700;
}

.nd-ink .nd-admit {
    border-top-color: rgba(255, 255, 255, .16);
    color: rgba(255, 255, 255, .5);
}

.nd-ink .nd-admit i {
    color: rgba(255, 255, 255, .4);
}

.nd-ink .nd-admit b {
    color: rgba(255, 255, 255, .78);
}

/* ── §3 PIPELINE ───────────────────────────────────────────────────
   One real block walked end to end through five tabs. The panels are
   height-locked: without min-height the section grows and shrinks as
   the reader tabs through it, which on a snapped full-viewport page
   means the fold moves under them. The value is the tallest panel
   (Options, four rows) measured at the 800px breakpoint. */
.nd-pipe-panels {
    min-height: 246px;
}

@media (min-width: 900px) and (max-height: 940px) {
    .nd-pipe-panels {
        min-height: 228px;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    .nd-pipe-panels {
        min-height: 210px;
    }
}

.nd-src {
    background: #fff;
    border: 1px solid var(--s200);
    border-left: 3px solid var(--g500);
    border-radius: 4px 14px 14px 4px;
    padding: 15px 18px;
}

.nd-src-tag {
    font-family: var(--font-mono);
    font-size: .66rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--s500);
    margin-bottom: 7px;
}

.nd-src p {
    font-size: .89rem;
    line-height: 1.62;
    color: var(--s700);
}

/* the angle / difficulty / variant fan-out */
.nd-fan {
    display: grid;
    gap: 9px;
}

.nd-fan-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 10px 14px;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 11px;
}

.nd-fan-row b {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .87rem;
    color: var(--s900);
}

.nd-fan-row span {
    font-size: .81rem;
    color: var(--s600);
    line-height: 1.5;
}

.nd-fan-row em {
    margin-left: auto;
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .68rem;
    color: var(--s500);
    white-space: nowrap;
}

/* the arithmetic strip that closes the section */
.nd-math {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 7px 9px;
    font-family: var(--font-mono);
    font-size: .74rem;
    color: var(--s600);
}

.nd-math b {
    padding: 5px 10px;
    border-radius: 8px;
    background: #fff;
    border: 1px solid var(--s200);
    font-weight: 700;
    color: var(--s800);
}

.nd-math b.out {
    background: var(--g600);
    border-color: var(--g600);
    color: #fff;
}

/* option rows — the distractor is the product, so it gets the space */
.nd-opts {
    display: grid;
    gap: 7px;
}

.nd-opt {
    display: grid;
    grid-template-columns: 26px 1fr;
    gap: 11px;
    align-items: start;
    padding: 9px 13px;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 10px;
}

.nd-opt i {
    width: 26px;
    height: 26px;
    border-radius: 7px;
    display: grid;
    place-items: center;
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: .68rem;
    font-style: normal;
    background: var(--s100);
    color: var(--s600);
}

.nd-opt b {
    display: block;
    font-family: var(--font-display);
    font-size: .84rem;
    font-weight: 700;
    color: var(--s900);
    line-height: 1.34;
}

.nd-opt span {
    display: block;
    font-size: .78rem;
    line-height: 1.5;
    color: var(--s500);
    margin-top: 2px;
}

.nd-opt.ok {
    border-color: var(--green-600);
    background: #f2fbf5;
}

.nd-opt.ok i {
    background: var(--green-600);
    color: #fff;
}

/* ── §5 THE LADDER ─────────────────────────────────────────────────
   Horizontal, deliberately. A vertical timeline was the first plan
   and it overflows: the page already scrolls downward, so a vertical
   ECG is both decoration and a height cost. Three stations across the
   width spend width — which this page has spare — instead of height,
   which it does not. */
.nd-lad {
    position: relative;
}

.nd-lad-svg {
    display: block;
    width: 100%;
    height: clamp(56px, 8vw, 84px);
    overflow: visible;
}

.nd-lad-svg .trace {
    fill: none;
    stroke: var(--g500);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

.nd-lad-svg .node {
    fill: #fff;
    stroke: var(--g500);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
}

.nd-lad-svg .node.fill {
    fill: var(--g600);
    stroke: var(--g600);
}

.nd-lad-stations {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: clamp(10px, 1.6vw, 20px);
    margin-top: 12px;
}

.nd-lad-st b {
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(.95rem, 1.5vw, 1.08rem);
    color: var(--s900);
    line-height: 1.28;
}

.nd-lad-st span {
    display: block;
    font-size: .82rem;
    line-height: 1.52;
    color: var(--s600);
    margin-top: 5px;
}

.nd-lad-st em {
    display: inline-block;
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .64rem;
    letter-spacing: .05em;
    color: var(--s400);
    margin-top: 7px;
}

.nd-lad-st.key b {
    color: var(--g600);
}

/* the two branch outcomes, beneath the trace */
.nd-branch {
    display: grid;
    gap: 12px;
    margin-top: clamp(16px, 2.4vw, 26px);
}

@media (min-width: 760px) {
    .nd-branch {
        grid-template-columns: 1fr 1fr;
    }
}

.nd-branch-card {
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 14px;
    padding: 16px 18px;
}

.nd-branch-card.key {
    border-color: var(--g200);
    background: linear-gradient(180deg, #fff, var(--g50));
}

.nd-branch-head {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 8px;
}

.nd-branch-head b {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .9rem;
    color: var(--s900);
}

.nd-branch-card p {
    font-size: .83rem;
    line-height: 1.6;
    color: var(--s600);
}

/* ── §6 THE CLIMB ──────────────────────────────────────────────────
   Six phases as compact rows. This reuses the .nd-phase vocabulary
   from the Features page rather than inventing a parallel one — the
   two are the same object seen from two distances. */
.nd-climb {
    display: grid;
    gap: 6px;
}

.nd-climb-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 12px;
    align-items: center;
    padding: 9px 14px;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 11px;
}

.nd-climb-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--g200);
}

.nd-climb-row:nth-child(2) .nd-climb-dot {
    background: var(--g400);
}

.nd-climb-row:nth-child(3) .nd-climb-dot {
    background: var(--g500);
}

.nd-climb-row:nth-child(4) .nd-climb-dot {
    background: var(--g600);
}

.nd-climb-row:nth-child(5) .nd-climb-dot {
    background: var(--g700);
}

.nd-climb-row:nth-child(6) .nd-climb-dot {
    background: var(--purple);
}

.nd-climb-row b {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .85rem;
    color: var(--s900);
}

.nd-climb-row span {
    font-size: .78rem;
    color: var(--s500);
    margin-left: 8px;
}

.nd-climb-row em {
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .67rem;
    color: var(--s500);
    white-space: nowrap;
}

/* per-concept readout — the thing a blended score destroys */
.nd-conc {
    display: grid;
    gap: 7px;
}

.nd-conc-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 10px;
    align-items: center;
    font-size: .8rem;
}

.nd-conc-row>span:first-child {
    color: var(--s700);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nd-conc-bar {
    grid-column: 1 / -1;
    height: 5px;
    border-radius: 3px;
    background: var(--s100);
    overflow: hidden;
}

.nd-conc-bar i {
    display: block;
    height: 100%;
    border-radius: 3px;
    background: var(--g500);
}

.nd-conc-row em {
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .72rem;
    font-weight: 700;
    color: var(--s700);
}

.nd-tag {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.nd-tag.s {
    background: var(--red-bg);
    color: var(--red);
}

.nd-tag.l {
    background: var(--amber-bg);
    color: var(--amber);
}

.nd-tag.m {
    background: var(--indigo-bg);
    color: var(--indigo);
}

/* ── §7 SCHEDULING ─────────────────────────────────────────────────
   The strand figures are the evidence, so they are shown as bars
   whose LENGTH is the stranded count. The point of the picture is
   that the middle bar is the longest — the curve is not monotonic,
   and no amount of intuition would have guessed that. */
.nd-strand {
    display: grid;
    gap: 11px;
}

.nd-strand-row {
    display: grid;
    grid-template-columns: 74px 1fr auto;
    gap: 13px;
    align-items: center;
}

.nd-strand-row>b {
    font-family: var(--font-mono);
    font-size: .73rem;
    font-weight: 700;
    color: var(--s700);
}

.nd-strand-bar {
    height: 20px;
    border-radius: 5px;
    background: var(--s100);
    overflow: hidden;
}

.nd-strand-bar i {
    display: block;
    height: 100%;
    border-radius: 5px;
    background: var(--g400);
}

.nd-strand-row.peak .nd-strand-bar i {
    background: var(--amber);
}

.nd-strand-row>em {
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .72rem;
    color: var(--s600);
    white-space: nowrap;
}

/* ── §8 BUILT, THEN REMOVED ────────────────────────────────────────
   No accent colour anywhere in here. The section is persuasive
   because it is flat: four things that failed, stated plainly. Give
   it a highlight and it starts to look like a feature list again. */
.nd-rem {
    display: grid;
    gap: 11px;
}

@media (min-width: 700px) {
    .nd-rem {
        grid-template-columns: 1fr 1fr;
    }
}

.nd-rem-card {
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 14px;
    padding: 15px 17px;
}

.nd-rem-card b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .89rem;
    color: var(--s900);
    text-decoration: line-through;
    text-decoration-color: var(--s300);
    text-decoration-thickness: 1.5px;
}

.nd-rem-card p {
    font-size: .81rem;
    line-height: 1.56;
    color: var(--s600);
    margin-top: 6px;
}

/* ── §9 THE AUDIT ──────────────────────────────────────────────────
   Three donuts, one per paper. Biology's ring closes completely and
   carries no percentage: "90 of 90" under a closed ring is believed,
   "100%" is not. Physics is left visibly open on purpose — the gap
   is the credible part, and its caption names what is in it. */
.nd-donuts {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: clamp(10px, 2vw, 24px);
}

.nd-donut {
    text-align: center;
}

/* margin:0 auto, not text-align:center — site.css sets `svg { display:
   block }` globally (see BASE), so the parent's text-align has no effect
   on it and the ring would sit hard left in its column. */
.nd-donut-svg {
    width: clamp(96px, 13vw, 132px);
    height: clamp(96px, 13vw, 132px);
    margin: 0 auto;
    transform: rotate(-90deg);
    overflow: visible;
}

.nd-donut-svg circle {
    fill: none;
    stroke-width: 13;
}

/* Direct and indirect are two shades of ONE blue, deliberately close: both
   mean "the student had seen this", and a hard contrast between them made
   the ring look like it was reporting a problem where there wasn't one.
   The MISS is the only segment that changes hue, to amber, because the gap
   is the part worth looking at — and pointing at our own gap is the whole
   reason this section is credible.

   Two earlier passes failed here: --g400 beside --site-sky render as
   rgb(93,146,207) and rgb(125,179,236), so every ring looked identical;
   and a dark blue for indirect read as empty track, which made a covered
   question look like a miss. */
.nd-donut-svg .track {
    stroke: rgba(255, 255, 255, .07);
}

.nd-donut-svg .d {
    stroke: var(--site-sky);
}

.nd-donut-svg .i {
    stroke: var(--site-sky);
    opacity: .74;
}

.nd-donut-svg .m {
    stroke: #e2a850;
}

.nd-donut-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .92rem;
    color: #fff;
    margin-top: 11px;
}

.nd-donut-frac {
    font-family: var(--font-mono);
    font-size: .78rem;
    font-weight: 700;
    color: var(--site-sky);
    margin-top: 3px;
}

.nd-donut-split {
    font-size: .7rem;
    line-height: 1.5;
    color: rgba(255, 255, 255, .5);
    margin-top: 5px;
}

/* legend + the combined row */
.nd-key {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin-top: clamp(14px, 2vw, 20px);
    font-size: .72rem;
    color: rgba(255, 255, 255, .58);
}

.nd-key span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.nd-key i {
    width: 9px;
    height: 9px;
    border-radius: 2px;
    display: inline-block;
}

/* These three MUST stay in lockstep with .nd-donut-svg .d/.i/.m above.
   A legend that disagrees with the chart is worse than no legend. */
.nd-key i.d {
    background: var(--site-sky);
}

.nd-key i.i {
    background: var(--site-sky);
    opacity: .74;
}

.nd-key i.m {
    background: #e2a850;
}

.nd-total {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 18px;
    padding: 14px 18px;
    margin-bottom: clamp(16px, 2.4vw, 26px);
    border-radius: 14px;
    background: rgba(255, 255, 255, .05);
    border: 1px solid rgba(255, 255, 255, .12);
}

.nd-total b {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.5rem, 3vw, 2.1rem);
    letter-spacing: -.03em;
    color: #fff;
    line-height: 1;
}

.nd-total span {
    font-size: .82rem;
    color: rgba(255, 255, 255, .7);
}

.nd-total em {
    font-style: normal;
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: .74rem;
    color: rgba(255, 255, 255, .52);
}

/* ── short-viewport trims for this page only ──────────────────────
   Same principle as the Features trims: take the air, keep the type
   readable. Measured at 1280x800 and 1440x860. */
@media (min-width: 900px) and (max-height: 940px) {
    .nd-admit {
        margin-top: 14px;
        padding-top: 11px;
        font-size: .77rem;
    }

    .nd-fan-row {
        padding: 8px 13px;
    }

    .nd-opt {
        padding: 7px 12px;
    }

    .nd-climb-row {
        padding: 7px 13px;
    }

    .nd-branch-card {
        padding: 13px 16px;
    }

    .nd-rem-card {
        padding: 13px 15px;
    }

    .nd-strand {
        gap: 9px;
    }

    .nd-donut-svg {
        width: clamp(88px, 10vw, 108px);
        height: clamp(88px, 10vw, 108px);
    }

    .nd-total {
        padding: 11px 16px;
    }

    .nd-seg {
        margin-bottom: 16px;
    }

    .nd-seg button {
        min-height: 40px;
        font-size: .82rem;
    }
}

/* §4 is the tallest white section: a head, FIVE steps and an admitted
   limit. Five rows means every pixel taken off a row is worth five, so
   this trims the step internals rather than the type — untrimmed it ran
   29px over at 1512x860 and left only 31px of slack at 1920x920.

   Deliberately on the site's existing 940px height breakpoint rather
   than a new one: a third breakpoint would mean three places to keep in
   sync every time a row is added to any section on this page. */
@media (min-width: 900px) and (max-height: 940px) {
    .nd-steps {
        gap: 8px;
    }

    .nd-step {
        padding: 12px 16px;
        gap: 13px;
    }

    .nd-step-n {
        width: 28px;
        height: 28px;
        border-radius: 8px;
        font-size: .69rem;
    }

    .nd-step-hook {
        font-size: .82rem;
        margin-bottom: 3px;
    }

    .nd-step p {
        font-size: .82rem;
        line-height: 1.52;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    .nd-lad-st span {
        font-size: .79rem;
    }

    .nd-branch-card p {
        font-size: .8rem;
    }

    .nd-rem-card p {
        font-size: .78rem;
    }

    .nd-climb-row {
        padding: 6px 12px;
    }

    .nd-donut-split {
        font-size: .66rem;
    }

    /* §4 and §9 are the two that bind at 1366x768 — the single most
       common screen in a school computer lab, which is exactly where a
       coaching-centre buyer will open this page. */
    .nd-step {
        padding: 10px 15px;
    }

    .nd-step p {
        font-size: .8rem;
    }

    .nd-donut-svg {
        width: clamp(78px, 8.5vw, 94px);
        height: clamp(78px, 8.5vw, 94px);
    }

    .nd-donut-svg circle {
        stroke-width: 15;
    }

    .nd-donut-name {
        font-size: .86rem;
        margin-top: 8px;
    }

    .nd-donut-frac {
        font-size: .74rem;
    }

    .nd-total {
        padding: 10px 15px;
        margin-bottom: 13px;
    }

    .nd-key {
        font-size: .69rem;
        margin-top: 10px;
    }

    .nd-donut-name {
        margin-top: 7px;
    }

    .nd-donut-split {
        margin-top: 3px;
    }

    .nd-stat-scope {
        margin-top: 11px;
        padding-top: 10px;
        font-size: .7rem;
        line-height: 1.55;
    }
}

/* phone: the three donuts stack to one column rather than shrink to
   coins, and the ladder stations become a single reading column. */
@media (max-width: 639px) {
    .nd-donuts {
        grid-template-columns: 1fr;
        gap: 20px;
    }

    .nd-lad-stations {
        grid-template-columns: 1fr;
        gap: 16px;
    }

    .nd-lad-svg {
        display: none;
    }

    .nd-strand-row {
        grid-template-columns: 62px 1fr;
    }

    .nd-strand-row>em {
        grid-column: 2;
    }
}

/* ── reduced motion ──────────────────────────────────────────────
   The ladder trace draws itself in; under reduce it is simply
   already drawn. Nothing here re-adds motion the base file removed. */
.nd-lad-svg .trace {
    stroke-dasharray: 1400;
    stroke-dashoffset: 1400;
}

.nd-lad.in .trace {
    animation: ndTrace 1.5s var(--site-ease) forwards;
}

@keyframes ndTrace {
    to {
        stroke-dashoffset: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .nd-lad-svg .trace {
        stroke-dasharray: none;
        stroke-dashoffset: 0;
        animation: none;
    }

    .nd-lad.in .trace {
        animation: none;
    }
}

/* ════════════════════════════════════════════════════════════════
   17. NIA PAGE  (site/nia.html)

   Two new component families and nothing else. Everything structural
   on that page — .nd-vp, .nd-sec-head, .nd-points, .nd-steps,
   .nd-grid.g2, .nd-seg / .nd-panel, .nd-admit — already exists above
   and is reused verbatim.

     .nd-chat   a compact Nia panel. It is NOT a scaled copy of the
                real one in nia.css: that panel is 380px of docked
                column with a composer, a history drawer and a help
                sheet, none of which say anything to a reader. This
                keeps the four parts that carry the argument — the
                pulse, the context subtitle, two turns, the chips —
                and drops the rest. Budget: ~250px tall, because §3
                has to hold a segmented bar AND a panel AND a
                paragraph inside 800px of viewport.

     .nd-hl     the highlight-to-ask gesture, which is the one thing
                on this page that is genuinely better shown moving.
                Pure CSS off .nd-rv.in, so site.js needs no new code
                and the <noscript> block in the page head can undo it
                in three lines.
   ════════════════════════════════════════════════════════════════ */

/* ── a page with TWO sticky bars ────────────────────────────────
   .nd-vp's padding-top clears one bar. nia.html carries a sub-nav as
   well, so it clears two — and the clearance stays in PADDING, never
   in scroll-margin-top, for exactly the reason written above .nd-feat:
   scroll-margin offsets the snap position too and opens a gap at every
   snap point. With it in padding, `scroll-snap-align: start` and a
   sub-nav #anchor both land the section's top edge at the viewport top
   and the content sits below both bars either way. That is what lets
   nia.html keep html.nd-snap AND have working anchors, which
   features.html could not do when it used scroll-margin.

   --site-sub tracks the sub-nav's real height at each breakpoint. The
   bar itself gets slimmer on short screens, because 50px of chrome on
   a 720px viewport is 7% of the page budget spent on navigation. */
:root {
    --site-sub: 50px;
}

.nd-sub2 .nd-vp {
    padding-top: calc(var(--site-nav) + var(--site-sub) + 28px);
}

@media (min-width: 900px) {
    .nd-sub2 .nd-vp {
        padding-top: calc(var(--site-nav) + var(--site-sub) + 34px);
    }
}

@media (min-width: 900px) and (max-height: 940px) {
    :root {
        --site-sub: 42px;
    }

    .nd-sub2 .nd-vp {
        padding-top: calc(var(--site-nav) + var(--site-sub) + 18px);
        padding-bottom: 30px;
    }

    .nd-subnav a {
        padding: 10px 12px;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    :root {
        --site-sub: 38px;
    }

    .nd-sub2 .nd-vp {
        padding-top: calc(var(--site-nav) + var(--site-sub) + 14px);
        padding-bottom: 22px;
    }

    .nd-subnav a {
        padding: 8px 11px;
        font-size: .78rem;
    }
}

/* ── the context panel is two columns, not one left-hugging card ──
   A 520px chat alone in a 1180px wrap leaves half the section empty
   and reads as an unfinished layout. Pairing it with the paragraph
   that explains it fills the row, and — because the two sit side by
   side instead of stacked — takes about 80px off the tallest panel,
   which §2 needs. Stacks on a phone, chat first. */
.nd-chat-split {
    display: grid;
    gap: 18px;
    align-items: center;
}

.nd-chat-split .nd-body {
    max-width: 46ch;
}

@media (min-width: 900px) {
    .nd-chat-split {
        grid-template-columns: minmax(0, 520px) minmax(0, 1fr);
        gap: clamp(28px, 4vw, 56px);
    }
}

/* ── the pulse. Lifted from nia.css so the marketing page and the
      product beat at the same rate. One keyframe, two users. ── */
@keyframes ndBeat {

    0%,
    72%,
    100% {
        transform: scale(1);
        opacity: .9;
    }

    78% {
        transform: scale(1.6);
        opacity: 1;
    }

    84% {
        transform: scale(.82);
    }

    90% {
        transform: scale(1.28);
    }
}

.nd-chat {
    max-width: 520px;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 16px;
    box-shadow: var(--site-shadow);
    overflow: hidden;
}

.nd-chat-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 13px;
    background: var(--s50);
    border-bottom: 1px solid var(--s200);
}

.nd-chat-mark {
    width: 26px;
    height: 26px;
    flex: 0 0 26px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    background: linear-gradient(135deg, var(--g600) 0%, var(--indigo) 100%);
}

.nd-chat-mark s {
    display: block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #fff;
    animation: ndBeat 2.4s ease-in-out infinite;
}

.nd-chat-who {
    min-width: 0;
}

.nd-chat-who b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .83rem;
    line-height: 1.2;
    color: var(--s900);
}

/* Mirrors .nia-ai in mobile/nia.css — the AI label that sits beside
   the name in the real product. Kept here so the mockup on this page
   shows what a student actually sees. Change both together. */
.nd-chat-who .nd-chat-ai {
    display: inline-block;
    margin-left: 5px;
    padding: 0 4px;
    border-radius: 4px;
    background: var(--g50);
    color: var(--g600);
    border: 1px solid var(--g100);
    font-family: var(--font-body);
    font-size: .52rem;
    font-weight: 700;
    letter-spacing: .06em;
    vertical-align: 2px;
    line-height: 1.6;
}

/* The subtitle is the whole point of the component: it is the line
   that proves she knows which screen you are on. Ellipsis rather
   than wrap, so a long concept name cannot push the header to two
   rows and cost the section 22px it does not have. */
.nd-chat-who em {
    display: block;
    font-style: normal;
    font-size: .69rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--g600);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nd-chat-tag {
    margin-left: auto;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 9px;
    border-radius: 999px;
    background: var(--s100);
    color: var(--s500);
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.nd-chat-body {
    padding: 13px;
    display: grid;
    gap: 8px;
}

.nd-chat-msg {
    max-width: 88%;
    padding: 9px 12px;
    border-radius: 13px;
    font-size: .815rem;
    line-height: 1.56;
}

.nd-chat-msg.me {
    justify-self: end;
    background: var(--g600);
    color: #fff;
    border-bottom-right-radius: 5px;
}

.nd-chat-msg.nia {
    justify-self: start;
    background: var(--s50);
    border: 1px solid var(--s200);
    color: var(--s600);
    border-bottom-left-radius: 5px;
}

.nd-chat-msg.nia b {
    color: var(--s900);
    font-weight: 700;
}

.nd-chat-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 0 13px 12px;
}

.nd-chat-chips span {
    padding: 6px 11px;
    border-radius: 999px;
    border: 1px solid var(--g200);
    background: var(--g50);
    color: var(--g600);
    font-size: .715rem;
    font-weight: 600;
    line-height: 1.2;
}

.nd-chat-foot {
    padding: 8px 13px;
    border-top: 1px dashed var(--s200);
    font-size: .67rem;
    line-height: 1.5;
    color: var(--s400);
}

/* The locked state. A greyed-out chat would read as "broken"; an
   empty frame with a lock reads as "deliberately absent", which is
   the actual product behaviour and the better argument. */
.nd-chat.off {
    background: var(--s50);
    box-shadow: none;
}

.nd-chat.off .nd-chat-head {
    background: var(--s100);
}

.nd-chat.off .nd-chat-mark {
    background: var(--s300);
}

.nd-chat.off .nd-chat-mark s {
    animation: none;
    opacity: .8;
}

.nd-chat.off .nd-chat-who em {
    color: var(--s500);
}

.nd-chat-empty {
    padding: 30px 18px 34px;
    text-align: center;
}

.nd-chat-empty i {
    display: block;
    font-size: 1.35rem;
    color: var(--s300);
    margin-bottom: 10px;
}

.nd-chat-empty b {
    display: block;
    font-family: var(--font-display);
    font-size: .88rem;
    color: var(--s700);
    margin-bottom: 4px;
}

.nd-chat-empty span {
    display: block;
    font-size: .76rem;
    line-height: 1.55;
    color: var(--s500);
}

/* ── the highlight gesture ──────────────────────────────────────
   Three beats: the sweep, then the pill, then it stays. It runs
   once when the card reveals and never loops — an infinite loop in
   peripheral vision is the thing people close a tab over. */
.nd-hl {
    position: relative;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 16px;
    padding: 20px;
    box-shadow: var(--site-shadow);
}

.nd-hl-tag {
    font-family: var(--font-mono);
    font-size: .65rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--s400);
    margin-bottom: 10px;
}

.nd-hl p {
    font-size: .87rem;
    line-height: 1.72;
    color: var(--s700);
}

.nd-hl mark {
    background: linear-gradient(var(--g100), var(--g100)) left center / 0 100% no-repeat;
    color: inherit;
    border-radius: 3px;
    padding: 1px 0;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}

.nd-hl.in mark {
    animation: ndSweep .95s .35s var(--site-ease) forwards;
}

@keyframes ndSweep {
    to {
        background-size: 100% 100%;
    }
}

.nd-hl-pill {
    position: absolute;
    left: 20px;
    bottom: 18px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 14px;
    border-radius: 11px;
    background: var(--site-ink);
    color: #fff;
    font-size: .77rem;
    font-weight: 700;
    box-shadow: 0 12px 28px -12px rgba(11, 18, 32, .6);
    opacity: 0;
    transform: translateY(6px);
}

.nd-hl-pill i {
    color: var(--site-sky);
    font-size: .72rem;
}

.nd-hl.in .nd-hl-pill {
    animation: ndPop .38s 1.25s var(--site-ease) forwards;
}

@keyframes ndPop {
    to {
        opacity: 1;
        transform: none;
    }
}

/* The pill is absolutely positioned, so the card needs the room
   reserved for it or it lands on top of the last line of text. */
.nd-hl-space {
    height: 54px;
}

/* ── short viewports ────────────────────────────────────────────
   §3 (segmented bar + chat + paragraph) and §8 (four steps) are the
   two tightest sections on the page. Squeeze the chat internals,
   never the type. */
@media (min-width: 900px) and (max-height: 940px) {
    .nd-chat-body {
        padding: 11px;
        gap: 7px;
    }

    .nd-chat-msg {
        padding: 8px 11px;
        line-height: 1.5;
    }

    .nd-chat-chips {
        padding: 0 11px 10px;
    }

    .nd-chat-empty {
        padding: 22px 16px 26px;
    }

    .nd-hl {
        padding: 17px;
    }

    .nd-hl p {
        line-height: 1.62;
    }

    .nd-hl-space {
        height: 48px;
    }
}

/* ── step density on short screens ──────────────────────────────
   Four .nd-step rows plus a head and an admit is the tightest thing
   on nia.html (§8) and the 940px block does not take enough back at
   800px. 4px of vertical padding a row is invisible; across four
   rows and their gaps it is ~38px, which is the difference between
   fitting and not.

   Deliberately NOT scoped to the Nia page: protocol.html §4 is five
   steps and is the tightest section on that page too, so it gets the
   same relief. Nothing else in the file uses .nd-step. */
@media (min-width: 900px) and (max-height: 800px) {
    .nd-steps {
        gap: 10px;
    }

    .nd-step {
        padding: 13px 16px;
    }

    .nd-step p {
        line-height: 1.52;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    .nd-chat-msg {
        font-size: .78rem;
    }

    .nd-chat-foot {
        padding: 6px 11px;
        font-size: .64rem;
    }

    .nd-hl p {
        font-size: .82rem;
    }
}

/* Phone: the chat is the argument, so it goes full width rather
   than sitting in a 520px box with air either side. */
@media (max-width: 639px) {
    .nd-chat {
        max-width: none;
    }
}

/* ── reduced motion ─────────────────────────────────────────────
   Both the pulse and the sweep are decorative. Under reduce the
   sweep is simply already swept and the pill already placed, so the
   card still says the same thing without anything moving. */
@media (prefers-reduced-motion: reduce) {
    .nd-chat-mark s {
        animation: none;
    }

    .nd-hl mark,
    .nd-hl.in mark {
        animation: none;
        background-size: 100% 100%;
    }

    .nd-hl-pill,
    .nd-hl.in .nd-hl-pill {
        animation: none;
        opacity: 1;
        transform: none;
    }
}


/* ════════════════════════════════════════════════════════════════
   18. AUDIT FIGURES  (index.html §2)

   The credibility band used to be a half-height strip under the hero,
   carrying three counts from the Biology-only audit. Two things forced
   this component:

     The audit finished. protocol.html §10 now holds a full 180-question
     result across all three subjects, and the landing page was still
     quoting the Biology-only slice with "Physics and Chemistry audits
     are in progress". A landing page contradicting the evidence page is
     worse than no landing figure at all.

     Three numbers now do the work of ten. .nd-stat-num is 6.2rem — it
     is built for ONE hero figure and three of them at that size is a
     scoreboard, not a claim. .nd-audit-row's 1.5rem is a list row and
     reads as small print. This sits between the two and is the only
     size at which "173/180" and "692/720" can stand side by side.

   The full per-subject split, the donuts and the misses stay on
   protocol.html. This is the headline and the link, nothing more.
   ════════════════════════════════════════════════════════════════ */

.nd-figs {
    display: grid;
    gap: 12px;
}

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

.nd-fig {
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 16px;
    padding: 20px;
    box-shadow: var(--site-shadow);
}

.nd-fig b {
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.85rem, 3.5vw, 2.6rem);
    line-height: 1;
    letter-spacing: -.035em;
    color: var(--g600);
}

.nd-fig em {
    display: block;
    font-style: normal;
    margin-top: 6px;
    font-family: var(--font-mono);
    font-size: .65rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--s400);
}

.nd-fig span {
    display: block;
    margin-top: 11px;
    font-size: .825rem;
    line-height: 1.55;
    color: var(--s600);
}

/* The marks figure is the one a parent reads. Give it the edge — the
   same treatment .nd-step.key gets for the move nobody else makes. */
.nd-fig.key {
    border-color: var(--g500);
    background: var(--g50);
}

.nd-fig.key span {
    color: var(--s700);
}

@media (min-width: 900px) and (max-height: 940px) {
    .nd-fig {
        padding: 16px 17px;
    }

    .nd-fig span {
        margin-top: 9px;
        font-size: .8rem;
        line-height: 1.5;
    }
}


/* ════════════════════════════════════════════════════════════════
   19. MOBILE HARDENING

   Reported symptom: "the lines go out of frame on mobile and it side
   scrolls." A static min-content pass over all four pages at 320, 360
   and 390px found no box wider than the viewport, so this is not an
   element overflowing — it is the horizontal RAILS behaving badly.

   There are five of them: .nd-subnav-in, .nd-seg, .nd-mods (the phone
   module rail), .nd-cs-tabs and .nd-cmp-scroll. Three problems, all
   fixed here:

   1. SCROLL CHAINING. overscroll-behavior was set nowhere in the file.
      Swipe a rail to its end on a phone and the gesture chains into the
      page — or into the browser's back-swipe. Reads exactly like "the
      page scrolls sideways", and it got much worse the day a full-bleed
      sub-nav landed at the top of every screen. contain stops it.

   2. THE VIEWPORT ITSELF. html had no overflow-x and body had hidden.
      Body's value does propagate to the viewport, but propagation makes
      BODY a scroll container — which is the classic way position:sticky
      dies, and all three pages now have a sticky sub-nav. clip does the
      same clipping without creating a scroll container, so sticky keeps
      working. hidden stays first as the pre-Safari-16 fallback.

   3. NO EDGE AFFORDANCE. A nine-item sub-nav on a 360px screen cuts the
      last item off mid-word against a hard edge with nothing to say it
      scrolls. That IS "lines going out of frame". A mask fade on the
      right turns a bug into an affordance.
   ════════════════════════════════════════════════════════════════ */

/* ⚠ overscroll-behavior MUST be on the ROOT element.
   It propagates to the viewport only from <html>. On <body> it is
   silently ignored — unlike `overflow`, which does propagate from body
   when html is visible. That one-line difference is why the interior
   pages still scrolled sideways on a real phone after the §19 fix: the
   rails were contained, but the viewport itself was never told to
   refuse the chained gesture.

   The device measurements made the mechanism unambiguous. Overflow
   equalled scrollX exactly, on every sample — 65/65, 82/83, 69/69 —
   while body.scrollWidth stayed pinned at the viewport width and every
   fixed layer measured exactly 390. Nothing was too wide. What happens
   is a feedback loop: a swipe chains out of a rail and nudges the page
   sideways; a position:fixed element stays at viewport left:0, which in
   DOCUMENT coordinates is now x=scrollX; documentElement.scrollWidth
   counts fixed layers, so the document reports itself wider by exactly
   the amount scrolled, which permits more scrolling. The white gap is
   that loop, not a layout fault — which is why no element could ever be
   found to blame for it. */

html {
    overflow-x: hidden;
    overflow-x: clip;
    overscroll-behavior-x: none;
}

body {
    overflow-x: clip;
    overscroll-behavior-x: none;
}

.nd-subnav-in,
.nd-seg,
.nd-mods,
.nd-cs-tabs,
.nd-cmp-scroll {
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
}

/* Fade the right edge of the sub-nav only while it actually overflows.
   A two-item sub-nav on a wide phone must not look clipped, so the mask
   is applied on the scroll container and sized off its own padding —
   when there is nothing to scroll the fade sits over the gutter and is
   invisible anyway. */
@media (max-width: 899px) {
    .nd-subnav-in {
        gap: 4px;
        -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 34px), transparent 100%);
        mask-image: linear-gradient(90deg, #000 calc(100% - 34px), transparent 100%);
        scroll-padding-inline: var(--site-gut);
    }

    .nd-subnav a {
        scroll-snap-align: start;
    }

    .nd-subnav-in {
        scroll-snap-type: x proximity;
    }
}

/* ── shrink guards ───────────────────────────────────────────────
   ⚠ THIS LIST WAS WRONG ONCE. min-width:0 is only ever correct on a
   child that is genuinely flexible AND whose text can wrap. Put it on
   an `auto` grid track, or on anything holding white-space:nowrap, and
   the track shrinks below its own content and the text spills sideways
   across its neighbour — which is exactly what .nd-climb-row did
   ("Foundation · all easy" printing on top of "10 Q · 8 min") and what
   .nd-fan-row's PYQ count did. Both are back off the list.

   The rule of thumb: if the child sits in a 1fr track or is a wrapping
   paragraph, it belongs here. If it sits in an `auto` track, or it is
   nowrap, it does not — it needs a stacking rule at a breakpoint
   instead, which is what the tablet tier below provides. */
.nd-point-txt,
.nd-step>div,
.nd-chat-who,
.nd-rung>div,
.nd-opt>*,
.nd-fig,
.nd-card {
    min-width: 0;
}

/* Last-resort guard for a long unbreakable token — a chapter slug, a
   pasted URL, a formula. Breaking mid-word is ugly; a page that scrolls
   sideways on a phone is worse. */
@media (max-width: 639px) {

    .nd-body,
    .nd-lead,
    .nd-point-txt span,
    .nd-step p,
    .nd-fig span,
    .nd-admit span,
    .nd-chat-msg {
        overflow-wrap: anywhere;
    }

    /* The h0 is the one place a long word can genuinely outrun a 320px
       screen, because its clamp floor is 2.3rem regardless of width. */
    .nd-h0,
    .nd-h1 {
        overflow-wrap: break-word;
    }
}


/* ════════════════════════════════════════════════════════════════
   20. THE TABLET TIER  (640px – 899px)

   This band had almost nothing written for it, and that is the gap the
   reported breakage falls into. Two breakpoints do all the work in this
   file: 640px turns simple grids from one column to two, and 900px
   turns on every real two-column split (.nd-split, .nd-hero-in,
   .nd-feat-body, .nd-chat-split) plus the wider gutter.

   But the ROW components — .nd-climb-row, .nd-strand-row, .nd-fan-row,
   .nd-donuts, .nd-lad-stations — only ever got their stacking rules at
   max-width:639px. So from 640 to 899 they hold their full desktop
   three-track shape, and once .nd-figs went to three columns at 640 the
   band had genuinely tight rows in it too. Anything with a fixed track
   and a nowrap sibling starts colliding well before it starts
   overflowing, which is why the checker stayed quiet: a collision is
   not an overflow.

   The fix is to move every stacking rule that said 639 up to 899, so a
   row is either in its desktop shape with a desktop-width container, or
   stacked. There is no in-between state any more.
   ════════════════════════════════════════════════════════════════ */

@media (max-width: 899px) {

    /* Three donuts side by side need ~110px each plus their captions;
       below the split breakpoint they get a column instead. */
    .nd-donuts,
    .nd-lad-stations {
        grid-template-columns: 1fr;
    }

    /* The count drops to its own row rather than fighting the label for
       an `auto` track that cannot give. */
    .nd-strand-row {
        grid-template-columns: 62px 1fr;
    }

    .nd-strand-row>em {
        grid-column: 2;
    }

    .nd-climb-row {
        grid-template-columns: auto 1fr;
        row-gap: 4px;
    }

    .nd-climb-row em {
        grid-column: 2;
    }

    .nd-fan-row {
        flex-wrap: wrap;
    }

    .nd-fan-row em {
        margin-left: 0;
        flex-basis: 100%;
    }

    /* 692 / 720 at 1.85rem does not fit a 186px column, which is what a
       three-up becomes at 640. Two-up, then three at 760. */
    .nd-figs {
        grid-template-columns: 1fr;
    }

    /* Same fade the sub-nav gets. A segmented control whose last tab is
       sliced in half against a hard edge reads as broken markup; with a
       fade it reads as a rail, which is what it is. */
    .nd-seg {
        -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 30px), transparent 100%);
        mask-image: linear-gradient(90deg, #000 calc(100% - 30px), transparent 100%);
    }

    /* Long-token guard moves up with everything else — a 640px column
       is no safer than a 380px one for an unbreakable string. */
    .nd-body,
    .nd-lead,
    .nd-point-txt span,
    .nd-step p,
    .nd-fig span,
    .nd-admit span,
    .nd-chat-msg {
        overflow-wrap: anywhere;
    }

    .nd-h0,
    .nd-h1 {
        overflow-wrap: break-word;
    }
}

@media (min-width: 760px) and (max-width: 899px) {
    .nd-figs {
        grid-template-columns: repeat(3, 1fr);
    }
}


/* ════════════════════════════════════════════════════════════════
   21. THE .nd-vp GRID-ITEM BLOWOUT

   Reported: index #who, protocol #questions and nia #screens run off
   the right edge with no way to scroll to what is out there. Those are
   three of the only four sections on the site that contain a .nd-seg
   (the fourth is features #roles, same bug, just further down the page).

   MECHANISM. .nd-vp is `display: grid` — it has to be, for `align-content:
   safe center` to do the vertical centring the whole one-screen-one-section
   contract depends on. That makes .nd-wrap a GRID ITEM, and a grid item's
   default `min-width: auto` gives the auto track a floor equal to the
   item's min-content contribution. A track floor beats the container's
   width: if anything inside .nd-wrap reports a min-content wider than the
   viewport, the column simply grows past it. .nd-wrap's own
   `max-width: 1180px` does not save you, because max-width is applied to
   the item AFTER the track has already been sized.

   Then §19's `overflow-x: clip` hides the overflow — so instead of a
   scrollbar you get content silently amputated at the edge. Clip is still
   right; it was showing the symptom, not causing it.

   `min-width: 0` on the item restores the sane behaviour: the track is
   bounded by the container and children wrap or scroll inside it.

   This is the single most load-bearing rule in the file for narrow
   screens. Do not remove it while .nd-vp is a grid.
   ════════════════════════════════════════════════════════════════ */

.nd-vp>*,
.nd-wrap,
.nd-seg,
.nd-subnav-in,
.nd-mods,
.nd-cs-tabs,
.nd-cmp-scroll {
    min-width: 0;
}

/* ── .nd-seg stops being a rail on narrow screens ────────────────
   Even with the blowout fixed, a horizontally scrolling segmented
   control is a poor phone control: the tabs ARE the section's table of
   contents, and half of them sitting off-screen behind a fade means
   nobody discovers "During a test" — which on nia.html is the single
   best panel in the section.

   Four or five short tabs fit two-up comfortably, so below 900px the
   control becomes a wrapping grid instead. Nothing scrolls, nothing is
   cut off, and the mask from §20 is switched back off because there is
   no longer an edge to fade. A five-tab control (protocol #questions)
   lands 2/2/1, which is fine — they are numbered.

   .nd-seg is a flex container in JS's eyes either way; initSeg only ever
   reads data-panel off the buttons, so this is purely visual. */
@media (max-width: 899px) {
    .nd-seg {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 5px;
        overflow-x: visible;
        -webkit-mask-image: none;
        mask-image: none;
    }

    .nd-seg button {
        flex: none;
        min-width: 0;
        padding: 0 12px;
        font-size: .82rem;
        white-space: normal;
        line-height: 1.25;
        text-align: center;
    }
}

/* One tab per row under ~400px: two 12px-padded tabs plus a gap needs
   about 175px each, and "Anywhere else" does not survive being wrapped
   into a 150px box. */
@media (max-width: 399px) {
    .nd-seg {
        grid-template-columns: minmax(0, 1fr);
    }
}


/* ── 320px stragglers ────────────────────────────────────────────
   Turned up once the checker stopped assuming scroll containers absorb
   their contents. Two shapes, both only at the very bottom of the range:

   .nd-price-mini .nd-card — the price and the long product names
   ("Schools & institutes", "₹4,500") set a min-content the 276px content
   box of a 320px screen cannot meet.

   .nd-shot / .mk — the pure-CSS product mockups on features.html are
   built from fixed-px parts (a 76px ring, 28-32px icons, their gaps) and
   were never told they could scale. They cannot reflow, so they get to
   scroll inside their own figure instead — a mockup is an illustration,
   and a slightly croppable illustration beats a page that cannot be
   read. */
@media (max-width: 480px) {

    .nd-price-mini .nd-card h3,
    .nd-price-mini .nd-card b,
    .nd-price-mini .nd-card p {
        overflow-wrap: anywhere;
    }

    .nd-shot,
    .nd-shot-alt {
        min-width: 0;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
    }

    .nd-shot::-webkit-scrollbar,
    .nd-shot-alt::-webkit-scrollbar {
        display: none;
    }

    .nd-feat-art,
    .nd-feat-body {
        min-width: 0;
    }
}

/* ════════════════════════════════════════════════════════════════
   16. PARENTS PAGE  (parents.html)

   Nine .nd-vp sections under a sub-nav, so the page carries
   body.nd-sub2 and html.nd-snap — same contract as nia.html. The
   clearance for BOTH sticky bars lives in .nd-sub2 .nd-vp's PADDING,
   never in scroll-margin-top, which would offset the snap position
   and open a gap at every snap point.

   Deliberately NOT using .nd-band for the tinted sections. .nd-band
   sets `padding` as a shorthand, which nia.html then has to cancel
   with an inline `padding-top:0` — and that inline also cancels the
   .nd-sub2 clearance, leaving the section's top edge under the bars.
   A background-only class avoids the whole collision.

   Every mockup here is a real parent-portal screen redrawn in site
   vocabulary. The numbers are illustrative but the SHAPES are not:
   a gated metric really does render as "not enough yet" rather than
   0%, and the map really does show untouched chapters. If the
   product changes shape, these change with it.
   ════════════════════════════════════════════════════════════════ */

:root {
    /* Namespaced per the contract in §1. --green-600 exists as a token
       but has no background pair, and the parent portal needs one for
       "finished" and "correct". */
    --site-ok: #16a34a;
    --site-ok-bg: #e9f7ee;
    --site-ok-ink: #157f3c;
}

/* background-only tints — see the note above on .nd-band */
.nd-pa-tint {
    background: var(--g50);
}

.nd-pa-wash {
    background: var(--s50);
}

/* ── the section body: one mockup beside its four points ─────────
   Art comes FIRST in source order on every section, because on a
   phone the screenshot is the argument and the four points are the
   footnotes. On desktop `.flip` moves it to the right-hand column,
   alternating down the page. */
.nd-pa-split {
    display: grid;
    gap: clamp(20px, 3vw, 40px);
    align-items: center;
}

.nd-pa-art {
    min-width: 0;
}

/* .mk's own shadow is tuned for the ink hero. These sit on white and
   on --g50, so they take the site's light-surface shadow instead. */
.nd-pa-art .mk {
    border-color: var(--s200);
    box-shadow: var(--site-shadow);
}

.nd-pa-side {
    min-width: 0;
}

@media (min-width: 900px) {
    .nd-pa-split {
        grid-template-columns: 1.04fr .96fr;
    }

    .nd-pa-split.flip .nd-pa-art {
        order: 2;
    }
}

/* On a phone the mockups are the tightest thing on the page. Capping
   their width stops a 24-tile chapter map stretching to 700px on a
   tablet, where the tiles read as a bar chart rather than a syllabus. */
.nd-pa-art>.mk {
    max-width: 460px;
}

@media (min-width: 900px) {
    .nd-pa-art>.mk {
        max-width: none;
    }
}


/* ════ §2 · CONSENT — the switch that lives on the student's phone ════ */

.mk-tog {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 12px;
    border: 1px solid var(--s200);
    border-radius: 11px;
}

.mk-tog+.mk-tog {
    margin-top: 7px;
}

.mk-tog .nd-ico {
    width: 30px;
    height: 30px;
    flex-basis: 30px;
    border-radius: 9px;
    font-size: .72rem;
}

.mk-tog div {
    flex: 1;
    min-width: 0;
}

.mk-tog b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .755rem;
    color: var(--s900);
    line-height: 1.3;
}

.mk-tog span {
    display: block;
    font-size: .645rem;
    line-height: 1.45;
    color: var(--s500);
    margin-top: 2px;
}

/* the switch itself — a picture of a control, never a control */
.mk-sw {
    flex: 0 0 34px;
    width: 34px;
    height: 20px;
    border-radius: 99px;
    background: var(--s300);
    position: relative;
}

.mk-sw::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 99px;
    background: #fff;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .3);
}

.mk-sw.on {
    background: var(--site-ok);
}

.mk-sw.on::after {
    left: 16px;
}


/* ════ §3 · HOME — the sentence, the alert, the two gated metrics ════ */

/* The headline is a SENTENCE, and it has to look like one. A card with
   a big number in it would be exactly the thing this screen refuses.

   NOT .mk-say — that name is already the Nia chat bubble row in §13, and
   it carries `display:flex`. A rule that only sets background and padding
   loses to it silently: every <b> in the sentence becomes its own flex
   item and the paragraph renders as four ragged columns. Before adding a
   mk- class, grep for it. */
.mk-line {
    background: var(--g50);
    border: 1px solid var(--g100);
    border-left: 3px solid var(--g500);
    border-radius: 4px 12px 12px 4px;
    padding: 11px 13px;
    font-size: .765rem;
    line-height: 1.52;
    color: var(--s700);
}

.mk-line b {
    color: var(--g700);
    font-weight: 700;
}

.mk-week {
    display: flex;
    gap: 4px;
    margin-top: 9px;
}

.mk-week i {
    flex: 1;
    height: 25px;
    border-radius: 7px;
    background: var(--s100);
    display: grid;
    place-items: center;
    font-style: normal;
    font-size: .55rem;
    font-weight: 700;
    color: var(--s400);
}

.mk-week i.on {
    background: var(--g500);
    color: #fff;
}

/* An alert with a next step attached. Only the FIRST one ever carries
   the `em` line — see parent_home._needs_you(). */
.mk-alert {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    margin-top: 9px;
    padding: 10px 12px;
    border-radius: 12px;
    background: var(--amber-bg);
    border: 1px solid rgba(192, 124, 18, .24);
}

/* 32px, matching .nd-ico.sm in the points column beside it. At 28px it
   read as undersized against a panel this wide. */
.mk-alert .nd-ico {
    width: 32px;
    height: 32px;
    flex-basis: 32px;
    border-radius: 9px;
    font-size: .8rem;
    background: rgba(192, 124, 18, .15);
    color: var(--amber);
}

/* .nd-ico centres its contents with place-items, but a Font Awesome glyph
   still sits on a baseline inside a line box that reserves descender
   space — so a glyph with no descender (the warning triangle, the shield)
   renders visibly above centre. line-height:1 collapses that reserve.
   Scoped to this page's mockups so nothing else moves. */
.nd-pa-art .nd-ico i {
    display: block;
    line-height: 1;
}

.mk-alert div {
    flex: 1;
    min-width: 0;
}

.mk-alert b {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .755rem;
    color: var(--s900);
    line-height: 1.3;
}

.mk-alert span {
    display: block;
    font-size: .655rem;
    line-height: 1.45;
    color: var(--s600);
    margin-top: 2px;
}

.mk-alert em {
    display: block;
    font-style: normal;
    margin-top: 7px;
    padding-top: 7px;
    border-top: 1px dashed rgba(192, 124, 18, .34);
    font-size: .645rem;
    line-height: 1.5;
    color: var(--s600);
}

.mk-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 7px;
    margin-top: 9px;
}

.mk-metric {
    border: 1px solid var(--s200);
    border-radius: 12px;
    padding: 10px 11px;
}

.mk-metric span {
    display: block;
    font-size: .585rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--s500);
    line-height: 1.4;
}

.mk-metric b {
    display: block;
    margin-top: 5px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.3rem;
    line-height: 1;
    color: var(--s900);
}

.mk-metric i {
    display: block;
    font-style: normal;
    margin-top: 4px;
    font-size: .63rem;
    color: var(--s500);
}

.mk-metric i.up {
    color: var(--site-ok-ink);
    font-weight: 700;
}

/* A number that has not earned the right to be stated. This is the
   whole argument of the page rendered as one card, so it must not
   look like an error or an empty state — it looks like a fact. */
.mk-metric.gate {
    background: var(--s50);
    border-style: dashed;
}

.mk-metric.gate b {
    font-family: var(--font-body);
    font-weight: 700;
    font-size: .8rem;
    color: var(--s400);
    line-height: 1.35;
    margin-top: 6px;
}


/* ════ §4 · LEARNING — the syllabus map ════ */

.mk-grp {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    font-size: .625rem;
    font-weight: 700;
    color: var(--s600);
    margin: 11px 0 5px;
}

.mk-grp:first-of-type {
    margin-top: 0;
}

.mk-grp em {
    font-style: normal;
    font-weight: 600;
    color: var(--s400);
    font-size: .59rem;
}

.mk-map {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    gap: 4px;
}

/* The five states colour the map tile and the legend swatch from the
   SAME rule. A legend that repeats the colours in its own selector is
   a legend that will eventually be wrong. */
.mk-map i,
.mk-key s {
    background: #fff;
    border: 1px solid var(--s200);
}

.mk-map i.reading,
.mk-key s.reading {
    background: var(--g100);
    border-color: var(--g200);
}

.mk-map i.ro,
.mk-key s.ro {
    background: var(--amber-bg);
    border-color: rgba(192, 124, 18, .34);
}

.mk-map i.testing,
.mk-key s.testing {
    background: var(--purple-bg);
    border-color: rgba(21, 94, 99, .34);
}

.mk-map i.done,
.mk-key s.done {
    background: var(--site-ok);
    border-color: var(--site-ok);
}

.mk-map i {
    height: 20px;
    border-radius: 5px;
}

.mk-key {
    display: flex;
    flex-wrap: wrap;
    gap: 5px 11px;
    margin-top: 11px;
    padding-top: 9px;
    border-top: 1px solid var(--s100);
}

.mk-key span {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .59rem;
    color: var(--s500);
}

/* <s> rather than a pseudo-element so the swatch can carry the same
   state class the tile does — see the shared rule above. */
.mk-key s {
    display: block;
    width: 9px;
    height: 9px;
    flex: 0 0 9px;
    border-radius: 3px;
    text-decoration: none;
}


/* ════ §5 · TESTS — one wrong answer, opened ════ */

.mk-stem {
    font-size: .735rem;
    line-height: 1.5;
    color: var(--s800);
    margin-bottom: 9px;
}

.mk-opt {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 10px;
    border: 1px solid var(--s200);
    border-radius: 9px;
    font-size: .695rem;
    line-height: 1.35;
    color: var(--s600);
}

.mk-opt+.mk-opt {
    margin-top: 5px;
}

.mk-opt s {
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    border-radius: 99px;
    border: 1px solid var(--s300);
    display: grid;
    place-items: center;
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: .55rem;
    font-weight: 700;
    color: var(--s500);
}

.mk-opt u {
    margin-left: auto;
    text-decoration: none;
    font-size: .58rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
}

.mk-opt.picked {
    border-color: var(--red);
    background: var(--red-bg);
    color: var(--red);
}

.mk-opt.picked s {
    border-color: var(--red);
    background: var(--red);
    color: #fff;
}

.mk-opt.right {
    border-color: var(--site-ok);
    background: var(--site-ok-bg);
    color: var(--site-ok-ink);
}

.mk-opt.right s {
    border-color: var(--site-ok);
    background: var(--site-ok);
    color: #fff;
}

/* The distractor explanation. Dashed, because it is commentary on the
   question rather than part of it. */
.mk-why {
    margin-top: 9px;
    padding: 9px 11px;
    border-radius: 10px;
    background: var(--s50);
    border: 1px dashed var(--s300);
    font-size: .665rem;
    line-height: 1.55;
    color: var(--s600);
}

.mk-why b {
    color: var(--s800);
}


/* ════ §6 · INSIGHTS — when the testing actually happens ════ */

.mk-hrs {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 72px;
}

.mk-hrs i {
    flex: 1;
    min-height: 2px;
    border-radius: 3px 3px 0 0;
    background: var(--g200);
}

/* After 10pm. Red because bedtime is squarely a parent's business in a
   way that osmosis is not — this is the one bar colour on the page
   that is a judgement, and it is the parent's to make. */
.mk-hrs i.late {
    background: var(--red);
    opacity: .74;
}

.mk-hrs-ax {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid var(--s100);
    font-family: var(--font-mono);
    font-size: .55rem;
    color: var(--s400);
}


/* ════ §8 · THE RULES ════ */

/* Not .nd-grid.g3: that helper is one column between 640px and 900px,
   which turns six cards into a column a tablet reader never reaches
   the bottom of. Two, then three. */
.nd-pa-rules {
    display: grid;
    gap: 13px;
}

@media (min-width: 620px) {
    .nd-pa-rules {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 900px) {
    .nd-pa-rules {
        grid-template-columns: repeat(3, 1fr);
    }
}

.nd-pa-rule {
    padding: 17px 18px;
}

.nd-pa-rule h3 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .89rem;
    line-height: 1.32;
    color: var(--s900);
    margin-bottom: 6px;
}

.nd-pa-rule p {
    font-size: .795rem;
    line-height: 1.55;
    color: var(--s600);
}

.nd-pa-rule .nd-pa-n {
    display: block;
    font-family: var(--font-mono);
    font-size: .6rem;
    font-weight: 700;
    letter-spacing: .1em;
    color: var(--g500);
    margin-bottom: 8px;
}


/* ── SHORT LAPTOPS ────────────────────────────────────────────────
   Nine full-viewport sections on a 13" screen. The two height steps
   match the ones already in place for index.html and nia.html: type,
   gaps and mockup padding come down together rather than one at a
   time, because shrinking type alone leaves the whitespace looking
   like a mistake. */

@media (min-width: 900px) and (max-height: 940px) {
    .nd-pa-split {
        gap: clamp(18px, 2.4vw, 30px);
    }

    .nd-pa-rule {
        padding: 14px 16px;
    }

    .nd-pa-rule p {
        font-size: .77rem;
    }

    .mk-map i {
        height: 17px;
    }

    .mk-hrs {
        height: 62px;
    }

    .mk-week i {
        height: 22px;
    }

    .nd-pa-art .mk {
        padding: 13px;
    }

    /* Four points beside a mockup is the tallest thing in §3-§7, and
       the points are the column that overflows first. Scoped to
       .nd-pa-split so the same list on features.html is untouched. */
    .nd-pa-split .nd-points {
        gap: 13px;
    }

    .nd-pa-split .nd-point-txt span {
        font-size: .825rem;
        line-height: 1.5;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    .nd-pa-rule {
        padding: 12px 14px;
    }

    .nd-pa-art .mk {
        padding: 12px;
    }

    .nd-pa-split .nd-points {
        gap: 11px;
    }

    .nd-pa-split .nd-point-txt strong {
        font-size: .875rem;
    }

    .nd-pa-split .nd-point-txt span {
        font-size: .785rem;
        line-height: 1.48;
    }

    .nd-pa-rule h3 {
        font-size: .84rem;
    }

    .nd-pa-rule p {
        font-size: .745rem;
        line-height: 1.5;
    }

    .nd-pa-rule .nd-pa-n {
        margin-bottom: 5px;
    }

    .mk-map i {
        height: 15px;
    }

    .mk-hrs {
        height: 54px;
    }

    .mk-week i {
        height: 20px;
    }

    .mk-alert em {
        margin-top: 6px;
        padding-top: 6px;
    }
}


/* ── REDUCED MOTION ───────────────────────────────────────────────
   Nothing on this page animates beyond the shared .nd-rv reveal and
   the ink drift, both already handled in §14. Stated here so the next
   person adding an ambient loop to a mockup knows where it goes. */


/* ════════════════════════════════════════════════════════════════
   17. TEACHERS PAGE  (teachers.html)

   Twelve .nd-vp sections under a ten-anchor sub-nav. Same contract as
   parents.html: html.nd-snap + body.nd-sub2, clearance for BOTH sticky
   bars in .nd-sub2 .nd-vp's PADDING, never scroll-margin-top.

   REUSES §16 RATHER THAN RESTATING IT
   .nd-pa-split / .nd-pa-art / .nd-pa-side / .nd-pa-tint / .nd-pa-wash /
   .nd-pa-rules / .nd-pa-rule and the short-laptop trims that go with
   them are all shared with parents.html. The `pa-` prefix is historical
   — both audience pages are one layout. Not renamed, because a rename
   means editing a shipped page for a cosmetic reason and risking the
   .mk-say class of bug for nothing.

   NEW CLASSES ARE PREFIXED mk-t
   The mk- namespace already holds 31 names across features.html and
   parents.html. .mk-say cost a rendering bug on parents.html because a
   new rule set background and padding but not `display`, and lost
   silently to an existing flex rule. Every mockup class added here
   carries the mk-t prefix and was checked against the full list first.
   ════════════════════════════════════════════════════════════════ */


/* ════ §2 · THE STUDENT RECORD ════ */

.mk-tav {
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
    border-radius: 10px;
    display: grid;
    place-items: center;
    background: var(--g600);
    color: #fff;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .72rem;
}

/* Four headline numbers. Two-up on a phone — four 80px columns turn
   "GETTING RIGHT" into four wrapped lines. */
.mk-tquad {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
    margin-top: 10px;
}

@media (min-width: 430px) {
    .mk-tquad {
        grid-template-columns: repeat(4, 1fr);
    }
}

.mk-tquad .mk-metric {
    padding: 8px 9px;
}

.mk-tquad .mk-metric b {
    font-size: 1.02rem;
    margin-top: 3px;
}

.mk-tquad .mk-metric i {
    font-size: .585rem;
}


/* ════ §3 · THE DISTRACTOR THEY KEEP CHOOSING ════ */

/* Red, and it is the one red thing on the page that is not an alert.
   A repeated wrong option is not a warning about the student — it is
   the single most specific piece of teaching information in the
   product, and it earns the emphasis. */
.mk-tdist {
    display: flex;
    gap: 11px;
    align-items: flex-start;
    padding: 11px 12px;
    border-radius: 12px;
    background: var(--red-bg);
    border: 1px solid rgba(196, 61, 61, .24);
}

.mk-tdist-n {
    flex: 0 0 34px;
    height: 25px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    background: var(--red);
    color: #fff;
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: .67rem;
}

.mk-tdist div {
    flex: 1;
    min-width: 0;
}

.mk-tdist b {
    display: block;
    font-size: .73rem;
    font-weight: 600;
    line-height: 1.42;
    color: var(--s900);
}

.mk-tdist span {
    display: block;
    margin-top: 3px;
    font-size: .64rem;
    font-weight: 700;
    color: var(--red);
}

.mk-ttrick {
    margin-top: 7px;
    padding: 8px 10px;
    border-radius: 4px 10px 10px 4px;
    background: var(--g50);
    border-left: 3px solid var(--g500);
    font-size: .665rem;
    line-height: 1.5;
    color: var(--s600);
}

.mk-ttrick b {
    color: var(--g700);
}


/* ════ §4 · NOTES AND FOLLOW-UPS ════ */

.mk-tne {
    padding: 10px 11px;
    border: 1px solid var(--s200);
    border-radius: 11px;
}

.mk-tne+.mk-tne {
    margin-top: 6px;
}

.mk-tne p {
    font-size: .7rem;
    line-height: 1.5;
    color: var(--s700);
}

.mk-tne-f {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-top: 7px;
    padding-top: 7px;
    border-top: 1px solid var(--s100);
    font-size: .6rem;
    color: var(--s500);
}

.mk-tne-f em {
    font-style: normal;
    margin-left: auto;
}

.mk-tne-f i {
    font-size: .58rem;
    color: var(--s400);
}

/* The same note, four days later, as it surfaces on Home. */
.mk-tdue {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 11px;
    border-radius: 11px;
    background: var(--amber-bg);
    border: 1px solid rgba(192, 124, 18, .24);
}

.mk-tdue div {
    flex: 1;
    min-width: 0;
}

.mk-tdue b {
    display: block;
    font-family: var(--font-display);
    font-size: .72rem;
    color: var(--s900);
}

.mk-tdue span {
    display: block;
    margin-top: 2px;
    font-size: .63rem;
    line-height: 1.4;
    color: var(--s600);
}

.mk-tdue em {
    flex: 0 0 auto;
    font-style: normal;
    font-size: .6rem;
    font-weight: 700;
    color: var(--amber);
}


/* ════ §5 · TWO TEACHERS, SIDE BY SIDE ════ */

.mk-tsplit {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.mk-tcol {
    border: 1px solid var(--s200);
    border-radius: 11px;
    padding: 10px;
    min-width: 0;
}

.mk-tcol.key {
    border-color: var(--purple);
    background: var(--purple-bg);
}

.mk-tcol>b {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-display);
    font-size: .695rem;
    font-weight: 700;
    color: var(--s900);
    margin-bottom: 8px;
}

.mk-tcol>b i {
    font-size: .62rem;
    color: var(--g500);
}

.mk-tcol.key>b i {
    color: var(--purple);
}

.mk-tcol ul {
    list-style: none;
    display: grid;
    gap: 5px;
}

.mk-tcol li {
    position: relative;
    padding-left: 12px;
    font-size: .63rem;
    line-height: 1.42;
    color: var(--s600);
}

.mk-tcol li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 6px;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--s300);
}

/* A hollow bullet is something this teacher is deliberately NOT shown.
   That absence is the argument of the section, so it has to be visible
   rather than simply missing. */
.mk-tcol li.no {
    color: var(--s400);
}

.mk-tcol li.no::before {
    background: transparent;
    box-shadow: inset 0 0 0 1px var(--s300);
}


/* ════ §6 · FLAGS AND THE FOUR GROUPS ════ */

.mk-tflag {
    display: flex;
    gap: 10px;
    align-items: center;
    padding: 9px 10px;
    border: 1px solid var(--s200);
    border-radius: 11px;
}

.mk-tflag+.mk-tflag {
    margin-top: 6px;
}

.mk-tflag div {
    flex: 1;
    min-width: 0;
}

.mk-tflag b {
    display: block;
    font-family: var(--font-display);
    font-size: .715rem;
    color: var(--s900);
}

.mk-tflag span {
    display: block;
    margin-top: 2px;
    font-size: .65rem;
    line-height: 1.42;
    color: var(--s600);
}

.mk-tflag u {
    flex: 0 0 26px;
    height: 26px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    text-decoration: none;
    background: var(--g50);
    color: var(--g600);
    font-size: .64rem;
}

.mk-tgroups {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 5px;
    margin-top: 9px;
    padding-top: 9px;
    border-top: 1px solid var(--s100);
}

.mk-tgroups span {
    text-align: center;
    font-size: .565rem;
    line-height: 1.35;
    color: var(--s500);
}

.mk-tgroups b {
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.02rem;
    line-height: 1.2;
    color: var(--s900);
}

.mk-tgroups span.hot b {
    color: var(--red);
}


/* ════ §7 · WHICH OPTION THE CLASS PICKED ════ */

.mk-tospl {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .66rem;
    color: var(--s600);
}

.mk-tospl+.mk-tospl {
    margin-top: 6px;
}

.mk-tospl s {
    flex: 0 0 17px;
    height: 17px;
    border-radius: 99px;
    border: 1px solid var(--s300);
    display: grid;
    place-items: center;
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: .54rem;
    font-weight: 700;
    color: var(--s500);
}

.mk-tospl p {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mk-tospl i {
    display: block;
    flex: 0 0 66px;
    height: 7px;
    border-radius: 99px;
    background: var(--s100);
    overflow: hidden;
}

.mk-tospl i em {
    display: block;
    height: 100%;
    border-radius: 99px;
    background: var(--s400);
}

.mk-tospl u {
    flex: 0 0 28px;
    text-align: right;
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: .6rem;
    font-weight: 700;
    color: var(--s500);
}

.mk-tospl.trap s {
    border-color: var(--red);
    background: var(--red);
    color: #fff;
}

.mk-tospl.trap i em {
    background: var(--red);
}

.mk-tospl.trap u {
    color: var(--red);
}

.mk-tospl.ok s {
    border-color: var(--site-ok);
    background: var(--site-ok);
    color: #fff;
}

.mk-tospl.ok i em {
    background: var(--site-ok);
}

.mk-tospl.ok u {
    color: var(--site-ok-ink);
}


/* ════ §8 · TWO NUMBERS, NEVER ONE ════ */

.mk-tcm {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 11px;
    border: 1px solid var(--s200);
    border-radius: 11px;
}

.mk-tcm+.mk-tcm {
    margin-top: 6px;
}

.mk-tcm>b {
    flex: 1;
    min-width: 0;
    font-family: var(--font-display);
    font-size: .705rem;
    font-weight: 700;
    color: var(--s900);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mk-tcm em {
    flex: 0 0 68px;
    text-align: right;
    font-style: normal;
}

.mk-tcm em span {
    display: block;
    font-size: .535rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--s500);
}

.mk-tcm em i {
    font-style: normal;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: .86rem;
    color: var(--s900);
}

/* Below the sample floor. Reads as a fact, never as a zero. */
.mk-tcm em i.gate {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: .615rem;
    color: var(--s400);
}


/* ── SHORT LAPTOPS ────────────────────────────────────────────────
   The .nd-pa-split trims in §16 already handle the points column and
   the mockup padding. These are the teacher-only components. Same two
   height steps as the rest of the site — 940 and 800, never a third. */

@media (min-width: 900px) and (max-height: 940px) {
    .mk-tne p {
        font-size: .68rem;
    }

    .mk-tcol li {
        font-size: .615rem;
    }

    .mk-tquad .mk-metric b {
        font-size: .95rem;
    }

    .mk-tgroups b {
        font-size: .95rem;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    .mk-tne {
        padding: 8px 10px;
    }

    .mk-tne p {
        font-size: .655rem;
        line-height: 1.46;
    }

    .mk-tne-f {
        margin-top: 6px;
        padding-top: 6px;
    }

    .mk-tcol {
        padding: 9px;
    }

    .mk-tcol li {
        font-size: .6rem;
        line-height: 1.4;
    }

    .mk-tflag {
        padding: 8px 10px;
    }

    .mk-tflag span {
        font-size: .63rem;
    }

    .mk-tquad .mk-metric {
        padding: 7px 8px;
    }

    .mk-tquad .mk-metric b {
        font-size: .9rem;
    }

    .mk-tcm {
        padding: 8px 10px;
    }

    .mk-tospl i {
        flex-basis: 56px;
    }
}


/* ── SEVEN NAV ITEMS ──────────────────────────────────────────────
   Adding Teachers takes the desktop row from six labels to seven. The
   row first appears at 1024px, where the track is 928px and the row
   measures roughly 890 — it fits, but by about 36px, which is inside
   the error bar of a font-metric estimate rather than outside it.

   Two cheap insurances. `nowrap` means a bad estimate produces a
   horizontal squeeze rather than "Insti-\ntutes" wrapping to two lines
   and doubling the header's height. And the padding steps down for the
   narrow band only, which buys ~50px back where it is actually needed
   and changes nothing at 1180 and above.

   If a seventh item ever becomes an eighth, raise the burger
   breakpoint from 1023px instead of shaving this further. */
.nd-link {
    white-space: nowrap;
}

@media (min-width: 1024px) and (max-width: 1150px) {
    .nd-links {
        gap: 0;
    }

    .nd-links .nd-link {
        padding-left: 9px;
        padding-right: 9px;
    }
}


/* ════════════════════════════════════════════════════════════════
   18. INSTITUTES PAGE  (institutes.html)

   Twelve .nd-vp sections under a ten-anchor sub-nav. Same contract as
   §16 and §17: html.nd-snap + body.nd-sub2, clearance for BOTH sticky
   bars in .nd-sub2 .nd-vp's PADDING, never scroll-margin-top.

   THIS PAGE REUSES MORE THAN IT ADDS, ON PURPOSE
   §4 is built entirely from the landing page's audience components —
   .nd-seg, .nd-panel, .nd-card.raised, .nd-split.s50, .nd-aud-q,
   .nd-checks, .nd-aud-close — because a school arriving from
   index.html's "For schools" button should land on something it
   recognises. §8 and §10 are .nd-steps. §5 is .nd-grid.g4. New CSS
   here covers only what genuinely has no equivalent: the chain, the
   arithmetic figure, and the price block.

   NEW CLASSES ARE PREFIXED nd-il- / mk-i
   Checked against the full mk- and nd- namespace before writing. §16's
   .mk-say collision cost a rendering bug; the cure is to grep first,
   every time.
   ════════════════════════════════════════════════════════════════ */


/* ════ §2 · THE ARITHMETIC ════
   One number, stated large, with its own working shown underneath. The
   working matters more than the figure — a principal who does the
   multiplication himself is persuaded; one who is handed a total is
   being sold to. */

.nd-il-sum {
    display: grid;
    gap: 14px;
    text-align: center;
    padding: clamp(20px, 3vw, 30px) clamp(16px, 2.5vw, 26px);
    border: 1px solid var(--s200);
    border-radius: 18px;
    background: #fff;
    box-shadow: var(--site-shadow);
}

.nd-il-mult {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 7px 12px;
}

.nd-il-mult span {
    display: grid;
    gap: 2px;
    min-width: 62px;
}

.nd-il-mult span b {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.15rem, 2.2vw, 1.6rem);
    line-height: 1;
    color: var(--s900);
}

.nd-il-mult span em {
    font-style: normal;
    font-size: .6rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--s500);
}

.nd-il-mult i {
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .9rem;
    color: var(--s300);
    align-self: start;
    padding-top: 2px;
}

.nd-il-total {
    padding-top: 14px;
    border-top: 1px solid var(--s100);
}

.nd-il-total b {
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(2.1rem, 5.5vw, 3.4rem);
    line-height: 1;
    letter-spacing: -.03em;
    color: var(--g600);
}

.nd-il-total span {
    display: block;
    margin-top: 8px;
    font-size: .85rem;
    line-height: 1.5;
    color: var(--s600);
}


/* ════ §3 · THE CHAIN ════
   Five stages, each labelled with WHO acts. The actor chip is the whole
   point of the diagram: the argument is not that the software is clever
   but that four different people are joined up by it. */

.mk-chain {
    display: grid;
    gap: 0;
}

.mk-ilink {
    display: flex;
    gap: 11px;
    align-items: flex-start;
    padding: 10px 0;
}

.mk-ilink+.mk-ilink {
    border-top: 1px dashed var(--s200);
}

.mk-ilink-n {
    flex: 0 0 26px;
    height: 26px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    background: var(--g600);
    color: #fff;
    font-family: var(--font-mono);
    font-size: .62rem;
    font-weight: 700;
}

.mk-ilink:last-child .mk-ilink-n {
    background: var(--purple);
}

.mk-ilink div {
    flex: 1;
    min-width: 0;
}

.mk-ilink-who {
    display: inline-block;
    margin-bottom: 4px;
    padding: 2px 7px;
    border-radius: 5px;
    background: var(--s100);
    font-family: var(--font-mono);
    font-size: .55rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--s500);
}

.mk-ilink b {
    display: block;
    font-family: var(--font-display);
    font-size: .735rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--s900);
}

.mk-ilink span {
    display: block;
    margin-top: 3px;
    font-size: .655rem;
    line-height: 1.45;
    color: var(--s600);
}


/* ════ §5 · THE EIGHT MODULES ════ */

.nd-il-mod {
    display: flex;
    gap: 11px;
    align-items: flex-start;
    padding: 14px 15px;
}

.nd-il-mod div {
    min-width: 0;
}

.nd-il-mod h3 {
    font-family: var(--font-display);
    font-size: .84rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--s900);
    margin-bottom: 4px;
}

.nd-il-mod p {
    font-size: .765rem;
    line-height: 1.5;
    color: var(--s600);
}


/* ════ §9 · THE PRICE ════
   The headline figure, then the two numbers that actually close the
   sale: what it costs a month, and what the institutional layer costs
   over a family buying the student licence alone. Both are divisions a
   buyer would do anyway, so doing them here is a courtesy rather than
   a trick — and the working is printed beside each. */

.nd-il-price {
    padding: clamp(20px, 3vw, 30px) clamp(18px, 3vw, 32px);
    border: 1px solid var(--g200);
    border-radius: 18px;
    background: #fff;
    box-shadow: var(--site-shadow);
    text-align: center;
}

.nd-il-fig {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(2.4rem, 6.5vw, 3.8rem);
    line-height: 1;
    letter-spacing: -.03em;
    color: var(--s900);
}

.nd-il-fig em {
    font-style: normal;
    font-size: .34em;
    font-weight: 700;
    letter-spacing: 0;
    color: var(--s500);
}

.nd-il-per {
    margin-top: 9px;
    font-size: .88rem;
    color: var(--s600);
}

.nd-il-per b {
    color: var(--s900);
}

.nd-il-two {
    display: grid;
    gap: 9px;
    margin-top: 17px;
    padding-top: 16px;
    border-top: 1px solid var(--s100);
}

@media (min-width: 560px) {
    .nd-il-two {
        grid-template-columns: 1fr 1fr;
    }
}

.nd-il-two div {
    padding: 11px 12px;
    border-radius: 12px;
    background: var(--g50);
    border: 1px solid var(--g100);
}

.nd-il-two b {
    display: block;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.28rem;
    line-height: 1;
    color: var(--g700);
}

.nd-il-two span {
    display: block;
    margin-top: 5px;
    font-size: .705rem;
    line-height: 1.45;
    color: var(--s600);
}


/* ════ §11 · THE ASK ════ */

.nd-il-ask {
    display: grid;
    gap: 11px;
}

@media (min-width: 760px) {
    .nd-il-ask {
        grid-template-columns: repeat(3, 1fr);
    }
}

.nd-il-ask>div {
    padding: 15px 16px;
    border: 1px solid var(--s200);
    border-radius: 14px;
    background: #fff;
}

.nd-il-ask h3 {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-display);
    font-size: .8rem;
    font-weight: 700;
    color: var(--s900);
    margin-bottom: 8px;
}

.nd-il-ask h3 i {
    font-size: .72rem;
    color: var(--g500);
}

.nd-il-ask ul {
    list-style: none;
    display: grid;
    gap: 5px;
}

.nd-il-ask li {
    position: relative;
    padding-left: 13px;
    font-size: .755rem;
    line-height: 1.48;
    color: var(--s600);
}

.nd-il-ask li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 8px;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--g300);
}


/* ── SHORT LAPTOPS ────────────────────────────────────────────────
   §3 (five chain links) and §5 (eight module cards) are the tight
   ones. Same two height steps as the rest of the site — 940 and 800,
   never a third. */

@media (min-width: 900px) and (max-height: 940px) {
    .mk-ilink {
        padding: 8px 0;
    }

    .nd-il-mod {
        padding: 12px 13px;
    }

    .nd-il-mod p {
        font-size: .735rem;
    }

    .nd-il-ask>div {
        padding: 13px 14px;
    }

    .nd-il-ask li {
        font-size: .73rem;
    }
}

@media (min-width: 900px) and (max-height: 800px) {

    /* Five chain links plus a header is the tallest mockup on the page,
       and at 800px it runs about 8px past the fold. The saving is taken
       from the chip and the title rather than the description, because
       the description is the sentence that carries the argument. */
    .mk-ilink {
        padding: 7px 0;
    }

    .mk-ilink-who {
        margin-bottom: 3px;
        padding: 1px 6px;
    }

    .mk-ilink b {
        font-size: .705rem;
    }

    .mk-ilink span {
        font-size: .63rem;
        line-height: 1.42;
    }

    .nd-il-mod {
        padding: 10px 12px;
        gap: 9px;
    }

    .nd-il-mod h3 {
        font-size: .8rem;
        margin-bottom: 3px;
    }

    .nd-il-mod p {
        font-size: .705rem;
        line-height: 1.46;
    }

    .nd-il-sum {
        padding: 18px 20px;
        gap: 11px;
    }

    .nd-il-total {
        padding-top: 11px;
    }

    .nd-il-price {
        padding: 18px 22px;
    }

    .nd-il-two {
        margin-top: 13px;
        padding-top: 12px;
    }

    .nd-il-ask>div {
        padding: 11px 13px;
    }

    .nd-il-ask li {
        font-size: .71rem;
        line-height: 1.44;
    }
}


/* ════════════════════════════════════════════════════════════════
   19. PRICING PAGE  (pricing.html)

   Eight .nd-vp sections under a six-anchor sub-nav. Same contract as
   §16-§18: html.nd-snap + body.nd-sub2, clearance for BOTH sticky bars
   in .nd-sub2 .nd-vp's PADDING, never scroll-margin-top.

   WHY NOT .nd-price-mini
   The landing page's three-card preview exists and is fine there, but
   it is a 3-column grid with centred text and no feature list. This
   page needs four tiers, a highlighted recommendation, a per-month
   division under each figure and a short list inside each card. Bending
   .nd-price-mini into that shape would change how index.html renders.
   New grid, old tokens.

   NEW CLASSES ARE PREFIXED nd-pr-
   Note that .nd-price-mini, .nd-price-tag and .nd-price-term already
   exist in §10. nd-pr- was checked against the whole sheet before
   writing — §16's .mk-say collision is the reason that check is now a
   step rather than an instinct.
   ════════════════════════════════════════════════════════════════ */


/* ════ §2 · THE PLANS ════ */

.nd-pr-grid {
    display: grid;
    gap: 12px;
}

@media (min-width: 620px) {
    .nd-pr-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 1024px) {
    .nd-pr-grid {
        grid-template-columns: repeat(4, 1fr);
    }
}

.nd-pr-card {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 20px 18px;
    border: 1px solid var(--s200);
    border-radius: 16px;
    background: #fff;
}

/* The recommendation. Raised rather than recoloured — a card in a
   different hue reads as a different product, which is the opposite of
   a conversion ladder where each step is the same thing, larger. */
.nd-pr-card.pick {
    border-color: var(--g500);
    box-shadow: var(--site-shadow);
}

.nd-pr-badge {
    position: absolute;
    top: -10px;
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--g600);
    color: #fff;
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.nd-pr-name {
    font-family: var(--font-display);
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--s500);
}

.nd-pr-fig {
    display: block;
    margin: 9px 0 2px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.95rem;
    line-height: 1;
    letter-spacing: -.03em;
    color: var(--s900);
}

.nd-pr-fig em {
    font-style: normal;
    font-size: .42em;
    font-weight: 700;
    letter-spacing: 0;
    color: var(--s500);
}

.nd-pr-term {
    font-family: var(--font-mono);
    font-size: .655rem;
    color: var(--s500);
}

/* "Founder's Offer" is a LABEL, and there is deliberately no
   struck-through "was" price anywhere on this page to go with it.

   These prices have never been higher than they are, so a reference
   price would have to be invented — and an invented one is a
   misleading advertisement under s.2(28) of the Consumer Protection
   Act, on top of the CCPA's 2023 dark-pattern guidelines, under which
   nine education and retail platforms have already been fined. The
   label says the price is introductory, which is true and needs no
   anchor to be worth reading.

   Amber rather than the brand blue: it has to read as a note ON the
   card, not as another badge competing with "Most students". */
.nd-pr-offer {
    display: inline-block;
    align-self: flex-start;
    margin-top: 9px;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--amber-bg);
    color: var(--amber);
    font-family: var(--font-mono);
    font-size: .575rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
}

/* The bundle comparison, on Complete only. BOTH figures are prices a
   student can actually pay today — three Single Subjects against one
   Complete — which is the only reason a saving may be claimed here at
   all. checkout.js recomputes it from the live prices; see paintSaving. */
/* The pill is a modifier OF the price, so it sits tight to it. Flex
   items do not collapse margins, so without this the pill floats
   equidistant between the name and the figure and reads as neither.

   ⚠️ Deliberately 0,2,0: it therefore BEATS the `.nd-pr-fig { margin:
   7px 0 2px }` in the short-laptop block below, whatever the order.
   That is wanted — 4px is already tight enough for every height — but
   it is why editing that block will not move this gap. */
.nd-pr-offer + .nd-pr-fig {
    margin-top: 4px;
}

.nd-pr-save {
    margin-top: 5px;
    font-family: var(--font-mono);
    font-size: .625rem;
    line-height: 1.45;
    color: var(--amber);
}

/* ⚠️ checkout.js hides this with el.hidden when the bundle stops
   saving anything, and an author `display` beats the hidden attribute
   — the bug tools/check_hidden.py exists for. */
.nd-pr-save[hidden] {
    display: none;
}

.nd-pr-foot {
    margin-top: 20px;
    text-align: center;
    font-size: .8rem;
    line-height: 1.6;
    color: var(--s500);
}

.nd-pr-note {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--s100);
    font-size: .765rem;
    line-height: 1.5;
    color: var(--s600);
}

.nd-pr-list {
    list-style: none;
    display: grid;
    gap: 6px;
    margin-top: 11px;
}

.nd-pr-list li {
    position: relative;
    padding-left: 18px;
    font-size: .745rem;
    line-height: 1.45;
    color: var(--s600);
}

.nd-pr-list li::before {
    content: '\f00c';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    position: absolute;
    left: 0;
    top: 1px;
    font-size: .6rem;
    color: var(--g500);
}

/* A capability this tier does NOT have. Struck rather than absent,
   because the ladder only reads as a ladder if each rung shows what the
   next one adds. */
.nd-pr-list li.off {
    color: var(--s400);
}

.nd-pr-list li.off::before {
    content: '\f068';
    color: var(--s300);
}

/* margin-top:auto belongs on the WRAPPER, not the button. The card is
   the flex column, so an auto margin on a button nested one level down
   pushes nothing — and the four buttons would sit at four different
   heights wherever the feature lists differ in length. */
.nd-pr-cta {
    margin-top: auto;
    padding-top: 15px;
}

.nd-pr-card .nd-btn {
    width: 100%;
}


/* ════ §3 · THE MATRIX ════
   Horizontally scrollable on a phone rather than reflowed into four
   stacked lists. A comparison the reader cannot see side by side is not
   a comparison, and four stacked lists is what the cards above already
   are. */

.nd-pr-scroll {
    overflow-x: auto;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--s200);
    border-radius: 14px;
    background: #fff;
}

.nd-pr-tbl {
    width: 100%;
    min-width: 620px;
    border-collapse: collapse;
    font-size: .755rem;
}

.nd-pr-tbl th,
.nd-pr-tbl td {
    padding: 9px 12px;
    text-align: center;
    border-bottom: 1px solid var(--s100);
}

.nd-pr-tbl tr:last-child th,
.nd-pr-tbl tr:last-child td {
    border-bottom: 0;
}

.nd-pr-tbl thead th {
    position: sticky;
    top: 0;
    background: var(--s50);
    font-family: var(--font-display);
    font-size: .68rem;
    font-weight: 700;
    color: var(--s800);
    border-bottom: 1px solid var(--s200);
}

.nd-pr-tbl thead th span {
    display: block;
    margin-top: 2px;
    font-family: var(--font-mono);
    font-size: .58rem;
    font-weight: 500;
    color: var(--s500);
}

/* The row label column stays put while the tiers scroll past it. */
.nd-pr-tbl tbody th,
.nd-pr-tbl thead th:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    min-width: 176px;
    text-align: left;
    background: #fff;
    font-weight: 600;
    color: var(--s700);
}

.nd-pr-tbl thead th:first-child {
    z-index: 2;
    background: var(--s50);
}

.nd-pr-tbl td i {
    font-size: .78rem;
    color: var(--g500);
}

.nd-pr-tbl td i.no {
    color: var(--s300);
}

.nd-pr-tbl td em {
    font-style: normal;
    font-size: .68rem;
    color: var(--s500);
}

.nd-pr-tbl col.hi,
.nd-pr-tbl td.hi,
.nd-pr-tbl thead th.hi {
    background: var(--g50);
}


/* ── SHORT LAPTOPS ────────────────────────────────────────────────
   §2 (four cards with lists) and §3 (an eleven-row matrix) are the
   tight ones. Same two height steps as the rest of the site. */

@media (min-width: 900px) and (max-height: 940px) {
    .nd-pr-card {
        padding: 17px 16px;
    }

    .nd-pr-fig {
        font-size: 1.78rem;
    }

    .nd-pr-offer {
        margin-top: 7px;
    }

    .nd-pr-list li {
        font-size: .72rem;
    }

    .nd-pr-tbl th,
    .nd-pr-tbl td {
        padding: 7px 12px;
    }
}

@media (min-width: 900px) and (max-height: 800px) {
    .nd-pr-card {
        padding: 15px 15px;
    }

    .nd-pr-fig {
        font-size: 1.62rem;
        margin: 7px 0 2px;
    }

    .nd-pr-offer {
        margin-top: 6px;
        padding: 2px 8px;
        font-size: .55rem;
    }

    .nd-pr-save {
        font-size: .6rem;
    }

    .nd-pr-foot {
        margin-top: 15px;
        font-size: .755rem;
    }

    .nd-pr-note {
        margin-top: 8px;
        padding-top: 8px;
        font-size: .73rem;
        line-height: 1.46;
    }

    .nd-pr-list {
        gap: 5px;
        margin-top: 9px;
    }

    .nd-pr-list li {
        font-size: .705rem;
        line-height: 1.42;
    }

    .nd-pr-cta {
        margin-top: 12px;
    }

    .nd-pr-tbl {
        font-size: .72rem;
    }

    .nd-pr-tbl th,
    .nd-pr-tbl td {
        padding: 6px 11px;
    }
}
/* ════════════════════════════════════════════════════════════════
   CHECKOUT  (pricing.html only — see site/checkout.js)

   The sheet the Razorpay flow puts its own states in: starting,
   waiting for the webhook, unlocked, failed, cancelled. Razorpay
   draws its own modal on top of this; these are OUR screens either
   side of it.

   Bottom sheet on phones, centred card from 640px — the same shape
   the app's paywall uses, so the two feel like one product even
   though they are different codebases.
   ════════════════════════════════════════════════════════════════ */

.ck-overlay {
    position: fixed;
    inset: 0;
    z-index: 9500;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    background: rgba(11, 18, 32, .6);
    backdrop-filter: blur(3px);
    animation: ckFade .18s ease;
}

.ck-card {
    background: #fff;
    width: 100%;
    max-width: 430px;
    border-radius: 20px 20px 0 0;
    padding: 26px 22px calc(26px + env(safe-area-inset-bottom));
    text-align: center;
    animation: ckUp .24s cubic-bezier(.2, .8, .3, 1);
    /* A short phone in landscape, or the timeout message with a long
       order id in it, can outgrow the viewport. Scroll the card rather
       than pushing its button off the bottom of the screen where the
       student cannot reach it. */
    max-height: 88vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

@media (min-width: 640px) {
    .ck-overlay {
        align-items: center;
    }

    .ck-card {
        border-radius: 18px;
        padding: 30px 28px;
    }
}

@keyframes ckFade {
    from { opacity: 0 }
    to { opacity: 1 }
}

@keyframes ckUp {
    from { transform: translateY(22px) }
    to { transform: translateY(0) }
}

@media (prefers-reduced-motion: reduce) {

    .ck-overlay,
    .ck-card {
        animation: none;
    }
}

.ck-h {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 800;
    color: var(--s900, #0f172a);
    margin: 12px 0 8px;
}

.ck-msg {
    font-size: .9rem;
    line-height: 1.6;
    color: var(--s600, #475569);
    margin: 0 0 18px;
}

.ck-msg code {
    font-family: var(--font-mono);
    font-size: .82em;
    background: var(--s100, #f1f5f9);
    padding: .1em .4em;
    border-radius: 4px;
}

.ck-spin {
    width: 34px;
    height: 34px;
    margin: 4px auto 0;
    border: 3px solid var(--g100, #dce8f6);
    border-top-color: var(--g500, #2f6cb3);
    border-radius: 50%;
    animation: ckSpin .8s linear infinite;
}

@keyframes ckSpin {
    to { transform: rotate(360deg) }
}

@media (prefers-reduced-motion: reduce) {
    .ck-spin { animation-duration: 2.4s }
}

.ck-tick {
    width: 52px;
    height: 52px;
    margin: 0 auto;
    border-radius: 50%;
    background: #e7f6ee;
    color: #1f9e4a;
    font-size: 1.6rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ck-subjects {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin-bottom: 14px;
}

.ck-cancel {
    background: none;
    border: 0;
    color: var(--s500, #64748b);
    font-family: inherit;
    font-size: .86rem;
    cursor: pointer;
    padding: 6px;
}

.ck-overlay .nd-btn {
    width: 100%;
    justify-content: center;
}

/* Test mode is invisible otherwise, and paying ₹1,999 of imaginary
   money while believing it real is a bad five minutes. */
#ck-testbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9400;
    background: #c07c12;
    color: #fff;
    font-family: var(--font-mono);
    font-size: .68rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    text-align: center;
    padding: 6px 10px;
}


/* ════ 21. LEGAL & COMPANY PAGES ═══════════════════════════════════
   terms.html · privacy.html · refund.html · contact.html · about.html

   NUMBERING: §20 is THE TABLET TIER above. This file already
   double-uses 16–19 (two §17s, two §19s), so this block takes the
   next free number rather than renumbering blocks that other comments
   in here point at by name.

   ─────────────────────────────────────────────────────────────────
   WHY THESE FIVE PAGES BREAK THE SITE'S HABITS

   Every other page here is a pitch you scan. These are the only
   LONG-FORM READING on the site: a refund clause is something a
   parent reads start to finish, on a phone, possibly twice, before
   deciding whether to spend ₹4,999. So they drop two site-wide
   conventions on purpose:

     · NO .nd-vp, NO html.nd-snap. A legal document that pages itself
       one viewport at a time is unreadable — and unquotable, which
       matters when a payment-gateway reviewer wants to point at
       clause 7.2. These pages scroll like a document.

     · A ~70ch measure instead of the 60ch .nd-lead. Long prose needs
       the wider column; a marketing sentence does not. 70ch at
       .95rem lands around 640px, which is the whole content column
       below 900px anyway — so the measure only bites on desktop,
       where it is the thing that stops a clause running 1100px wide.

   Everything else is the existing vocabulary unchanged: the navy
   .nd-page-head, .nd-ico, .nd-callout, .nd-cmp tables, .nd-btn. Same
   brand, calmer. Nothing here invents a colour or a font.
   ════════════════════════════════════════════════════════════════ */

/* ── the reading column ── */
.nd-legal {
    max-width: 70ch;
}

.nd-legal p,
.nd-legal li {
    font-size: .95rem;
    line-height: 1.75;
    color: var(--s600);
}

.nd-legal p + p {
    margin-top: 13px;
}

.nd-legal strong,
.nd-legal b {
    color: var(--s800);
    font-weight: 700;
}

/* Underlined on purpose. The base `a` rule strips underlines, which is
   right for nav pills and card links surrounded by chrome — and wrong
   inside a paragraph of grey prose, where colour alone is the only cue
   and fails for a red-green colourblind reader. */
.nd-legal a {
    color: var(--g600);
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-thickness: 1px;
}

.nd-legal a:hover {
    color: var(--g700);
}

.nd-legal ul,
.nd-legal ol {
    display: grid;
    gap: 9px;
    margin: 13px 0 0;
    padding-left: 21px;
}

.nd-legal li::marker {
    color: var(--s400);
}

/* ── numbered sections ──
   The numbers are WRITTEN INTO THE MARKUP, not generated by a CSS
   counter. A counter renumbers silently when a section is inserted,
   and these documents cross-reference each other by clause ("clause 9
   of the Terms"). A number that can drift is a number that can make a
   cross-reference wrong without anybody having edited it. */
.nd-legal-sec {
    margin-top: clamp(34px, 4.4vw, 48px);
    scroll-margin-top: calc(var(--site-nav) + 22px);
}

.nd-legal-sec > h2 {
    font-family: var(--font-display);
    font-size: clamp(1.12rem, 2vw, 1.4rem);
    font-weight: 800;
    letter-spacing: -.018em;
    line-height: 1.28;
    color: var(--s900);
    display: flex;
    gap: 12px;
    align-items: baseline;
    margin-bottom: 14px;
}

.nd-legal-n {
    font-family: var(--font-mono);
    font-size: .78em;
    font-weight: 700;
    color: var(--g500);
    flex: 0 0 auto;
}

.nd-legal-sec h3 {
    font-family: var(--font-display);
    font-size: .98rem;
    font-weight: 700;
    line-height: 1.4;
    color: var(--s800);
    margin: 24px 0 9px;
}

/* ── "last updated", in the navy head ── */
.nd-legal-meta {
    margin-top: 22px;
    font-family: var(--font-mono);
    font-size: .74rem;
    letter-spacing: .01em;
    color: var(--site-sky);
}

/* ── contents ──
   On the three long documents; absent from about/contact. It is a real
   nav landmark, not decoration: on a phone the alternative to a jump
   list is thumb-scrolling past nine clauses to reach the refund
   window. */
.nd-toc {
    margin-top: 30px;
    background: var(--s50);
    border: 1px solid var(--s200);
    border-radius: 16px;
    padding: 20px 22px;
}

.nd-toc h2 {
    font-family: var(--font-display);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--s500);
    margin-bottom: 12px;
}

.nd-toc ol {
    display: grid;
    gap: 7px;
    padding-left: 20px;
}

.nd-toc li {
    font-size: .87rem;
    line-height: 1.5;
}

.nd-toc li::marker {
    font-family: var(--font-mono);
    font-size: .78rem;
    color: var(--s400);
}

.nd-toc a {
    color: var(--s700);
    text-decoration: none;
}

.nd-toc a:hover {
    color: var(--g600);
    text-decoration: underline;
    text-underline-offset: 2px;
}

@media (min-width: 640px) {
    .nd-toc ol {
        grid-template-columns: repeat(2, 1fr);
        gap: 7px 24px;
    }
}

/* ── definition rows ──
   Entity details, processor lists, contact facts. A <dl> rather than a
   table because these are label/value pairs with no second axis, and a
   one-column table on a phone is a table that has stopped being one. */
.nd-legal-dl {
    display: grid;
    gap: 0;
    margin-top: 15px;
    border: 1px solid var(--s200);
    border-radius: 16px;
    overflow: hidden;
    background: #fff;
}

.nd-legal-dl > div {
    display: grid;
    gap: 2px 18px;
    padding: 13px 18px;
    border-bottom: 1px solid var(--s100);
}

.nd-legal-dl > div:last-child {
    border-bottom: 0;
}

.nd-legal-dl dt {
    font-family: var(--font-display);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--s500);
}

.nd-legal-dl dd {
    font-size: .91rem;
    line-height: 1.62;
    color: var(--s700);
}

.nd-legal-dl dd a {
    color: var(--g600);
    text-decoration: underline;
    text-underline-offset: 2px;
}

@media (min-width: 640px) {
    .nd-legal-dl > div {
        grid-template-columns: 190px 1fr;
        align-items: baseline;
    }
}

/* ── the one-line answer, above the contents ──
   On refund.html and privacy.html. The reviewer, and every parent,
   wants the rule before the reasoning. */
.nd-legal-tldr {
    margin-top: 26px;
    border-radius: 4px 18px 18px 4px;
    border-left: 3px solid var(--g500);
    background: var(--g50);
    padding: 20px 22px;
}

.nd-legal-tldr b {
    display: block;
    font-family: var(--font-display);
    font-size: .97rem;
    font-weight: 800;
    letter-spacing: -.012em;
    color: var(--s900);
    margin-bottom: 7px;
}

.nd-legal-tldr p {
    font-size: .91rem;
    line-height: 1.68;
    color: var(--s700);
}

/* ════ 22. CONTACT PAGE ════════════════════════════════════════════
   The site's FIRST form. Nothing in this stylesheet had styled an
   <input> before now, because until this page every call to action on
   these pages was a link into the app. Kept deliberately small: four
   controls, a textarea, a checkbox, one button.
   ════════════════════════════════════════════════════════════════ */
.nd-contact {
    display: grid;
    gap: clamp(28px, 3.6vw, 44px);
    align-items: start;
}

@media (min-width: 900px) {
    .nd-contact {
        grid-template-columns: .82fr 1.18fr;
    }
}

.nd-contact-cards {
    display: grid;
    gap: 14px;
}

.nd-contact-card {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 18px;
    padding: 18px 19px;
    box-shadow: var(--site-shadow);
}

.nd-contact-card h3 {
    font-family: var(--font-display);
    font-size: .95rem;
    font-weight: 700;
    color: var(--s900);
    margin-bottom: 6px;
}

.nd-contact-card p {
    font-size: .875rem;
    line-height: 1.62;
    color: var(--s600);
}

.nd-contact-card a {
    color: var(--g600);
    text-decoration: none;
    font-weight: 600;
}

.nd-contact-card a:hover {
    text-decoration: underline;
    text-underline-offset: 2px;
}

.nd-contact-card .nd-cap {
    margin-top: 5px;
}

/* ── the form ── */
.nd-form {
    background: #fff;
    border: 1px solid var(--s200);
    border-radius: 20px;
    padding: clamp(20px, 2.6vw, 28px);
    box-shadow: var(--site-shadow);
    display: grid;
    gap: 15px;
}

.nd-field {
    display: grid;
    gap: 6px;
}

.nd-field label {
    font-family: var(--font-display);
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--s700);
}

.nd-field .req {
    color: var(--red);
}

.nd-field input,
.nd-field select,
.nd-field textarea {
    font-family: var(--font-body);
    font-size: .92rem;
    line-height: 1.5;
    color: var(--s800);
    background: var(--s50);
    border: 1px solid var(--s200);
    border-radius: 12px;
    padding: 11px 13px;
    width: 100%;
    transition: border-color .16s var(--site-ease), background .16s var(--site-ease);
}

/* 16px on phones, or iOS Safari zooms the whole page in on focus and
   never zooms back out. The .92rem above is ~14.7px, so the floor has
   to be stated explicitly for the small tier. */
@media (max-width: 639px) {

    .nd-field input,
    .nd-field select,
    .nd-field textarea {
        font-size: 16px;
    }
}

.nd-field textarea {
    min-height: 132px;
    resize: vertical;
}

.nd-field input::placeholder,
.nd-field textarea::placeholder {
    color: var(--s400);
}

.nd-field input:focus,
.nd-field select:focus,
.nd-field textarea:focus {
    outline: none;
    background: #fff;
    border-color: var(--g400);
    box-shadow: 0 0 0 3px var(--g50);
}

.nd-field select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%2364748b' stroke-width='1.6' d='M1 1.6 6 6.4l5-4.8'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    background-size: 11px;
    padding-right: 36px;
}

@media (min-width: 560px) {
    .nd-form-row {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 15px;
    }
}

/* ── consent ── */
.nd-check {
    display: flex;
    gap: 11px;
    align-items: flex-start;
    cursor: pointer;
}

.nd-check input {
    flex: 0 0 auto;
    width: 17px;
    height: 17px;
    margin-top: 2px;
    accent-color: var(--g500);
    cursor: pointer;
}

.nd-check span {
    font-size: .83rem;
    line-height: 1.6;
    color: var(--s600);
}

.nd-check a {
    color: var(--g600);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ── submit + status ──
   .nd-form-msg is aria-live. It collapses while empty rather than
   reserving its space: a blank status box under a button reads as an
   error that has not finished loading. */
.nd-form-msg {
    font-size: .84rem;
    line-height: 1.6;
    color: var(--s600);
}

.nd-form-msg:empty {
    display: none;
}

.nd-form-msg.ok {
    color: var(--g600);
    font-weight: 600;
}

.nd-form-note {
    font-size: .77rem;
    line-height: 1.55;
    color: var(--s500);
    display: flex;
    gap: 8px;
    align-items: flex-start;
}

.nd-form-note i {
    color: var(--s400);
    margin-top: 3px;
}

/* ════ 23. FOOTER — FIFTH COLUMN ═══════════════════════════════════
   The Legal column (Terms · Privacy · Refunds) added a fifth track to
   a grid that was written for four. Overriding here rather than
   editing §8 keeps the original rule readable as "brand + three".

   Below 900px nothing changes: the 2-column tier at 640px simply
   wraps to three rows, and the single column below that was always a
   stack. Only the desktop track list needs to know.
   ════════════════════════════════════════════════════════════════ */
@media (min-width: 900px) {
    .nd-foot-grid {
        grid-template-columns: 1.45fr repeat(4, 1fr);
        gap: 34px;
    }
}


/* ════ 24. LEGAL & INFORMATION PAGES ═══════════════════════════════
   terms · privacy · refund · contact · about

   These are the only pages on the site that are READ rather than
   scanned, and that difference drives every choice below. They do not
   carry `html.nd-snap` and they do not use `.nd-vp`: somebody checking
   what our refund window is must not have a section snap under them
   mid-sentence. They scroll like a document because they are one.

   The nav is position:fixed with no body offset, so unlike every other
   page here — where `.nd-vp` supplies the clearance — these pages pad
   their own top. That is `.nd-legal-head` padding-top, and it is
   load-bearing rather than spacing taste.

   SECTION NUMBERS COME FROM A CSS COUNTER, not from the markup. A
   legal document genuinely is an ordered sequence and gets cited by
   number ("under clause 7"), so numbering carries meaning rather than
   decorating. Deriving it means inserting a clause cannot leave the
   document numbered 1, 2, 3, 3, 4.
   ════════════════════════════════════════════════════════════════ */

.nd-legal-head {
    padding: calc(var(--site-nav) + 54px) 0 34px;
    background: var(--s50);
    border-bottom: 1px solid var(--s200);
}

.nd-legal-kicker {
    font-family: var(--font-mono);
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--g600);
    margin-bottom: 12px;
}

.nd-legal-head h1 {
    font-family: var(--font-display);
    font-size: clamp(1.9rem, 4.4vw, 2.9rem);
    font-weight: 800;
    line-height: 1.12;
    letter-spacing: -.02em;
    color: var(--s900);
    text-wrap: balance;
    margin: 0 0 14px;
}

.nd-legal-sub {
    font-size: clamp(1rem, 1.5vw, 1.12rem);
    line-height: 1.6;
    color: var(--s600);
    max-width: 62ch;
    margin: 0;
}

.nd-legal-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    margin-top: 20px;
    font-size: .85rem;
    color: var(--s500);
}

.nd-legal-meta b {
    color: var(--s700);
    font-weight: 600;
}

/* ── document shell: sticky contents rail + prose ── */
.nd-legal-body {
    padding: clamp(34px, 5vw, 60px) 0 clamp(54px, 7vw, 88px);
}

.nd-legal-grid {
    display: grid;
    gap: 40px;
}

/* min-width:0 IS THE WHOLE MOBILE FIX, and it is not decorative.
   A grid item's default min-width is `auto`, which resolves to its
   MIN-CONTENT width — and .nd-doc contains tables carrying
   min-width:460px. On a single-column grid (every screen under
   1000px) that 460px became the column's floor, the column grew past
   the viewport, and all three legal pages scrolled sideways on a
   phone. The desktop track list says minmax(0, 1fr), which is why
   this only ever broke below the breakpoint. */
.nd-legal-grid>* {
    min-width: 0;
}

@media (min-width: 1000px) {
    .nd-legal-grid {
        grid-template-columns: 232px minmax(0, 1fr);
        gap: 56px;
        align-items: start;
    }
}

.nd-toc {
    border: 1px solid var(--s200);
    border-radius: 14px;
    padding: 18px 20px;
    background: #fff;
}

@media (min-width: 1000px) {
    .nd-toc {
        position: sticky;
        top: calc(var(--site-nav) + 22px);
        max-height: calc(100vh - var(--site-nav) - 46px);
        overflow-y: auto;
    }
}

.nd-toc h2 {
    font-family: var(--font-mono);
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--s500);
    margin: 0 0 12px;
}

.nd-toc ol {
    list-style: none;
    counter-reset: toc;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.nd-toc li {
    counter-increment: toc;
}

.nd-toc a {
    display: flex;
    gap: 10px;
    padding: 6px 8px;
    margin: 0 -8px;
    border-radius: 8px;
    font-size: .875rem;
    line-height: 1.4;
    color: var(--s600);
    text-decoration: none;
    transition: background .15s, color .15s;
}

.nd-toc a::before {
    content: counter(toc);
    font-family: var(--font-mono);
    font-size: .74rem;
    font-weight: 700;
    color: var(--s400);
    flex: none;
    min-width: 1.1em;
    padding-top: 2px;
}

.nd-toc a:hover {
    background: var(--g50);
    color: var(--g700);
}

.nd-toc a:hover::before {
    color: var(--g500);
}

/* ── the prose itself ── */
.nd-doc {
    counter-reset: clause;
    max-width: 72ch;
    font-size: 1rem;
    line-height: 1.72;
    color: var(--s700);
    /* email addresses and payment references are long unbreakable
       tokens; on a 360px phone one of them pushes the page sideways
       and the whole body scrolls. */
    overflow-wrap: break-word;
}

.nd-doc>section {
    counter-increment: clause;
    padding-top: 8px;
    margin-bottom: 38px;
    scroll-margin-top: calc(var(--site-nav) + 20px);
}

.nd-doc>section>h2 {
    display: flex;
    gap: 12px;
    font-family: var(--font-display);
    font-size: clamp(1.15rem, 2vw, 1.35rem);
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: -.01em;
    color: var(--s900);
    text-wrap: balance;
    margin: 0 0 14px;
}

.nd-doc>section>h2::before {
    content: counter(clause);
    font-family: var(--font-mono);
    font-size: .82rem;
    font-weight: 700;
    color: var(--g500);
    flex: none;
    padding-top: 6px;
    min-width: 1.4em;
}

/* an unnumbered heading inside a document (contact / about pages,
   which are not clause-structured) */
.nd-doc>section.plain>h2::before {
    content: none;
}

.nd-doc h3 {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    color: var(--s800);
    margin: 22px 0 8px;
}

.nd-doc p {
    margin: 0 0 14px;
}

.nd-doc ul,
.nd-doc ol {
    margin: 0 0 14px;
    padding-left: 22px;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.nd-doc li::marker {
    color: var(--s400);
}

.nd-doc a {
    color: var(--g600);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.nd-doc a:hover {
    color: var(--g700);
}

.nd-doc strong {
    color: var(--s900);
    font-weight: 600;
}

/* plain-English gloss. Deliberately NOT a substitute for the clause
   beside it — it sits above the operative text, never replaces it. */
.nd-plain {
    display: flex;
    gap: 11px;
    background: var(--g50);
    border: 1px solid var(--g100);
    border-radius: 12px;
    padding: 13px 16px;
    margin: 0 0 16px;
    font-size: .92rem;
    line-height: 1.6;
    color: var(--g700);
}

.nd-plain i {
    color: var(--g500);
    margin-top: 4px;
    flex: none;
}

.nd-plain b {
    font-weight: 700;
}

/* a clause people lose money by skimming */
.nd-flag {
    display: flex;
    gap: 11px;
    background: var(--amber-bg);
    border: 1px solid rgba(192, 124, 18, .22);
    border-radius: 12px;
    padding: 13px 16px;
    margin: 0 0 16px;
    font-size: .92rem;
    line-height: 1.6;
    color: #7c4f06;
}

.nd-flag i {
    color: var(--amber);
    margin-top: 4px;
    flex: none;
}

/* key/value block for seller identity and the grievance officer */
.nd-deets {
    border: 1px solid var(--s200);
    border-radius: 14px;
    padding: 4px 18px;
    margin: 0 0 16px;
    background: var(--s50);
}

.nd-deets dl {
    margin: 0;
    display: grid;
    gap: 0;
}

@media (min-width: 620px) {
    .nd-deets dl {
        grid-template-columns: 172px minmax(0, 1fr);
    }
}

.nd-deets dt {
    font-family: var(--font-mono);
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--s500);
    padding: 14px 0 4px;
}

.nd-deets dd {
    margin: 0;
    padding: 0 0 14px;
    font-size: .95rem;
    line-height: 1.6;
    color: var(--s800);
    overflow-wrap: break-word;
}

@media (min-width: 620px) {

    .nd-deets dt,
    .nd-deets dd {
        padding: 14px 0;
        border-top: 1px solid var(--s200);
    }

    .nd-deets dl>dt:first-of-type,
    .nd-deets dl>dt:first-of-type+dd {
        border-top: 0;
    }
}

.nd-deets dd a {
    color: var(--g600);
}

/* summary tables inside a document */
.nd-doc .nd-tblwrap {
    overflow-x: auto;
    border: 1px solid var(--s200);
    border-radius: 12px;
    margin: 0 0 16px;
}

.nd-doc table {
    width: 100%;
    border-collapse: collapse;
    font-size: .9rem;
    min-width: 460px;
}

.nd-doc thead th {
    text-align: left;
    font-family: var(--font-mono);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--s500);
    background: var(--s50);
    padding: 11px 14px;
    border-bottom: 1px solid var(--s200);
    white-space: nowrap;
}

.nd-doc tbody td {
    padding: 11px 14px;
    border-bottom: 1px solid var(--s100);
    vertical-align: top;
    color: var(--s700);
}

.nd-doc tbody tr:last-child td {
    border-bottom: 0;
}

.nd-doc tbody td:first-child {
    color: var(--s900);
    font-weight: 600;
}

.nd-doc .nd-num {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

/* ── PHONE ──────────────────────────────────────────────────────────
   Everything below 700px. Three separate problems, none of which a
   desktop viewport reveals.
   ─────────────────────────────────────────────────────────────────── */
@media (max-width: 700px) {

    /* 1. The header was reserving desktop-sized air above a headline
          that is already much shorter here. */
    .nd-legal-head {
        padding: calc(var(--site-nav) + 30px) 0 24px;
    }

    /* 2. The contents list is up to nineteen entries. Stacked in one
          column it pushed the first actual clause most of a screen
          down, so on a phone it runs as two compact columns and reads
          as an index rather than as a wall to scroll past. It is NOT
          given its own scrollbar — a nested scroller inside a page
          that also scrolls is worse than the problem it solves. */
    .nd-toc {
        padding: 14px 16px;
    }

    .nd-toc ol {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 2px 12px;
    }

    .nd-toc a {
        font-size: .82rem;
        padding: 5px 6px;
        margin: 0 -6px;
        gap: 7px;
    }

    /* 3. Tables stop being tables. Four columns inside a 460px
          min-width box meant sideways scrolling on every one of them;
          each row becomes a card instead, with the column header
          reappearing above each value via data-label. The labels live
          in the markup, so a <td> without one degrades to an unlabelled
          line rather than to something broken. */
    .nd-doc .nd-tblwrap {
        overflow-x: visible;
        border: 0;
        border-radius: 0;
    }

    .nd-doc table {
        min-width: 0;
        display: block;
    }

    .nd-doc thead {
        display: none;
    }

    .nd-doc tbody,
    .nd-doc tr,
    .nd-doc tbody td {
        display: block;
        width: 100%;
    }

    .nd-doc tbody tr {
        border: 1px solid var(--s200);
        border-radius: 12px;
        background: #fff;
        padding: 6px 14px;
        margin-bottom: 10px;
    }

    .nd-doc tbody tr:last-child {
        margin-bottom: 0;
    }

    .nd-doc tbody td {
        border-bottom: 0;
        padding: 8px 0;
    }

    .nd-doc tbody td+td {
        border-top: 1px solid var(--s100);
    }

    .nd-doc tbody td::before {
        content: attr(data-label);
        display: block;
        font-family: var(--font-mono);
        font-size: .66rem;
        font-weight: 700;
        letter-spacing: .07em;
        text-transform: uppercase;
        color: var(--s500);
        margin-bottom: 3px;
    }

    .nd-doc tbody td:empty {
        display: none;
    }
}

/* ── about page: the Infinite AI Solutions mark ──
   The artwork is a square that already carries its own purple ground
   AND the <democratizing.intelligence/> line, so this deliberately does
   NOT wrap it in a coloured panel or re-typeset the tagline underneath.
   Painting a purple behind it would need an exact colour match to avoid
   a visible seam, and setting the tagline twice reads as a mistake. */
.nd-brandmark {
    display: flex;
    justify-content: center;
    margin: 0;
}

.nd-brandmark img {
    width: min(340px, 88%);
    height: auto;
    border-radius: 18px;
    box-shadow: var(--site-shadow-lift);
}

/* the one or two sentences on a page that carry the argument */
.nd-doc .nd-lede {
    font-family: var(--font-display);
    font-size: clamp(1.06rem, 2vw, 1.24rem);
    font-weight: 600;
    line-height: 1.55;
    letter-spacing: -.01em;
    color: var(--s900);
    text-wrap: pretty;
    margin: 0 0 16px;
}

/* ── contact page: reachable-here cards ── */
.nd-reach {
    display: grid;
    gap: 14px;
    margin: 0 0 26px;
}

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

.nd-reach-card {
    border: 1px solid var(--s200);
    border-radius: 14px;
    padding: 20px;
    background: #fff;
    box-shadow: var(--site-shadow);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.nd-reach-card .ic {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    display: grid;
    place-items: center;
    background: var(--g50);
    color: var(--g600);
    font-size: 1rem;
    margin-bottom: 6px;
}

.nd-reach-card h3 {
    font-family: var(--font-display);
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--s900);
    margin: 0;
}

.nd-reach-card .val {
    font-size: .98rem;
    font-weight: 600;
    color: var(--g600);
    word-break: break-word;
}

.nd-reach-card .val a {
    color: inherit;
    text-decoration: none;
}

.nd-reach-card .val a:hover {
    text-decoration: underline;
}

.nd-reach-card .when {
    font-size: .85rem;
    color: var(--s500);
    line-height: 1.5;
}


/* ════ 24b. DELETE ACCOUNT ═════════════════════════════════════════
   site/delete-account.html only. Generated from genlegal.py like the
   rest of §24 — do not hand-edit the HTML.

   Deliberately NOT a red page. This is a legitimate thing to want to
   do, and a screen dressed as a warning either frightens someone who
   has every right to be here or gets clicked through by someone who
   does not. The weight sits in the words: what goes, what stays, and
   what happens to the money. Red appears once, on the button that
   actually does it. */
.nd-del {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    gap: 26px;
    align-items: start;
}

@media (max-width: 860px) {
    .nd-del {
        grid-template-columns: 1fr;
        gap: 20px;
    }
}

.nd-del-step {
    border: 1px solid var(--s200);
    border-radius: 14px;
    padding: 22px;
    background: #fff;
    box-shadow: var(--site-shadow);
}

.nd-del-step h3 {
    margin: 0 0 8px;
    font-size: 1.05rem;
    color: var(--s900);
}

.nd-del-step p {
    font-size: .9rem;
    line-height: 1.6;
    color: var(--s600);
    margin: 0 0 14px;
}

.nd-del-step label {
    display: block;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--s500);
    margin: 14px 0 6px;
}

.nd-del-step input[type="email"],
.nd-del-step input[type="text"] {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 14px;
    border: 1px solid var(--s300);
    border-radius: 10px;
    font: inherit;
    font-size: .95rem;
    color: var(--s900);
    background: #fff;
}

.nd-del-step input:focus {
    outline: 2px solid var(--g500);
    outline-offset: 1px;
    border-color: var(--g500);
}

.nd-del-step button {
    margin-top: 14px;
    width: 100%;
    padding: 13px 18px;
    border: 0;
    border-radius: 10px;
    font: inherit;
    font-weight: 650;
    font-size: .95rem;
    cursor: pointer;
    background: var(--g500);
    color: #fff;
}

/* The one red thing on the page, and only on the step that is
   irreversible. */
#del-go {
    background: var(--red);
}

.nd-del-step button:disabled {
    opacity: .45;
    cursor: not-allowed;
}

.nd-del-note {
    margin: 12px 0 0;
    font-size: .87rem;
    line-height: 1.55;
}

.nd-del-note.ok {
    color: #1a7355;
}

.nd-del-note.bad {
    color: var(--red);
}

.nd-del-note:empty {
    display: none;
}

.nd-del-money {
    margin: 12px 0;
    padding: 12px 14px;
    border-radius: 10px;
    border: 1px solid var(--s200);
}

.nd-del-money.ok {
    background: #f2f9f6;
    border-color: rgba(26, 115, 85, .25);
}

.nd-del-money.warn {
    background: var(--red-bg);
    border-color: rgba(196, 61, 61, .25);
}

.nd-del-money b {
    display: block;
    font-size: .95rem;
    color: var(--s900);
    margin-bottom: 4px;
}

.nd-del-money span {
    display: block;
    font-size: .85rem;
    line-height: 1.55;
    color: var(--s600);
}

.nd-del-check {
    display: flex !important;
    align-items: center;
    gap: 8px;
    margin-top: 10px !important;
    text-transform: none !important;
    letter-spacing: 0 !important;
    font-size: .87rem !important;
    font-weight: 600 !important;
    color: var(--s700) !important;
    cursor: pointer;
}

.nd-del-check input {
    width: auto;
    margin: 0;
}

.nd-del-hide {
    display: none !important;
}

.nd-del-aside {
    font-size: .88rem;
    line-height: 1.65;
    color: var(--s600);
}

.nd-del-aside h3 {
    margin: 0 0 8px;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--s500);
}

.nd-del-aside h3:not(:first-child) {
    margin-top: 22px;
}

.nd-del-aside ul {
    margin: 0;
    padding-left: 18px;
}

.nd-del-aside p {
    margin: 0 0 10px;
}


/* ════ 25. ABOUT PAGE ══════════════════════════════════════════════
   site/about.html only.

   This page is a snap deck, not a document — html.nd-snap and .nd-vp,
   one screen per scroll, the same as every other marketing page. It
   was briefly built on §24's document styles and read as a legal
   notice, which is the wrong register for the one page whose whole job
   is to say why the company exists.

   Almost everything here is borrowed: .nd-vp, .nd-sec-head, .nd-h0,
   .nd-h1, .nd-lead, .nd-eyebrow, .nd-pa-split, .nd-cta-row. Only the
   four things below are new, because nothing existing did them.

   SNAPPING: every section must fit 900x800 with nothing below the
   fold. §cost and §pricing are the tight ones — if copy grows there,
   check both before shipping.
   ════════════════════════════════════════════════════════════════ */

/* hero: the second paragraph, set below .nd-lead so two stacked
   paragraphs do not both shout */
.nd-ab-p {
    font-size: clamp(.96rem, 1.5vw, 1.06rem);
    line-height: 1.66;
    margin: 14px 0 0;
    max-width: 64ch;
}

/* body copy that runs in two columns on a wide screen purely so a
   section clears the fold; it is one continuous argument, not a grid */
.nd-ab-two {
    display: grid;
    gap: 10px clamp(26px, 3.4vw, 46px);
    margin-top: clamp(16px, 2.4vw, 26px);
}

.nd-ab-two p {
    margin: 0;
    font-size: clamp(.95rem, 1.45vw, 1.04rem);
    line-height: 1.68;
    color: var(--s600);
}

@media (min-width: 860px) {
    .nd-ab-two {
        grid-template-columns: 1fr 1fr;
    }
}

/* the three figures on §pricing */
.nd-ab-figs {
    display: grid;
    gap: 14px;
    margin-top: clamp(18px, 2.6vw, 30px);
}

@media (min-width: 760px) {
    .nd-ab-figs {
        grid-template-columns: repeat(3, 1fr);
    }
}

.nd-ab-fig {
    border: 1px solid var(--s200);
    border-radius: 16px;
    background: #fff;
    box-shadow: var(--site-shadow);
    padding: clamp(16px, 2.2vw, 22px);
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.nd-ab-fig b {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 3.4vw, 2rem);
    font-weight: 800;
    letter-spacing: -.02em;
    color: var(--s900);
    font-variant-numeric: tabular-nums;
}

.nd-ab-fig span {
    font-size: .92rem;
    line-height: 1.5;
    color: var(--s600);
}

.nd-ab-fig.free b {
    color: var(--g600);
}

/* the closing statement. Uppercase is set in CSS, not typed into the
   markup, so the sentence stays readable to a screen reader and stays
   editable as a sentence. */
.nd-ab-creed {
    max-width: 900px;
    margin: 0 auto;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(18px, 3vw, 30px);
}

.nd-ab-said {
    font-size: clamp(.98rem, 1.6vw, 1.1rem);
    line-height: 1.7;
    color: rgba(255, 255, 255, .74);
    max-width: 62ch;
    margin: 0;
}

.nd-ab-creed-h {
    font-family: var(--font-display);
    font-size: clamp(1.85rem, 6.2vw, 3.5rem);
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -.015em;
    text-transform: uppercase;
    text-wrap: balance;
    color: #fff;
    margin: 0;
}

.nd-ab-creed-h .accent {
    color: var(--site-sky);
}

.nd-ab-creed-sub {
    font-size: clamp(1rem, 1.7vw, 1.14rem);
    font-weight: 400;
    line-height: 1.6;
    color: rgba(255, 255, 255, .8);
    margin: 0;
}


/* ════ 25. PARENTAL CONSENT  (site/consent.html) ═══════════════════
   One column, generous measure, read once by somebody who did not
   ask to be here. No table of contents and no rail: this is a form
   with an explanation attached, not a document to navigate.

   The prose inside #cs-copy is rendered by JavaScript from
   /api/consent/form/<token>, so the selectors below style whatever
   consent.py happens to be serving. Do not put words in this file.
   ════════════════════════════════════════════════════════════════ */

.nd-consent {
    max-width: 660px;
    margin: 0 auto;
}

/* ⚠️ The hidden attribute works through `display: none` in the
   browser's own stylesheet, so ANY author display rule beats it. Every
   panel on this page is shown and hidden from JavaScript, and one of
   them — the "tell us more" label under Something else — is styled
   `display: block` by an ID selector further down, which meant it could
   never be hidden. !important because that selector outranks this one;
   scoped to .nd-consent so it decides nothing outside this page. */
.nd-consent [hidden] {
    display: none !important;
}

/* ── Centred states: loading, thank-you, dead link ── */
.nd-cs-mid {
    text-align: center;
    padding: 40px 20px 30px;
}

.nd-cs-mid h2 {
    margin: 0 0 10px;
    font-size: 1.35rem;
    color: var(--s900);
}

.nd-cs-mid p {
    margin: 0 auto 14px;
    max-width: 46ch;
    font-size: .95rem;
    line-height: 1.65;
    color: var(--s600);
    text-wrap: pretty;
}

.nd-cs-ico {
    font-size: 2.2rem;
    line-height: 1;
    margin-bottom: 16px;
    color: var(--g500);
}

.nd-cs-spin {
    width: 30px;
    height: 30px;
    margin: 0 auto 18px;
    border: 3px solid var(--s200);
    border-top-color: var(--g500);
    border-radius: 50%;
    animation: ndCsSpin .9s linear infinite;
}

@keyframes ndCsSpin {
    to { transform: rotate(360deg); }
}

/* ── The rendered copy ── */
.nd-cs-eyebrow {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--s500);
    margin: 0 0 20px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--s200);
    /* An email address is one unbreakable token on a narrow phone. */
    overflow-wrap: anywhere;
}

#cs-copy h2 {
    margin: 30px 0 10px;
    font-size: 1.12rem;
    color: var(--s900);
}

#cs-copy h2:first-of-type {
    margin-top: 0;
}

#cs-copy p {
    margin: 0 0 12px;
    font-size: .95rem;
    line-height: 1.7;
    color: var(--s700);
    text-wrap: pretty;
}

/* The plan and its price. A parent told only "your child uses NAADI"
   and later shown a charge was not properly asked, so this block is
   deliberately the loudest thing above the buttons. */
.nd-cs-plan {
    margin: 22px 0;
    padding: 18px 20px;
    border-radius: 14px;
    background: #f2f9f6;
    border: 1px solid rgba(26, 115, 85, .22);
}

.nd-cs-plan h3 {
    margin: 0 0 8px;
    font-size: 1rem;
    color: #1a7355;
}

.nd-cs-plan p {
    margin: 0 0 8px;
    font-size: .9rem;
    line-height: 1.6;
    color: var(--s700);
}

.nd-cs-plan p:last-child {
    margin-bottom: 0;
}

/* A header with no links in it. The wordmark stays so the page is
   recognisably ours; nothing in it can be tapped, because there is
   nowhere a parent answering a consent form should be sent. */
.nd-nav-focused .nd-nav-in {
    justify-content: center;
}

.nd-nav-focused .nd-brand {
    cursor: default;
}

.nd-cs-feat,
.nd-cs-inc {
    list-style: none;
    margin: 4px 0 18px;
    padding: 0;
    display: grid;
    gap: 8px;
}

/* What a free account actually opens. Inside the green plan panel, so
   it needs a little more room than the feature list outside it. */
.nd-cs-inc {
    margin: 14px 0 16px;
    gap: 11px;
}

.nd-cs-inc li {
    font-size: .89rem;
    line-height: 1.55;
    color: var(--s700);
    padding-left: 22px;
    position: relative;
}

.nd-cs-inc li::before {
    content: "\2713";
    position: absolute;
    left: 0;
    top: 0;
    font-weight: 700;
    color: #1a7355;
}

.nd-cs-inc b {
    display: block;
    color: var(--s900);
    font-weight: 650;
    margin-bottom: 1px;
}

.nd-cs-feat li {
    font-size: .9rem;
    line-height: 1.55;
    color: var(--s600);
    padding-left: 16px;
    position: relative;
}

.nd-cs-feat li::before {
    content: "";
    position: absolute;
    left: 0;
    top: .62em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--g500);
}

.nd-cs-feat b {
    display: block;
    color: var(--s900);
    font-weight: 650;
}

.nd-cs-links {
    margin: 18px 0 0;
    font-size: .87rem;
    line-height: 2;
    color: var(--s500);
}

.nd-cs-links a {
    color: var(--g600);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ── The decision ── */
.nd-cs-act {
    margin-top: 30px;
    padding: 22px;
    border: 1px solid var(--s200);
    border-radius: 14px;
    background: #fff;
    box-shadow: var(--site-shadow);
}

.nd-cs-tick {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    cursor: pointer;
    font-size: .93rem;
    line-height: 1.6;
    color: var(--s900);
    text-wrap: pretty;
}

.nd-cs-tick input {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    margin-top: 1px;
    accent-color: var(--g500);
}

.nd-consent button {
    margin-top: 12px;
    width: 100%;
    padding: 14px 18px;
    border: 0;
    border-radius: 10px;
    font: inherit;
    font-weight: 650;
    font-size: .95rem;
    cursor: pointer;
}

.nd-cs-yes {
    background: var(--g500);
    color: #fff;
}

/* Refusing is a legitimate answer, not a destructive act, so it is
   an outline and not the red button. Red here would read as a
   warning against saying no. */
.nd-cs-no {
    background: #fff;
    border: 1px solid var(--s300) !important;
    color: var(--s700);
}

.nd-cs-skip {
    background: none;
    color: var(--s500);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.nd-consent button:disabled {
    opacity: .45;
    cursor: not-allowed;
}

.nd-cs-help {
    margin: 14px 0 0;
    font-size: .85rem;
    line-height: 1.6;
    color: var(--s500);
    text-align: center;
    text-wrap: pretty;
}

.nd-cs-err {
    margin: 12px 0 0;
    font-size: .88rem;
    line-height: 1.55;
    color: var(--red);
}

/* ── Why not? ── */
#cs-why h2 {
    margin: 0 0 8px;
    font-size: 1.25rem;
    color: var(--s900);
}

.nd-cs-sub {
    margin: 0 0 20px;
    font-size: .93rem;
    line-height: 1.65;
    color: var(--s600);
    text-wrap: pretty;
}

.nd-cs-reasons {
    display: grid;
    gap: 10px;
    margin-bottom: 18px;
}

.nd-cs-reason {
    display: flex;
    gap: 12px;
    align-items: center;
    padding: 14px 16px;
    border: 1px solid var(--s200);
    border-radius: 12px;
    cursor: pointer;
    font-size: .93rem;
    color: var(--s700);
    background: #fff;
    transition: border-color .15s, background .15s;
}

.nd-cs-reason:has(input:checked) {
    border-color: var(--g500);
    background: #f2f9f6;
}

.nd-cs-reason input {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    accent-color: var(--g500);
}

#cs-note,
#cs-wd-email {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 14px;
    border: 1px solid var(--s300);
    border-radius: 10px;
    font: inherit;
    font-size: .95rem;
    color: var(--s900);
    background: #fff;
}

#cs-note:focus,
#cs-wd-email:focus {
    outline: 2px solid var(--g500);
    outline-offset: 1px;
    border-color: var(--g500);
}

#cs-why label[for="cs-note"],
#cs-wd label[for="cs-wd-email"] {
    display: block;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--s500);
    margin: 14px 0 6px;
}

#cs-wd h2 {
    margin: 0 0 8px;
    font-size: 1.25rem;
    color: var(--s900);
}

@media (prefers-reduced-motion: reduce) {
    .nd-cs-spin {
        animation: none;
        border-top-color: var(--s200);
    }
}

/* Consent page, v1.1 copy — the blocks the new structure added. */

#cs-copy h1 {
    margin: 0 0 12px;
    font-size: 1.38rem;
    line-height: 1.3;
    color: var(--s900);
    text-wrap: balance;
}

#cs-copy h3 {
    margin: 22px 0 8px;
    font-size: .98rem;
    color: var(--s900);
}

/* The two prices, side by side. A parent scanning for "what will this
   cost me" should not have to read a paragraph to find out. */
.nd-cs-prices {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin: 16px 0 18px;
}

.nd-cs-price {
    flex: 1 1 180px;
    padding: 16px 18px;
    border: 1px solid var(--s200);
    border-radius: 12px;
    background: #fff;
}

.nd-cs-price b {
    display: block;
    font-size: 1.25rem;
    color: var(--s900);
    line-height: 1.2;
}

.nd-cs-price span {
    display: block;
    margin-top: 2px;
    font-size: .87rem;
    color: var(--s600);
}

/* The one line of belief on the page. Set apart because it is a claim
   about intent, not a feature. */
.nd-cs-belief {
    margin: 28px 0;
    padding: 22px 24px;
    border-radius: 14px;
    background: #f2f9f6;
    border: 1px solid rgba(26, 115, 85, .22);
    text-align: center;
}

.nd-cs-belief p {
    margin: 0 0 6px;
    font-size: 1.06rem;
    font-weight: 650;
    line-height: 1.4;
    color: #1a7355;
    text-wrap: balance;
}

.nd-cs-belief span {
    font-size: .88rem;
    color: var(--s600);
}

/* Sits under the two buttons: the account waits, and this is reversible. */
.nd-cs-help p {
    margin: 0 0 6px;
    font-size: .85rem;
    line-height: 1.6;
    color: var(--s500);
    text-align: center;
    text-wrap: pretty;
}

.nd-cs-help p:last-child {
    margin-bottom: 0;
}

.nd-cs-signoff {
    margin: 30px 0 0;
    text-align: center;
    font-size: .85rem;
    line-height: 1.7;
    color: var(--s500);
}

.nd-cs-signoff b {
    color: var(--s900);
    letter-spacing: .04em;
}
