/* ============================================================
   OpenGrading — public site
   ============================================================ */

:root {
    --ink: #12152b;
    --ink-soft: #4a5070;
    --muted: #878da6;
    --violet: #6c5ce7;
    --violet-dark: #5a4bd6;
    --violet-soft: #f1eeff;
    --line: #e7e9f0;
    --line-dark: rgba(255, 255, 255, .12);
    --paper: #ffffff;
    --shell: 1680px;
    --gutter: clamp(20px, 3vw, 52px);
    --section: clamp(76px, 9vw, 136px);
}

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

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

@media (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }
}

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

/* height:auto is what keeps the width/height attributes from stretching an
   image: those attributes set a specified height, which otherwise wins over a
   CSS width on its own. The attributes stay, they reserve the box and spare
   the page a layout shift; a rule that needs a real height sets its own. */
img {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    color: inherit;
    text-decoration: none;
}

h1, h2, h3, h4, p, figure, blockquote, ul {
    margin: 0;
}

ul {
    padding: 0;
    list-style: none;
}

.shell {
    width: 100%;
    max-width: var(--shell);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

/* ---------- Type scale ---------- */
.display {
    font-size: clamp(36px, 4.4vw, 62px);
    line-height: 1.06;
    letter-spacing: -.032em;
    font-weight: 800;
}

.h2 {
    font-size: clamp(29px, 3.4vw, 46px);
    line-height: 1.1;
    letter-spacing: -.03em;
    font-weight: 800;
}

.lead {
    font-size: clamp(16.5px, 1.25vw, 19px);
    line-height: 1.65;
    color: var(--ink-soft);
}
.chapter {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
}

.chapter-name {
    font-family: 'Parisienne', cursive;
    font-size: clamp(26px, 2.4vw, 34px);
    line-height: 1.1;
    color: var(--violet);
}

.chapter-rank {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .18em;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    flex: none;
}

/* The hero announces an audience, not a chapter: no rule, no number. */
.kicker {
    font-size: 12.5px;
    font-weight: 800;
    letter-spacing: .17em;
    text-transform: uppercase;
    color: var(--violet);
}

.band .chapter-name {
    color: #b3a6ff;
}

.band .chapter-rank {
    color: rgba(255, 255, 255, .38);
}

.ink-accent {
    color: var(--violet);
}

/* ---------- Actions ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    height: 54px;
    padding: 0 28px;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    transition: transform .22s cubic-bezier(.22, .61, .36, 1), box-shadow .22s ease, background .22s ease;
}

.btn-solid {
    background: var(--violet);
    color: #fff;
    box-shadow: 0 12px 28px -14px rgba(108, 92, 231, .9);
}

.btn-solid:hover {
    background: var(--violet-dark);
    transform: translateY(-2px);
    box-shadow: 0 18px 36px -14px rgba(108, 92, 231, 1);
}

.btn-solid i {
    transition: transform .22s cubic-bezier(.22, .61, .36, 1);
}

.btn-solid:hover i {
    transform: translateX(4px);
}

.btn-paper {
    background: #fff;
    color: var(--violet);
}

.btn-paper:hover {
    transform: translateY(-2px);
    box-shadow: 0 18px 36px -16px rgba(18, 21, 43, .5);
}

/* A text action: the rule under it draws from the left on hover. */
.link-arrow {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 15px;
    font-weight: 700;
    padding-bottom: 4px;
}

.link-arrow::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1.5px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .3s cubic-bezier(.22, .61, .36, 1);
}

.link-arrow:hover::after {
    transform: scaleX(1);
}

.link-arrow i {
    font-size: 13px;
    transition: transform .22s ease;
}

.link-arrow:hover i {
    transform: translateX(4px);
}

/* ============================================================
   Masthead
   ============================================================ */
.masthead {
    position: fixed;
    inset: 0 0 auto;
    z-index: 50;
    transition: background .3s ease, box-shadow .3s ease, backdrop-filter .3s ease;
}

.masthead.is-stuck {
    background: rgba(255, 255, 255, .82);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    box-shadow: 0 1px 0 var(--line);
}

.masthead-inner {
    display: flex;
    align-items: center;
    gap: 32px;
    height: 78px;
}

.wordmark {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-right: auto;
}

.wordmark-logo {
    width: 38px;
    height: 38px;
    border-radius: 12px;
    background: linear-gradient(145deg, #8172f2, #6c5ce7);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 19px;
    flex: none;
    box-shadow: 0 8px 18px -10px rgba(108, 92, 231, .9);
}

.wordmark-name {
    font-family: 'Parisienne', cursive;
    font-size: 27px;
    line-height: 1;
    padding-top: 4px;
}

.masthead-nav {
    display: flex;
    align-items: center;
    gap: 30px;
}

.masthead-nav a {
    position: relative;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--ink-soft);
    transition: color .2s ease;
}

.masthead-nav a::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: -6px;
    height: 1.5px;
    background: var(--violet);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .3s cubic-bezier(.22, .61, .36, 1);
}

.masthead-nav a:hover,
.masthead-nav a.is-active {
    color: var(--ink);
}

.masthead-nav a:hover::after,
.masthead-nav a.is-active::after {
    transform: scaleX(1);
}

/* Pricing page: room for the fixed masthead, as the hero does */
.pricing-page {
    padding: clamp(112px, 12vw, 148px) 0 72px;
}

.masthead .btn {
    height: 44px;
    padding: 0 20px;
    font-size: 14px;
}

@media (max-width: 860px) {
    .masthead-nav {
        display: none;
    }
}

/* ============================================================
   Hero
   ============================================================ */
.hero {
    position: relative;
    padding: clamp(112px, 12vw, 148px) 0 calc(var(--section) / 2);
    overflow: hidden;
}

/* Two soft washes rather than a pattern: they give the white some depth
   without competing with the product shot. */
.hero::before,
.hero::after {
    content: '';
    position: absolute;
    border-radius: 50%;
    pointer-events: none;
    z-index: 0;
}

.hero::before {
    width: 820px;
    height: 820px;
    right: -240px;
    top: -340px;
    background: radial-gradient(circle, rgba(108, 92, 231, .17) 0%, rgba(108, 92, 231, 0) 65%);
}

.hero::after {
    width: 620px;
    height: 620px;
    left: -280px;
    top: 180px;
    background: radial-gradient(circle, rgba(232, 165, 42, .12) 0%, rgba(232, 165, 42, 0) 65%);
}

.hero-grid {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1.02fr .98fr;
    align-items: center;
    gap: clamp(36px, 5vw, 72px);
}

.hero-copy .kicker {
    margin: 0 0 26px;
}

.hero-copy .display {
    margin-bottom: 24px;
    max-width: 19ch;
}

.hero-copy .lead {
    max-width: 52ch;
    margin-bottom: 38px;
}

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

/* ---------- The product shot ---------- */
.hero-stage {
    position: relative;
    display: flex;
    justify-content: center;
}

.hero-stage::before {
    content: '';
    position: absolute;
    inset: -8% -6% -14%;
    background: radial-gradient(60% 55% at 50% 45%, rgba(108, 92, 231, .22) 0%, rgba(108, 92, 231, 0) 70%);
    pointer-events: none;
}

.hero-shot {
    position: relative;
    width: min(100%, 540px);
    filter: drop-shadow(0 40px 60px rgba(18, 21, 43, .22));
    animation: float 9s ease-in-out infinite;
}

@keyframes float {
    0%, 100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-14px);
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero-shot {
        animation: none;
    }
}

@media (max-width: 900px) {
    .hero-grid {
        grid-template-columns: 1fr;
        gap: 30px;
    }

    /* The copy block dissolves so the headline, the shot, the lead and the
       call become siblings in one column and can be reordered: the picture
       goes straight under the headline instead of after the whole copy. */
    .hero-copy {
        display: contents;
    }

    .hero-copy .display {
        order: 1;
        margin-bottom: 0;
    }

    .hero-stage {
        order: 2;
    }

    .hero-copy .lead {
        order: 3;
        margin-bottom: 0;
    }

    .hero-actions {
        order: 4;
    }

    .hero-copy .display,
    .hero-copy .lead {
        max-width: none;
    }
}

/* Side by side the second call can be a plain link; stacked under a 54px pill
   it reads as a stray underline. Below this width the pair takes one shape and
   one width, the secondary in outline, so they read as a single block. */
@media (max-width: 560px) {
    .hero-actions {
        flex-direction: column;
        align-items: stretch;
        gap: 12px;
    }

    .hero-actions .btn {
        width: 100%;
        justify-content: center;
    }

    .hero-actions .link-arrow {
        justify-content: center;
        height: 54px;
        padding: 0 28px;
        border: 1px solid var(--line);
        border-radius: 999px;
        color: var(--ink);
    }

    .hero-actions .link-arrow::after {
        display: none;
    }
}

/* ---------- Figures under the hero ---------- */

.figures {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    margin-top: clamp(56px, 7vw, 92px);
}

.figure {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: clamp(30px, 3.2vw, 44px) clamp(12px, 1.6vw, 26px);
}

.figure + .figure {
    border-left: 1px solid var(--line);
}

.figure-value {
    font-size: clamp(30px, 3.1vw, 42px);
    font-weight: 800;
    letter-spacing: -.03em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* A short measure keeps a two-word and a four-word label the same shape
   under their number; balance splits the lines evenly where supported. */
.figure-label {
    margin-top: 12px;
    max-width: 19ch;
    font-size: 13.5px;
    color: var(--muted);
    line-height: 1.45;
    text-wrap: balance;
}

@media (max-width: 760px) {
    .figures {
        grid-template-columns: repeat(2, 1fr);
    }

    /* Two per row: only the second of each pair carries a divider, and the
       second row is separated by a rule instead of a column edge. */
    .figure:nth-child(odd) {
        border-left: none;
    }

    .figure:nth-child(n+3) {
        border-top: 1px solid var(--line);
    }
}

/* ============================================================
   Partner rail
   ============================================================ */
.rail {
    padding-block: calc(var(--section) / 2);
}

/* The rail now opens like a section: the kicker names it, the title carries
   the claim, and the logos run underneath. */
.rail-title {
    margin-top: 10px;
}

/* A continuous rail. The track carries the row twice, so moving it by half
   its own width returns to the exact starting frame: the loop has no seam. */
.marquee {
    position: relative;
    overflow: hidden;
    margin-top: 26px;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
}

.marquee-track {
    display: flex;
    width: max-content;
    animation: rail-slide 38s linear infinite;
}

.marquee:hover .marquee-track {
    animation-play-state: paused;
}

.marquee-group {
    display: flex;
    align-items: center;
    flex: none;
    gap: clamp(40px, 5vw, 86px);
    padding-right: clamp(40px, 5vw, 86px);
}

@keyframes rail-slide {
    to {
        transform: translateX(-50%);
    }
}

@media (prefers-reduced-motion: reduce) {
    .marquee-track {
        animation: none;
    }
}

.rail-logo {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    font-size: 16px;
    font-weight: 700;
    color: var(--ink);
    white-space: nowrap;
    transition: color .25s ease;
}

.rail-logo img {
    height: 26px;
    width: auto;
}

.rail-logo:hover {
    color: var(--violet);
}

/* ============================================================
   Section heads
   ============================================================ */
/* One spacing token for the whole page: each section carries half the gap,
   so any two neighbours add up to exactly var(--section). Nothing has to
   cancel anyone else's padding, and the rhythm stays even end to end. */
.section {
    padding-block: calc(var(--section) / 2);
}

.section-head {
    margin-bottom: clamp(44px, 5vw, 72px);
}

.section-head .h2,
.section-head .lead {
    max-width: 680px;
}

.section-head .chapter {
    margin-bottom: 26px;
}

.section-head .h2 {
    margin-bottom: 18px;
}

/* ============================================================
   Why Eska — one flow, three points of view
   The page's shell runs to 1680px, which is right for a marquee or a wide
   band but far too wide for prose: a line of text would run past comfortable
   reading length. This section therefore sets its own measure and splits it
   in two, so the copy keeps a readable column and the photograph carries the
   other half instead of empty paper.
   ============================================================ */
/* No measure of its own: the section sits on the page's shell, so its left
   edge lines up with the figures above it and the steps below. The prose is
   kept readable by capping the text itself, not by narrowing the column.
   The clip is for the figure's soft wash, which is drawn past its own box on
   purpose; clip, not hidden, so the column never becomes a scroll box. */
.why-shell {
    overflow-x: clip;
}

.why-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.22fr) minmax(0, 1fr);
    gap: clamp(36px, 4.5vw, 80px);
    align-items: center;
}

/* The break lives in the markup, so the violet half always opens its own
   line; the measure only guards against a very wide viewport. */
.why-head .h2 {
    margin-bottom: 14px;
    max-width: 24ch;
}

.why-head .lead {
    max-width: 52ch;
    margin-bottom: clamp(26px, 2.8vw, 38px);
}

/* ---------- The three points of view ---------- */
.why-list {
    display: grid;
}

/* Each row is a hairline-separated line, not a card: the tint lives in the
   icon alone, so three rows never read as three competing boxes. */
.why-item {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: clamp(14px, 1.5vw, 20px);
    align-items: start;
    padding: clamp(16px, 1.7vw, 22px) 0 clamp(16px, 1.7vw, 22px) 18px;
    border-bottom: 1px solid var(--line);
}

.why-item:first-child {
    border-top: 1px solid var(--line);
}

/* The accent sits in the left gutter and grows from the middle on approach,
   so the row is marked without the text ever moving. */
.why-item::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    width: 3px;
    height: 100%;
    border-radius: 3px;
    background: var(--why-tint, var(--violet));
    transform: translateY(-50%) scaleY(0);
    transition: transform .45s cubic-bezier(.22, .61, .36, 1);
}

.why-item:hover::before,
.why-item:focus-within::before {
    transform: translateY(-50%) scaleY(.68);
}

.why-icon {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: 12px;
    background: var(--why-wash, var(--violet-soft));
    color: var(--why-tint, var(--violet));
    font-size: 18px;
    flex: none;
}

.why-item h3 {
    font-size: 15.5px;
    font-weight: 800;
    letter-spacing: -.01em;
    line-height: 1.3;
    margin-bottom: 5px;
}

.why-item p {
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--ink-soft);
    max-width: 54ch;
}

/* One hue per audience: the teacher's violet is the brand, the administration
   takes amber because it watches, the integration green because it passes. */
.why-item.is-teacher {
    --why-tint: #6c5ce7;
    --why-wash: #f1eeff;
}

.why-item.is-admin {
    --why-tint: #c07a12;
    --why-wash: #fdf3e2;
}

.why-item.is-system {
    --why-tint: #1a7f54;
    --why-wash: #e8f6ef;
}

/* ---------- The photograph ---------- */
.why-figure {
    position: relative;
    margin: 0 0 0 auto;
    width: 100%;
    max-width: 580px;
}

/* A soft violet wash sits behind the frame and is clipped by nothing, so the
   organic shape reads as cut from the page rather than pasted onto it. */
.why-figure::before {
    content: '';
    position: absolute;
    inset: -8% -6% -10% -8%;
    border-radius: 50%;
    background: radial-gradient(circle at 60% 40%, rgba(108, 92, 231, .16) 0%, rgba(108, 92, 231, 0) 68%);
    pointer-events: none;
}

/* height:auto is load-bearing */
.why-shot {
    position: relative;
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    object-position: 38% 55%;
    border-radius: 44% 56% 46% 54% / 38% 40% 60% 62%;
    background: var(--violet-soft);
}

.why-note {
    position: absolute;
    top: -17%;
    right: 0;
    max-width: 11ch;
    font-family: 'Parisienne', cursive;
    font-size: clamp(16px, 1.5vw, 21px);
    line-height: 1.35;
    color: var(--violet);
    transform: rotate(-7deg);
    text-align: center;
    pointer-events: none;
}

@media (max-width: 980px) {
    .why-grid {
        grid-template-columns: minmax(0, 1fr);
        gap: clamp(32px, 5vw, 48px);
    }

    /* The photograph leads on a narrow screen: it sets the scene before the
       three readings, and keeps the column from opening on a wall of text. */
    .why-figure {
        order: -1;
        max-width: 470px;
        margin-inline: auto;
    }

    .why-head .h2,
    .why-head .lead {
        max-width: none;
    }
}

@media (max-width: 560px) {
    .why-note {
        top: -9%;
        right: 2%;
    }

    .why-item {
        padding-left: 14px;
    }

    .why-icon {
        width: 36px;
        height: 36px;
        border-radius: 10px;
        font-size: 16px;
    }
}

/* ============================================================
   Four steps
   ============================================================ */
.steps {
    position: relative;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: clamp(20px, 2.6vw, 42px);
}

.step {
    position: relative;
    padding-top: 42px;
}

/* The rail runs behind the dots and stops at the last one. */
.step::after {
    content: '';
    position: absolute;
    left: 15px;
    right: calc(-1 * clamp(20px, 2.6vw, 42px));
    top: 7px;
    height: 1px;
    background: var(--line);
}

.step:last-child::after {
    display: none;
}

.step::before {
    content: '';
    position: absolute;
    left: 0;
    top: 2px;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--violet);
    box-shadow: 0 0 0 5px var(--violet-soft);
    z-index: 1;
}

.step-number {
    position: absolute;
    top: 26px;
    right: 0;
    font-size: clamp(44px, 4.6vw, 64px);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -.04em;
    color: var(--violet);
    opacity: .1;
    pointer-events: none;
}

.step h3 {
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -.015em;
    margin-bottom: 10px;
}

.step p {
    font-size: 14.5px;
    color: var(--ink-soft);
    line-height: 1.6;
    max-width: 30ch;
}

@media (max-width: 880px) {
    .steps {
        grid-template-columns: 1fr;
        gap: 0;
    }

    .step {
        padding: 0 0 30px 32px;
    }

    .step:last-child {
        padding-bottom: 0;
    }

    .step::before {
        top: 5px;
    }

    .step::after {
        left: 5px;
        right: auto;
        top: 18px;
        bottom: 0;
        width: 1px;
        height: auto;
    }

    .step-number {
        top: -8px;
        right: 0;
    }

    .step p {
        max-width: none;
    }
}

/* ============================================================
   API — a dark band gives the page its half-way breath
   ============================================================ */
.band {
    background: #12152b;
    color: #fff;
    padding: var(--section) 0;
    margin-block: calc(var(--section) / 2);
    position: relative;
    overflow: hidden;
}

.band::before {
    content: '';
    position: absolute;
    width: 760px;
    height: 760px;
    right: -200px;
    top: -280px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(108, 92, 231, .4) 0%, rgba(108, 92, 231, 0) 62%);
    pointer-events: none;
}

.band .shell {
    position: relative;
    z-index: 1;
}

.band-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(40px, 5vw, 80px);
    align-items: start;
}

.band .h2 {
    margin-bottom: 18px;
}

.band .lead {
    color: rgba(255, 255, 255, .62);
    margin-bottom: 34px;
}

.band .chapter {
    margin-bottom: 26px;
}

.grants {
    border-top: 1px solid var(--line-dark);
}

.grant {
    display: flex;
    align-items: baseline;
    gap: 14px;
    padding: 15px 0;
    border-bottom: 1px solid var(--line-dark);
    font-size: 15px;
    color: rgba(255, 255, 255, .8);
    transition: color .22s ease, padding-left .28s cubic-bezier(.22, .61, .36, 1);
}

.grant:hover {
    color: #fff;
    padding-left: 8px;
}

.grant i {
    color: #a99bff;
    font-size: 12px;
    flex: none;
}

/* The code is not a panel: it sits on the band behind a violet margin rule. */
.snippet {
    border-left: 2px solid rgba(169, 155, 255, .45);
    padding-left: clamp(20px, 2.4vw, 32px);
}

.snippet-label {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    color: rgba(255, 255, 255, .42);
    margin-bottom: 18px;
}

.snippet pre {
    margin: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: clamp(12.5px, 1.05vw, 14px);
    line-height: 1.9;
    color: rgba(255, 255, 255, .9);
    overflow-x: auto;
}

.tok-key {
    color: #a99bff;
}

.tok-str {
    color: #7fd6a4;
}

.tok-bool {
    color: #ffc978;
}

.tok-punct {
    color: rgba(255, 255, 255, .4);
}

@media (max-width: 880px) {
    .band-grid {
        grid-template-columns: 1fr;
    }
}

.cta-section {
    padding-block: calc(var(--section) / 2);
}

.cta-band {
    display: flex;
    align-items: center;
    gap: clamp(20px, 2.6vw, 38px);
    padding: clamp(26px, 3vw, 40px) clamp(24px, 3vw, 46px);
    border-radius: 18px;
    background: linear-gradient(118deg, #6c5ce7 0%, #5a4bd6 52%, #4668d8 100%);
    color: #fff;
    overflow: hidden;
    position: relative;
}

/* The same soft corner light the API band uses, so the two dark surfaces
   belong to one family. */
.cta-band::before {
    content: '';
    position: absolute;
    width: 520px;
    height: 520px;
    right: -140px;
    top: -260px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255, 255, 255, .13) 0%, rgba(255, 255, 255, 0) 64%);
    pointer-events: none;
}

.cta-icon {
    display: grid;
    place-items: center;
    width: 54px;
    height: 54px;
    flex: none;
    font-size: 26px;
    color: rgba(255, 255, 255, .85);
    position: relative;
    z-index: 1;
}

.cta-copy {
    position: relative;
    z-index: 1;
    min-width: 0;
}

.cta-title {
    font-size: clamp(18px, 1.6vw, 22px);
    font-weight: 800;
    letter-spacing: -.015em;
    line-height: 1.3;
    margin-bottom: 7px;
}

.cta-copy p {
    font-size: 14.5px;
    line-height: 1.55;
    color: rgba(255, 255, 255, .72);
    max-width: 62ch;
}

.cta-btn {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    flex: none;
    margin-left: auto;
    padding: 13px 22px;
    border-radius: 9px;
    background: #fff;
    color: var(--violet);
    font-size: 14px;
    font-weight: 700;
    position: relative;
    z-index: 1;
    transition: background .25s ease, transform .25s ease;
}

.cta-btn:hover {
    background: var(--violet-soft);
    transform: translateY(-1px);
}

.cta-btn i {
    font-size: 15px;
}

/* Stacked, the action goes full width so it stays the obvious next step. */
@media (max-width: 820px) {
    .cta-band {
        flex-wrap: wrap;
        align-items: flex-start;
        gap: 18px;
    }

    .cta-icon {
        width: 44px;
        height: 44px;
        font-size: 22px;
    }

    .cta-copy {
        flex: 1 1 260px;
    }

    .cta-btn {
        margin-left: 0;
        width: 100%;
        justify-content: center;
    }
}

/* ============================================================
   Footer
   ============================================================ */
.footer {
    padding: calc(var(--section) / 2) 0 40px;
}

.footer-grid {
    display: grid;
    grid-template-columns: 1.6fr repeat(3, 1fr);
    gap: 40px clamp(24px, 3vw, 56px);
}

.footer-about {
    font-size: 14.5px;
    color: var(--ink-soft);
    line-height: 1.65;
    max-width: 38ch;
    margin: 18px 0 22px;
}

.footer h3 {
    font-size: 12px;
    font-weight: 800;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 18px;
}

.footer-links li + li {
    margin-top: 11px;
}

.footer-links a {
    font-size: 14.5px;
    color: var(--ink-soft);
    transition: color .2s ease;
}

.footer-links a:hover {
    color: var(--violet);
}

.footer-social {
    display: flex;
    gap: 10px;
}

.footer-social a {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink-soft);
    background: var(--violet-soft);
    transition: background .22s ease, color .22s ease, transform .22s ease;
}

.footer-social a:hover {
    background: var(--violet);
    color: #fff;
    transform: translateY(-2px);
}

.footer-base {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 10px;
    margin-top: clamp(44px, 5vw, 68px);
    padding-top: 26px;
    border-top: 1px solid var(--line);
    font-size: 13.5px;
    color: var(--muted);
}

@media (max-width: 880px) {
    .footer-grid {
        grid-template-columns: 1fr 1fr;
    }

    .footer-brand {
        grid-column: 1 / -1;
    }
}

/* ============================================================
   Scroll reveal
   The class is set on <html> by a head script: without it, or with reduced
   motion, nothing is ever hidden.
   ============================================================ */
.anim [data-reveal] {
    opacity: 0;
    transform: translateY(22px);
    transition: opacity .7s cubic-bezier(.22, .61, .36, 1),
                transform .7s cubic-bezier(.22, .61, .36, 1);
}

.anim [data-reveal].is-in {
    opacity: 1;
    transform: none;
}

/* On a phone the wordmark and a full-width action cannot share the bar; the
   hero's own call sits just below the fold, so the bar keeps only the mark. */
@media (max-width: 560px) {
    .masthead .btn {
        display: none;
    }

    .masthead-inner {
        height: 68px;
    }

    .wordmark-name {
        font-size: 24px;
    }
}

/* ============================================================
   Hero motion — the product, played
   A phone enters four marks and submits them; the laptop then shows the very
   same marks landing in the dashboard. Everything is drawn in CSS, so it stays
   sharp at any size, weighs nothing next to a video, and the copy inside it is
   real text rather than pixels. The timeline lives in one rAF loop that only
   toggles classes, so nothing animates off-screen.
   ============================================================ */
.scene {
    position: relative;
    width: 100%;
    aspect-ratio: 3 / 2;
    /* every inner size is in cqw, so the whole scene scales as one drawing */
    container-type: inline-size;
}

.dv {
    position: absolute;
    transition: transform 1.1s cubic-bezier(.65, 0, .35, 1), opacity .7s ease;
}

/* ---------- The laptop ---------- */
.dv-lap {
    right: 0;
    top: 9%;
    width: 78cqw;
    opacity: 0;
    transform: translateX(5cqw) scale(.95);
}

.scene.is-wide .dv-lap {
    opacity: 1;
    transform: none;
}

.lap-lid {
    border-radius: 2.2cqw;
    padding: .9cqw;
    background: linear-gradient(160deg, #3a3f52, #20232f);
    box-shadow: 0 6cqw 8cqw -4cqw rgba(18, 21, 43, .45);
}

.lap-screen {
    position: relative;
    aspect-ratio: 16 / 10;
    border-radius: 1.4cqw;
    overflow: hidden;
    background: #0f1226;
}

.lap-foot {
    height: 1.5cqw;
    margin: 0 -6%;
    border-radius: 0 0 1.4cqw 1.4cqw;
    background: linear-gradient(180deg, #2a2e3d, #171a24);
}

.lap-foot::after {
    content: '';
    display: block;
    width: 14%;
    height: .45cqw;
    margin: 0 auto;
    border-radius: 0 0 .6cqw .6cqw;
    background: rgba(255, 255, 255, .16);
}

/* ---------- The web app inside it ---------- */
.web {
    position: absolute;
    inset: 0;
    display: flex;
    background: #f7f6fd;
    font-size: 1.5cqw;
    line-height: 1.3;
}

.web-side {
    width: 7%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.4cqw;
    padding-top: 1.6cqw;
    background: #efecfb;
}

.ws-dot {
    width: 2.1cqw;
    height: 2.1cqw;
    border-radius: .6cqw;
    background: #cfc8ef;
    transition: background .3s ease;
}

.ws-dot.is-on {
    background: var(--violet);
}

.web-main {
    position: relative;
    flex: 1;
    min-width: 0;
}

.web-view {
    position: absolute;
    inset: 0;
    padding: 2.2cqw 2.6cqw;
    opacity: 0;
    transform: translateY(1.6cqw);
    transition: opacity .5s ease, transform .5s ease;
    pointer-events: none;
}

.web-view.is-on {
    opacity: 1;
    transform: none;
}

/* ---------- The submission page, as the platform draws it ---------- */
.wn-top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1cqw;
    font-size: 1.15cqw;
    margin-bottom: .6cqw;
}
.wn-right{
    display: flex;
    justify-content: center;
    align-content: center;
    gap: 2px;
}

.wn-school {
    font-weight: 800;
    color: var(--ink);
}

.wn-when {
    color: #9195ae;
}

/* The teacher is announced in the middle of the page, under their portrait. */
.wn-head {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .6cqw;
    margin-bottom: 1.4cqw;
}

.wn-face {
    width: 4.4cqw;
    height: 4.4cqw;
    border-radius: 50%;
    background: #ded9f0;
    box-shadow: inset 0 -.5cqw 1cqw rgba(108, 92, 231, .14);
    flex: none;
}

.wn-face.sm {
    width: 2.4cqw;
    height: 2.4cqw;
}

.wn-name {
    font-weight: 800;
    font-size: 2.1cqw;
    letter-spacing: -.02em;
    color: var(--ink);
}

.wn-crumb {
    display: flex;
    align-items: center;
    gap: .7cqw;
    font-size: 1.2cqw;
    color: #6f738c;
    margin-bottom: .7cqw;
}

.wn-crumb i {
    width: .7cqw;
    height: .7cqw;
    border-radius: 50%;
    background: var(--violet);
    flex: none;
}

.wn-rank {
    width: 1.6cqw;
    text-align: center;
    font-size: 1.2cqw;
    color: #9195ae;
    font-variant-numeric: tabular-nums;
    flex: none;
}

/* Surname set apart from the given names, with the roll number beneath. */
.wn-who {
    min-width: 0;
    font-size: 1.2cqw;
    color: #3a3d55;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wn-who b {
    font-weight: 800;
    color: var(--ink);
}

.wn-who s {
    display: block;
    text-decoration: none;
    font-size: 1cqw;
    color: #9ca0b6;
}

.wn-mark {
    margin-left: auto;
    font-weight: 800;
    font-size: 1.5cqw;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    flex: none;
}

.wv-crumb {
    color: #8b90ab;
    margin-bottom: .5cqw;
}

.wv-title {
    font-weight: 800;
    font-size: 2.3cqw;
    letter-spacing: -.02em;
    color: var(--ink);
    margin-bottom: 1.6cqw;
}

.wv-rows {
    display: block;
}

.wv-row {
    display: flex;
    align-items: center;
    gap: 1cqw;
    padding: .7cqw .6cqw;
    border-bottom: 1px solid #ebe9f4;
    color: var(--ink);
    opacity: 0;
    transform: translateX(-1.2cqw);
}

.web-notes.is-on .wv-row {
    animation: wvIn .45s cubic-bezier(.22, .61, .36, 1) forwards;
}

.web-notes.is-on .wv-row:nth-child(2) { animation-delay: .09s; }
.web-notes.is-on .wv-row:nth-child(3) { animation-delay: .18s; }
.web-notes.is-on .wv-row:nth-child(4) { animation-delay: .27s; }

@keyframes wvIn {
    to { opacity: 1; transform: none; }
}

/* ---------- The dashboard ---------- */
.wd-cards {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.1cqw;
    margin-bottom: 1.6cqw;
}

.wd-card {
    display: block;
    padding: 1.1cqw 1.2cqw;
    border-radius: .9cqw;
    background: #fff;
    box-shadow: 0 .3cqw .9cqw -.5cqw rgba(18, 21, 43, .16);
}

.wd-card em {
    display: block;
    font-style: normal;
    color: #8b90ab;
    font-size: 1.3cqw;
}

.wd-card b {
    font-size: 2.6cqw;
    font-weight: 800;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

.wd-panels {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.1cqw;
}

.wd-panel {
    display: block;
    padding: 1.2cqw;
    border-radius: .9cqw;
    background: #fff;
    box-shadow: 0 .3cqw .9cqw -.5cqw rgba(18, 21, 43, .16);
}

.wd-panel em {
    display: block;
    font-style: normal;
    font-weight: 700;
    color: var(--ink);
    margin-bottom: 1cqw;
    font-size: 1.4cqw;
}

/* Each bar is introduced by its subject and its count, as on the real board. */
.wd-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .8cqw;
    font-size: 1.15cqw;
    color: #8b90ab;
    margin-bottom: .35cqw;
}

.wd-line u {
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wd-line s {
    text-decoration: none;
    font-weight: 700;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    flex: none;
}

.wd-bar {
    display: block;
    height: .75cqw;
    border-radius: 999px;
    background: #ece9f8;
    margin-bottom: .8cqw;
    overflow: hidden;
}

.wd-bar::after {
    content: '';
    display: block;
    height: 100%;
    width: 0;
    border-radius: 999px;
    background: var(--violet);
    transition: width .9s cubic-bezier(.22, .61, .36, 1);
}

.wd-panel.is-green .wd-bar::after {
    background: #1fb573;
}

.web-dash.is-on .wd-bar::after {
    width: var(--w);
}

.wd-panel .wd-bar:nth-of-type(2)::after { transition-delay: .1s; }
.wd-panel .wd-bar:nth-of-type(3)::after { transition-delay: .2s; }
.wd-panel .wd-bar:nth-of-type(4)::after { transition-delay: .3s; }

.wd-bar { margin-bottom: 1cqw; }

/* The pointer that clicks the dashboard across in the sidebar. */
.web-cursor {
    position: absolute;
    left: 24%;
    top: 46%;
    width: 1.9cqw;
    height: 1.9cqw;
    border-radius: 50%;
    background: rgba(18, 21, 43, .5);
    box-shadow: 0 0 0 .5cqw rgba(18, 21, 43, .12);
    opacity: 0;
    transition: opacity .3s ease, left .7s cubic-bezier(.65, 0, .35, 1), top .7s cubic-bezier(.65, 0, .35, 1), transform .2s ease;
    pointer-events: none;
}

.scene.is-pointing .web-cursor {
    opacity: 1;
    left: 3.4%;
    top: 26%;
}

.scene.is-clicking .web-cursor {
    transform: scale(.7);
}

/* ---------- The marks, in flight ----------
   Each mark that is saved leaves the phone and settles into a stack, so the
   half of the frame the laptop has not reached yet carries the very thing
   being produced. On submit the stack packs into one parcel, and the parcel
   dissolves exactly where the laptop materialises: the machine arrives built
   out of the data rather than merely next to it. */
.flock {
    position: absolute;
    left: 61%;
    top: 16%;
    width: 36%;
    z-index: 1;
    pointer-events: none;
}

.chip {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1cqw;
    padding: .95cqw 1.2cqw;
    margin-bottom: .9cqw;
    border-radius: .9cqw;
    background: #fff;
    box-shadow: 0 .6cqw 1.6cqw -.6cqw rgba(18, 21, 43, .22);
    font-size: 1.25cqw;
    opacity: 0;
    /* starts down and to the left: the row it was just typed into */
    transform: translate(-72%, 62%) scale(.5);
    transition: opacity .45s ease, transform .6s cubic-bezier(.34, 1.26, .64, 1);
}

.chip.is-in {
    opacity: 1;
    transform: none;
}

.chip em {
    font-style: normal;
    font-weight: 700;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chip b {
    margin-left: auto;
    font-weight: 800;
    color: var(--violet);
    font-variant-numeric: tabular-nums;
    flex: none;
}

/* Packed: every chip slides back onto the first one's seat and fades, while
   the parcel takes their place. --k is the chip's rank, so one rule moves
   all four by their own distance. */
.flock.is-packed .chip {
    opacity: 0;
    transform: translateY(calc(var(--k) * -4.25cqw)) scale(.92);
    transition-duration: .4s;
}

.packet {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    display: block;
    padding: 1.2cqw 1.4cqw;
    border-radius: 1cqw;
    background: linear-gradient(135deg, #6c5ce7, #5a4bd6);
    color: #fff;
    box-shadow: 0 1cqw 2.4cqw -.8cqw rgba(108, 92, 231, .7);
    opacity: 0;
    transform: scale(.82);
    transition: opacity .35s ease, transform .5s cubic-bezier(.34, 1.26, .64, 1);
}

.packet em {
    display: block;
    font-style: normal;
    font-weight: 800;
    font-size: 1.6cqw;
}

.packet s {
    display: block;
    text-decoration: none;
    font-size: 1.1cqw;
    color: rgba(255, 255, 255, .78);
}

.flock.is-packed .packet {
    opacity: 1;
    transform: none;
}

/* Gone: the parcel flies into the space the laptop is opening up. */
.flock.is-gone .packet {
    opacity: 0;
    transform: translate(14cqw, 6cqw) scale(.55);
    transition-duration: .65s;
}

/* ---------- The phone ---------- */
.dv-phone {
    left: 2%;
    bottom: 0;
    width: 26cqw;
    transform: translate(108%, -8%) scale(1.08);
    transform-origin: center;
    z-index: 2;
}

.scene.is-wide .dv-phone {
    transform: none;
}

.ph-body {
    position: relative;
    border-radius: 4.2cqw;
    padding: .85cqw;
    background: linear-gradient(155deg, #3c4055, #1d2029);
    box-shadow: 0 5cqw 7cqw -3cqw rgba(18, 21, 43, .5);
}

.ph-island {
    position: absolute;
    top: 2.1cqw;
    left: 50%;
    transform: translateX(-50%);
    width: 26%;
    height: 1.5cqw;
    border-radius: 999px;
    background: #10121a;
    z-index: 3;
}

.ph-screen {
    position: relative;
    aspect-ratio: 9 / 19;
    border-radius: 3.5cqw;
    overflow: hidden;
    background: #fbfcfa;
}

.app {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    font-size: 1.35cqw;
    line-height: 1.25;
}

/* The app's own indigo, taken from the running build. */
.app-bar {
    display: flex;
    align-items: center;
    gap: 1.4cqw;
    padding: 3.4cqw 1.6cqw 1.3cqw;
    background: #261c57;
    color: #fff;
    font-weight: 700;
    font-size: 1.6cqw;
}

.ab-back,
.ab-menu {
    width: 1.6cqw;
    height: 1.6cqw;
    border-radius: .3cqw;
    background: rgba(255, 255, 255, .55);
    flex: none;
}

.ab-menu {
    margin-left: auto;
}

.app-tabs {
    display: flex;
    background: #fff;
    border-bottom: 1px solid #e9e7f3;
}

.app-tabs span {
    flex: 1;
    text-align: center;
    padding: 1.2cqw .4cqw;
    color: #9a9ab0;
    font-size: 1.15cqw;
}

.app-tabs .is-on {
    color: #261c57;
    font-weight: 700;
    box-shadow: inset 0 -.35cqw 0 #261c57;
}

.app-rows {
    flex: 1;
    overflow: hidden;
    background: #fff;
}

.ap-row {
    display: flex;
    align-items: center;
    gap: 1.1cqw;
    padding: 1.35cqw 1.5cqw;
    border-bottom: 1px solid #f0eef7;
    color: #2a2c3d;
}

.ap-row i {
    width: 2.6cqw;
    height: 2.6cqw;
    border-radius: 50%;
    background: #d9dcdb;
    flex: none;
}

.ap-row em {
    font-style: normal;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ap-row b {
    margin-left: auto;
    font-weight: 700;
    color: #a6a8b8;
    font-variant-numeric: tabular-nums;
    transition: color .25s ease;
}

.ap-row.is-done b {
    color: #261c57;
}

.app-send {
    padding: 1.5cqw;
    text-align: center;
    background: #261c57;
    color: #fff;
    font-weight: 700;
    font-size: 1.4cqw;
    transition: filter .2s ease;
}

.app-send.is-press {
    filter: brightness(1.35);
}

/* The mark dialog, as the app draws it. */
.app-modal {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: rgba(20, 18, 40, .42);
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s ease;
}

.app-modal.is-on {
    opacity: 1;
}

.am-box {
    width: 74%;
    padding: 2cqw 1.8cqw 1.4cqw;
    border-radius: 1cqw;
    background: #fff;
    transform: scale(.94);
    transition: transform .25s cubic-bezier(.22, .61, .36, 1);
}

.app-modal.is-on .am-box {
    transform: none;
}

.am-box p {
    font-size: 1.3cqw;
    color: #2a2c3d;
    margin-bottom: 1.6cqw;
}

.am-field {
    display: block;
    height: 2.4cqw;
    border-bottom: 1.5px solid #261c57;
    margin-bottom: 1.6cqw;
    font-size: 1.7cqw;
    font-weight: 700;
    color: #261c57;
}

.am-field s {
    text-decoration: none;
}

.am-acts {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1.4cqw;
    font-size: 1.2cqw;
}

.am-acts u {
    text-decoration: none;
    color: #7b7d92;
}

.am-acts b {
    padding: .7cqw 1.2cqw;
    border-radius: .4cqw;
    background: #261c57;
    color: #fff;
}

/* The confirmation the app shows after a submission. */
.app-toast {
    position: absolute;
    left: 50%;
    top: 7%;
    transform: translate(-50%, -1.2cqw);
    width: 82%;
    padding: 1.2cqw 1.4cqw;
    border-radius: 1cqw;
    background: #2c2c36;
    color: #fff;
    text-align: center;
    font-size: 1.2cqw;
    line-height: 1.35;
    opacity: 0;
    transition: opacity .3s ease, transform .3s ease;
}

.app-toast.is-on {
    opacity: 1;
    transform: translate(-50%, 0);
}

/* The finger. It only ever lands on something that reacts. */
.ph-tap {
    position: absolute;
    width: 4cqw;
    height: 4cqw;
    border-radius: 50%;
    border: .35cqw solid rgba(108, 92, 231, .75);
    background: rgba(108, 92, 231, .16);
    left: 76%;
    top: 40%;
    opacity: 0;
    transform: scale(.7);
    transition: opacity .25s ease, top .45s cubic-bezier(.65, 0, .35, 1), left .45s cubic-bezier(.65, 0, .35, 1), transform .25s ease;
    pointer-events: none;
    z-index: 4;
}

.dv-phone.is-tapping .ph-tap {
    opacity: 1;
    transform: scale(1);
}

/* ---------- Stacked, the laptop leads and the phone tucks in beside it ---------- */
@media (max-width: 900px) {
    .scene {
        aspect-ratio: 3 / 2;
    }
}

/* Motion is the whole point, so when it is refused the scene simply shows its
   last frame: the submission already on the dashboard. */
@media (prefers-reduced-motion: reduce) {
    .dv,
    .web-view,
    .wd-bar::after,
    .web-cursor,
    .ph-tap,
    .app-toast,
    .am-box {
        transition: none !important;
        animation: none !important;
    }
}
