/* =============================================================================
   Rise Foundation Payments - design system

   Typography and palette follow risefoundation.am, the foundation's own site.
   That resemblance is not cosmetic: a payment page looking unconnected to the
   site someone just left is indistinguishable from a phishing redirect.

   Fonts are self-hosted and subset in wwwroot/fonts - no CDN fonts or scripts on
   a page that takes card details, since every extra origin is another party who
   could alter it. The brand faces used to be merely NAMED in the stack and never
   shipped, which meant Armenian silently fell through to whatever the operating
   system happened to provide.

   Colours are role-named (--brand-500, --ink-700) rather than named after the
   hue, so a repalette is a token change and no component rule moves. Every value
   that carries text has its contrast ratio recorded beside it; the buttons on
   this site spend money, and an unreadable one is not a styling nicety.

   Dark mode overrides tokens only, never component rules, so the two themes
   cannot drift apart.
   ============================================================================= */

/* ---- fonts -------------------------------------------------------------------------------------
   Self-hosted and subset, from the same origin as everything else. No third-party font host is
   reachable from this page; see the no-CDN note above. Families match risefoundation.am so the
   payment surface is recognisably the same organisation.

   Each face declares a unicode-range, so the browser picks a file by CODEPOINT rather than by family
   order. Two consequences worth knowing: Armenian text can never be rendered in a Latin-only face
   however the stack is ordered or however <html lang> is tagged, and a page with no Armenian on it
   never downloads the Armenian files at all.

   Build steps and the reasons behind the subset are in wwwroot/fonts/README.md. */

@font-face {
  font-family: "Noto Sans"; src: url("fonts/noto-sans-latin.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Noto Sans Armenian"; src: url("fonts/noto-sans-armenian.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0530-058F, U+FB13-FB17;
}
@font-face {
  font-family: "Source Serif 4"; src: url("fonts/source-serif-4-latin.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Noto Serif Armenian"; src: url("fonts/noto-serif-armenian.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0530-058F, U+FB13-FB17;
}

:root {
    /* Teal, from the foundation's logo.
       The logo's own #2a9d8f is too light to carry white text - 3.3:1, below the
       4.5:1 WCAG AA needs for the 15px button label - so the interactive tone is
       darkened to #228276 (4.6:1) and the raw logo teal is kept for tints and
       borders where nothing sits on top of it. Unreadable buttons are not a
       styling nicety on a page where the button spends money. */
    --brand-50:  #eef1f8;
    --brand-100: #dde3f2;
    --brand-200: #b9c4e4;
    --brand-300: #3aa8a0;   /* risefoundation.am teal - 2.9:1 on white, so BORDERS AND TINTS ONLY, never behind text */
    --brand-500: #2440a8;   /* interactive: buttons, focus rings - white label 8.8:1 */
    --brand-600: #1b2c87;   /* risefoundation.am flag-blue - hover, white label 12.0:1 */
    --brand-700: #16204a;   /* risefoundation.am navy - links and headings on white, 15.7:1 */

    /* Warm gold, shared with bebras.am's --color-accent. Highlights and value
       flags only - never a primary action, so "attention" and "the thing to
       click" stay visually distinct. */
    --accent-50:  #fdf3df;
    --accent-200: #f7dfa8;
    --accent-500: #f0a81e;
    --accent-700: #5a2c05;   /* ink on the amber flag - 5.7:1. Never lighten this, in either theme. */

    --ink-900: #1c2226;
    --ink-700: #39434a;
    --ink-500: #4f585e;
    --ink-400: #767f84;
    --ink-200: #d2d8d7;
    --ink-100: #dfe4e3;
    --ink-50:  #f2f4f3;
    --white:   #ffffff;

    --success-50:  #eaf5f2;
    --success-200: #a9d8cd;
    --success-700: #0f6f5c;

    --warn-50:  #fdf4e6;
    --warn-200: #f7dfa8;
    --warn-700: #8e4708;

    --danger-50:  #fbeceb;
    --danger-200: #f3bfbd;
    /* Logo pink #ee4266 gives only 3.8:1 with white, so the button tone is a shade
       deeper; the lighter pink stays for borders and tinted panels. */
    --danger-500: #d3282c;
    --danger-700: #a11418;

    --page-bg: #eaedec;   /* risefoundation.am --background */

    /* The admin sidebar's own ground. It used to be var(--text), which is near-white in dark mode -
       so the panel rendered white-on-white and was unreadable. Navy also makes it the most direct
       cue to risefoundation.am anywhere in the product. White label: 15.7:1 light, 17.5:1 dark. */
    --admin-shell-bg: #16204a;
    --surface: var(--white);
    --border: var(--ink-200);
    --text: var(--ink-900);
    --text-muted: var(--ink-500);

    --radius-sm: 6px;
    --radius: 10px;
    --radius-lg: 16px;

    --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06);
    --shadow: 0 1px 3px rgba(15, 23, 42, .08), 0 4px 12px rgba(15, 23, 42, .05);
    --shadow-lg: 0 8px 30px rgba(15, 23, 42, .10);

    --space-1: .25rem;
    --space-2: .5rem;
    --space-3: .75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-8: 3rem;

    --ff-sans-am: "Noto Sans Armenian";
    --ff-sans: "Noto Sans";
    --ff-serif-am: "Noto Serif Armenian";
    --ff-serif: "Source Serif 4";
    --ff-fb-sans: "Segoe UI", "Arial Armenian", system-ui, -apple-system, sans-serif;
    --ff-fb-serif: Georgia, "Times New Roman", serif;

    /* Armenian first, matching risefoundation.am. Ordering is cosmetic rather than functional -
       unicode-range already decides which file serves which character - but it settles the codepoints
       both families could draw, such as digits and punctuation. */
    --font-sans: var(--ff-sans-am), var(--ff-sans), var(--ff-fb-sans);
    --font-serif: var(--ff-serif-am), var(--ff-serif), var(--ff-fb-serif);

    /* Kept so nothing referencing --font breaks while the switch-over happens in the next commit. */
    --font: var(--font-sans);

    /* Display face for headings, as used across bebras.am and codzilla.am. Falls
       back to the body stack, so a missing file costs weight, not legibility. */
    --font-mono: "Cascadia Mono", "SF Mono", Consolas, "Liberation Mono", monospace;

    --content-width: 68rem;
    --narrow-width: 44rem;
}

/* Latin-first when the element is tagged en or ru, Armenian-first otherwise - as risefoundation.am
   does. Custom properties inherit, so <span lang="en">Bebras</span> inside Armenian prose picks this
   up without a rule of its own. */
:lang(en), :lang(ru) {
  --font-sans: var(--ff-sans), var(--ff-sans-am), var(--ff-fb-sans);
  --font-serif: var(--ff-serif), var(--ff-serif-am), var(--ff-fb-serif);
}


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

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

body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: 1rem;
    line-height: 1.6;
    color: var(--text);
    background: var(--page-bg);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* ---------- Typography ---------------------------------------------------- */

/* Headings in the serif, body and forms in the sans. risefoundation.am sets serif for BODY copy too,
   which suits an editorial site; here the body is 15px form labels, table cells and 13px hints, and a
   serif at those sizes is materially harder to scan. Same identity, different register.

   The old -.01em tracking was tuned for Inter and a serif does not want it, and 650 is heavy on Source
   Serif, so both are reset here rather than inherited. */
h1, h2, h3, h4, .card__title, .product__name, .offer__name, .choice__title, .empty__title {
  font-family: var(--font-serif);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.3;
}
h1, h2, h3, h4 { margin: 0 0 var(--space-3); }
h1 { font-size: 1.875rem; }
h2 { font-size: 1.375rem; margin-top: var(--space-6); }
h3 { font-size: 1.125rem; margin-top: var(--space-5); }
h1:focus, h2:focus { outline: none; }

p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

a { color: var(--brand-700); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--brand-600); }

small, .text-sm { font-size: .875rem; }
.text-muted { color: var(--text-muted); }
.text-danger { color: var(--danger-700); }
code { font-family: var(--font-mono); font-size: .8125em; word-break: break-all; }

/* ---------- Layout -------------------------------------------------------- */

.page { flex: 1 0 auto; width: 100%; max-width: var(--content-width); margin: 0 auto; padding: var(--space-6) var(--space-4) var(--space-8); }

/* Used both as a modifier on .page and as a standalone wrapper inside it, so it has to centre itself. */
.page--narrow { max-width: var(--narrow-width); margin-inline: auto; }

/* Visible to screen readers only - for labels that would be redundant on screen. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.site-header { background: var(--surface); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 50; }
.site-header__inner { max-width: var(--content-width); margin: 0 auto; padding: var(--space-3) var(--space-4); display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.site-header__brand { font-weight: 700; color: var(--text); text-decoration: none; display: flex; align-items: center; gap: var(--space-2); margin-inline-end: auto; }
.site-header__mark { width: 2rem; height: 2rem; border-radius: var(--radius-sm); flex: none; object-fit: contain; }
.site-header__name { display: flex; flex-direction: column; line-height: 1.2; }
.site-header__name span:last-child { font-size: .75rem; font-weight: 500; color: var(--text-muted); }

.site-nav { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; }
.site-nav a { padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); color: var(--ink-700); text-decoration: none; font-size: .9375rem; font-weight: 500; }
.site-nav a:hover { background: var(--ink-100); color: var(--text); }
.site-nav a.active { background: var(--brand-50); color: var(--brand-700); }

.site-footer { flex: none; background: var(--surface); border-top: 1px solid var(--border); padding: var(--space-6) var(--space-4); font-size: .875rem; color: var(--text-muted); }
.site-footer__inner { max-width: var(--content-width); margin: 0 auto; display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-6); justify-content: space-between; }
.site-footer nav { display: flex; flex-wrap: wrap; gap: var(--space-3); }

/* Full width under the columns: it applies to every page, so it reads as a standing statement rather
   than one more footer column. */
.site-footer__assurance { flex: 1 0 100%; padding-top: var(--space-4); border-top: 1px solid var(--border); max-width: 70ch; }

/* ---------- Cards & surfaces ---------------------------------------------- */

.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-5); box-shadow: var(--shadow-sm); }
.card + .card { margin-top: var(--space-4); }
.card__title { margin: 0 0 var(--space-1); font-size: 1.0625rem; }
.card__hint { margin: 0 0 var(--space-4); color: var(--text-muted); font-size: .875rem; }

.grid { display: grid; gap: var(--space-4); }
.grid--products { grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }

.stack > * + * { margin-top: var(--space-4); }
.row { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; }
.row--end { justify-content: flex-end; }
.row--between { justify-content: space-between; }

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

.page-header { margin-bottom: var(--space-5); }
.page-header__lead { color: var(--text-muted); max-width: 60ch; margin: 0; }
.breadcrumb { display: flex; gap: var(--space-2); font-size: .875rem; color: var(--text-muted); margin-bottom: var(--space-2); padding: 0; list-style: none; flex-wrap: wrap; }
.breadcrumb a { color: var(--text-muted); }

/* ---------- Buttons ------------------------------------------------------- */

.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
    padding: .5625rem var(--space-4); border-radius: var(--radius-sm); border: 1px solid transparent;
    font: inherit; font-size: .9375rem; font-weight: 600; line-height: 1.2; cursor: pointer;
    text-decoration: none; transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }

.btn--primary { background: var(--brand-500); color: var(--surface); }
.btn--primary:hover:not(:disabled) { background: var(--brand-600); color: var(--surface); }

.btn--secondary { background: var(--surface); color: var(--ink-700); border-color: var(--border); }
.btn--secondary:hover:not(:disabled) { background: var(--ink-100); color: var(--text); }

.btn--danger { background: var(--danger-500); color: var(--surface); }
.btn--danger:hover:not(:disabled) { background: var(--danger-700); color: var(--surface); }

.btn--ghost { background: transparent; color: var(--ink-700); padding-inline: var(--space-2); }
.btn--ghost:hover:not(:disabled) { background: var(--ink-100); }

.btn--lg { padding: .75rem var(--space-5); font-size: 1rem; }
.btn--block { width: 100%; }

/* ---------- Forms --------------------------------------------------------- */

.field { margin-bottom: var(--space-4); }
.field > label, .field__label { display: block; font-weight: 600; font-size: .9375rem; margin-bottom: var(--space-1); }
.field__hint { display: block; font-size: .8125rem; color: var(--text-muted); margin-bottom: var(--space-2); }
.field__required { color: var(--danger-500); margin-inline-start: 2px; }

/* Matches on what an input is NOT, rather than listing the types it might be.
   Blazor's <InputText> emits a bare <input> with no type attribute at all unless one is passed
   explicitly, so an `input[type=text]` selector silently skipped every plain text field - names,
   school, address - leaving them as unstyled browser rectangles while the email and number fields
   next to them looked right. Excluding the controls that must not look like text boxes is the only
   form of this rule that cannot be defeated by a missing attribute. */
input:not([type=checkbox], [type=radio], [type=submit], [type=button], [type=file], [type=range], [type=color], [type=hidden]),
select,
textarea {
    width: 100%; padding: .5625rem var(--space-3); font: inherit; font-size: .9375rem; color: var(--text);
    background: var(--surface); border: 1px solid var(--ink-400); border-radius: var(--radius-sm);
    transition: border-color .12s ease, box-shadow .12s ease;
}

input:not([type=checkbox], [type=radio]):hover, select:hover, textarea:hover { border-color: var(--ink-500); }
input:focus-visible, select:focus-visible, textarea:focus-visible {
    outline: none; border-color: var(--brand-500);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-500) 25%, transparent);
}
input::placeholder { color: var(--ink-400); }

/* Inputs are full width by default, so text is never clipped. The narrower tiers below exist only
   where a field's width usefully signals how much is expected - a postcode in a full-width box invites
   a sentence - and every one is sized for its content in Armenian rather than for Latin digits.
   Erring wide: a field that is slightly too long costs nothing, one that truncates costs the user. */
.input--narrow { max-width: 9rem; }    /* pure digits: quantity, postcode, stock */
.input--code   { max-width: 15rem; }   /* short text or codes: unit, ADG code */
.input--money  { max-width: 15rem; }   /* an amount in drams, up to eight digits with separators */

/* A select's width is the width of its longest option, so it cannot be capped by a fixed max-width -
   that was clipping "— Ընտրեք —" on the grade picker. Sized to content instead, with a floor so a
   one-digit option list is still a comfortable target, and a ceiling of the container so a long option
   cannot push the form sideways. */
select {
    width: auto;
    min-width: 12rem;
    max-width: 100%;
}

.checkbox { display: flex; gap: var(--space-3); align-items: flex-start; font-weight: 500; cursor: pointer; }
.checkbox input[type=checkbox] { width: 1.125rem; height: 1.125rem; margin: .1875rem 0 0; flex: none; accent-color: var(--brand-500); cursor: pointer; }

/* Blazor validation hooks */
.valid.modified:not([type=checkbox]) { border-color: var(--success-700); }
.invalid { border-color: var(--danger-500); }
.validation-message { display: block; color: var(--danger-700); font-size: .8125rem; margin-top: var(--space-1); }
.validation-errors { margin: 0 0 var(--space-4); padding: var(--space-3) var(--space-4); background: var(--danger-50); border: 1px solid var(--danger-200); border-radius: var(--radius-sm); color: var(--danger-700); font-size: .875rem; }
.validation-errors ul { margin: 0; padding-inline-start: var(--space-4); }

/* ---------- Alerts & callouts --------------------------------------------- */

.alert { display: flex; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); border: 1px solid; font-size: .9375rem; }
.alert__icon { flex: none; font-size: 1rem; line-height: 1.5; }
.alert__body { min-width: 0; }
.alert--info { background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-700); }
.alert--success { background: var(--success-50); border-color: var(--success-200); color: var(--success-700); }
.alert--warning { background: var(--warn-50); border-color: var(--warn-200); color: var(--warn-700); }
.alert--danger { background: var(--danger-50); border-color: var(--danger-200); color: var(--danger-700); }

/* A destructive, irreversible action. Visually distinct from a mere warning so
   "this cannot be undone" is legible before the click, not after. */
.danger-zone { border: 1px solid var(--danger-200); border-radius: var(--radius); background: var(--danger-50); padding: var(--space-5); }
.danger-zone__title { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-2); font-size: 1rem; font-weight: 700; color: var(--danger-700); }
.danger-zone__body { font-size: .9375rem; color: var(--ink-700); }
.danger-zone__consequences { margin: 0 0 var(--space-4); padding-inline-start: var(--space-5); font-size: .9375rem; color: var(--ink-700); }
.danger-zone__consequences li { margin-bottom: var(--space-1); }
.danger-zone__confirm { padding: var(--space-3); background: var(--surface); border: 1px solid var(--danger-200); border-radius: var(--radius-sm); margin-bottom: var(--space-4); }

/* ---------- Badges -------------------------------------------------------- */

.badge { display: inline-flex; align-items: center; gap: var(--space-1); padding: .125rem var(--space-2); border-radius: 999px; font-size: .75rem; font-weight: 650; border: 1px solid; white-space: nowrap; }
.badge--neutral { background: var(--ink-100); border-color: var(--border); color: var(--ink-700); }
.badge--info { background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-700); }
.badge--success { background: var(--success-50); border-color: var(--success-200); color: var(--success-700); }
.badge--warning { background: var(--warn-50); border-color: var(--warn-200); color: var(--warn-700); }
.badge--danger { background: var(--danger-50); border-color: var(--danger-200); color: var(--danger-700); }

/* ---------- Tables -------------------------------------------------------- */

.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
table.data { width: 100%; border-collapse: collapse; font-size: .9375rem; }
table.data th, table.data td { padding: var(--space-3) var(--space-4); text-align: start; border-bottom: 1px solid var(--border); vertical-align: top; }
table.data thead th { background: var(--ink-50); font-size: .8125rem; font-weight: 650; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); white-space: nowrap; }
table.data tbody tr:last-child td { border-bottom: none; }
table.data tbody tr:hover { background: var(--ink-50); }
.num { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Key/value detail list, used for order metadata */
.kv { display: grid; grid-template-columns: minmax(8rem, max-content) 1fr; gap: var(--space-2) var(--space-4); margin: 0; font-size: .9375rem; }
.kv dt { color: var(--text-muted); }
.kv dd { margin: 0; }

/* ---------- Product cards ------------------------------------------------- */

.product { display: flex; flex-direction: column; gap: var(--space-2); }
.product__name { font-size: 1.0625rem; margin: 0; }
.product__desc { color: var(--text-muted); font-size: .9375rem; margin: 0; flex: 1 0 auto; }
.product__price { font-size: 1.25rem; font-weight: 700; }
.product__foot { margin-top: var(--space-2); }

/* ---------- Home page routing choices ------------------------------------- */

.choices { display: grid; gap: var(--space-3); }
.choice {
    display: flex; flex-direction: column; gap: var(--space-1);
    padding: var(--space-5); background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); text-decoration: none; color: inherit;
    box-shadow: var(--shadow-sm); transition: border-color .12s ease, box-shadow .12s ease;
}
.choice:hover { border-color: var(--brand-300); box-shadow: var(--shadow); color: inherit; }
.choice:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }
.choice__title { font-size: 1.0625rem; }
.choice__desc { color: var(--text-muted); font-size: .9375rem; }

/* ---------- Upsell: the one persuasive page ------------------------------- */

/* Reassurance first. A parent will not weigh a second purchase while still unsure the first worked. */
.secured {
    display: flex; gap: var(--space-3); align-items: center;
    padding: var(--space-4); margin-bottom: var(--space-5);
    background: var(--success-50); border: 1px solid var(--success-200);
    border-radius: var(--radius); color: var(--success-700);
}
.secured__tick {
    display: grid; place-items: center; flex: none;
    width: 1.75rem; height: 1.75rem; border-radius: 999px;
    background: var(--success-700); color: var(--surface); font-weight: 700;
}

.media { border-radius: var(--radius); overflow: hidden; background: var(--ink-100); }
.media video { display: block; width: 100%; height: auto; }

.offers { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }

.offer {
    position: relative; display: flex; flex-direction: column;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
    overflow: hidden; box-shadow: var(--shadow-sm);
    transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.offer:hover { box-shadow: var(--shadow); transform: translateY(-2px); }

/* The better-value option is meant to win the glance - a heavier border and a flag, not a trick. */
.offer--best { border-color: var(--brand-300); border-width: 2px; box-shadow: var(--shadow); }
.offer--chosen { border-color: var(--success-700); border-width: 2px; }

.offer__flag {
    position: absolute; inset-block-start: 0; inset-inline-end: 0;
    padding: var(--space-1) var(--space-3);
    background: var(--accent-500); color: var(--accent-700);
    font-size: .8125rem; font-weight: 700;
    border-end-start-radius: var(--radius);
}

.offer__image { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; background: var(--ink-100); }
.offer__image--empty {
    display: grid; place-items: center; padding: var(--space-4);
    color: var(--text-muted); font-size: .8125rem; text-align: center;
    background: linear-gradient(135deg, var(--ink-100), var(--brand-50));
}

.offer__body { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); flex: 1 0 auto; }
.offer__name { margin: 0; font-size: 1.0625rem; }
.offer__desc { margin: 0; font-size: .9375rem; color: var(--text-muted); flex: 1 0 auto; }

.offer__pricing { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
.offer__price { font-size: 1.5rem; font-weight: 700; }
.offer__was { color: var(--text-muted); text-decoration: line-through; font-size: 1rem; }

.offer__scarce { font-size: .875rem; font-weight: 600; color: var(--danger-700); }

.offer__foot { padding: 0 var(--space-4) var(--space-4); }

@media (max-width: 30rem) {
    .offers { grid-template-columns: 1fr; }
}

/* ---------- Steps / progress ---------------------------------------------- */

.steps { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: 0 0 var(--space-5); padding: 0; font-size: .875rem; }
.steps li { display: flex; align-items: center; gap: var(--space-2); color: var(--text-muted); }
.steps li::after { content: ""; width: 1.25rem; height: 1px; background: var(--border); margin-inline-start: var(--space-1); }
.steps li:last-child::after { display: none; }
.steps__num { display: grid; place-items: center; width: 1.5rem; height: 1.5rem; border-radius: 999px; background: var(--ink-100); color: var(--text-muted); font-size: .75rem; font-weight: 700; flex: none; }
.steps li.is-current { color: var(--text); font-weight: 600; }
.steps li.is-current .steps__num { background: var(--brand-500); color: var(--surface); }
.steps li.is-done .steps__num { background: var(--success-700); color: var(--surface); }  /* 6.1:1 light, 8.9:1 dark */

/* ---------- Flow controls ------------------------------------------------- */

/* Headcount picker. Big targets because this is the first thing anyone touches, often on a phone. */
.stepper { display: flex; align-items: center; gap: var(--space-4); }
.stepper__btn {
    width: 2.75rem; height: 2.75rem; flex: none;
    display: grid; place-items: center;
    font-size: 1.5rem; line-height: 1; font-family: inherit;
    background: var(--surface); color: var(--brand-700);
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    cursor: pointer;
}
.stepper__btn:hover:not(:disabled) { background: var(--brand-50); border-color: var(--brand-300); }
.stepper__btn:disabled { opacity: .4; cursor: not-allowed; }
.stepper__value { font-size: 1.75rem; font-weight: 700; min-width: 2rem; text-align: center; font-variant-numeric: tabular-nums; }

/* Back / running total / forward, in that order, on every step. */
.flow-nav {
    display: flex; align-items: center; gap: var(--space-3);
    margin-top: var(--space-5); padding-top: var(--space-4);
    border-top: 1px solid var(--border);
}
.flow-nav__total { margin-inline: auto; display: flex; flex-direction: column; align-items: center; line-height: 1.2; }

@media (max-width: 30rem) {
    .flow-nav { flex-wrap: wrap; }
    .flow-nav__total { order: -1; width: 100%; align-items: flex-start; margin-inline: 0; margin-bottom: var(--space-2); }
    .flow-nav .btn--lg { flex: 1 0 auto; }
}

/* Compact quantity control inside an offer card - reuses the stepper buttons. */
.qty { display: flex; align-items: center; gap: var(--space-2); }
.qty__value { font-size: 1.125rem; font-weight: 700; min-width: 1.75rem; text-align: center; font-variant-numeric: tabular-nums; }
.qty__total { margin-inline-start: auto; font-weight: 650; }

/* Type-to-search picker (schools). Absolute list so it overlays what follows rather
   than shoving the form down as suggestions appear. */
.picker { position: relative; }
.picker__input { width: 100%; }
.picker__list {
    position: absolute; inset-inline: 0; top: calc(100% + 2px); z-index: 20;
    margin: 0; padding: 0; list-style: none;
    max-height: 15rem; overflow-y: auto;
    background: var(--surface); border: 1px solid var(--brand-300);
    border-radius: var(--radius-sm); box-shadow: var(--shadow);
}
.picker__list--empty { padding: var(--space-3) var(--space-4); font-size: .875rem; color: var(--text-muted); }
.picker__option {
    display: flex; justify-content: space-between; gap: var(--space-3);
    width: 100%; padding: var(--space-2) var(--space-3);
    font: inherit; font-size: .9375rem; text-align: start;
    background: none; border: 0; border-bottom: 1px solid var(--border);
    cursor: pointer; color: inherit;
}
.picker__option:last-child { border-bottom: 0; }
.picker__option:hover { background: var(--brand-50); }
.picker__meta { color: var(--text-muted); font-size: .8125rem; }

/* A school already chosen reads as settled rather than as an editable field, so a stray keystroke
   cannot silently clear it. */
.picker__chosen {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
    padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
    background: var(--brand-50); border: 1px solid var(--brand-300);
    border-radius: var(--radius-sm);
}

/* ---------- Basket summary ------------------------------------------------ */

.summary { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
.summary__line { display: flex; justify-content: space-between; gap: var(--space-4); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border); font-size: .9375rem; }
.summary__total { display: flex; justify-content: space-between; gap: var(--space-4); padding: var(--space-4); font-weight: 700; font-size: 1.0625rem; background: var(--ink-50); }

/* ---------- Empty / loading states ---------------------------------------- */

.empty { text-align: center; padding: var(--space-8) var(--space-4); color: var(--text-muted); border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface); }
.empty__title { color: var(--text); margin-bottom: var(--space-1); }
.loading { color: var(--text-muted); padding: var(--space-5) 0; }

/* ---------- Environment banner -------------------------------------------- */

.env-banner { padding: var(--space-2) var(--space-4); font-size: .875rem; font-weight: 600; text-align: center; }
.env-banner--sandbox { background: var(--warn-50); color: var(--warn-700); border-bottom: 1px solid var(--warn-200); }
.env-banner--production { background: var(--success-50); color: var(--success-700); border-bottom: 1px solid var(--success-200); }

/* ---------- Blazor framework UI ------------------------------------------- */

.blazor-error-boundary { background: var(--danger-700); padding: var(--space-4); color: var(--white); border-radius: var(--radius-sm); }
.blazor-error-boundary::after { content: "An error has occurred."; }

/* ---------- Responsive ---------------------------------------------------- */

@media (max-width: 40rem) {
    .page { padding: var(--space-4) var(--space-3) var(--space-6); }
    h1 { font-size: 1.5rem; }
    .site-header__inner { padding: var(--space-3); }
    .site-header__name span:last-child { display: none; }
    .kv { grid-template-columns: 1fr; gap: 0; }
    .kv dt { margin-top: var(--space-2); font-size: .8125rem; }
    .btn--responsive-block { width: 100%; }
}

/* ---------- Dark mode ------------------------------------------------------
   Follows the visitor's OS setting. Tokens only - no component rules repeated,
   so the two themes cannot drift apart. */

@media (prefers-color-scheme: dark) {
    :root {
        --page-bg: #12171a;
        --admin-shell-bg: #141a1d;
        --surface: #1a2125;
        --border: #2b3439;
        --text: #e6eae9;
        --text-muted: #a7b0b3;

        --ink-50: #1f272b;
        --ink-100: #232c31;
        --ink-200: #2b3439;
        --ink-400: #79868b;
        --ink-700: #cfd6d6;

        /* The navy family collapses into the ground on dark, so the ramp inverts - 700 becomes the
           lightest - and risefoundation.am's cyan takes the interactive role. --brand-300 is the one
           rung that does NOT change: it is a border and a tint, and the teal reads on both grounds.
             --brand-500 #4ec3d9 with --surface  8.5:1
             --brand-700 #a5e2ee on --surface   11.4:1 */
        --brand-50: #10262c;
        --brand-100: #16333b;
        --brand-200: #1f4a55;
        --brand-500: #4ec3d9;
        --brand-600: #7ad3e4;
        --brand-700: #a5e2ee;

        --accent-50:  #2a2010;
        --accent-200: #4a3c1c;
        /* Amber and its ink both hold. Lightening --accent-700 here is what made .offer__flag
           light-gold-on-gold at 1.2:1 - it is ink on a fill, and the fill does not change. */
        --accent-500: #f0a81e;
        --accent-700: #5a2c05;

        --success-50: #0f2a24;
        --success-200: #1a5145;
        --success-700: #5fd3b4;

        --warn-50: #2a2010;
        --warn-200: #55421a;
        --warn-700: #f0b866;

        --danger-50: #2a1416;
        --danger-200: #5d2429;
        --danger-500: #f4685f;
        --danger-700: #ff9c99;

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
        --shadow: 0 1px 3px rgba(0, 0, 0, .5), 0 4px 12px rgba(0, 0, 0, .35);
        --shadow-lg: 0 8px 30px rgba(0, 0, 0, .5);
    }

}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

/* ---- admin shell -------------------------------------------------------------------------------
   A persistent sidebar rather than a top bar: this is an application with a small fixed set of
   sections, and an operator working through orders should never go via a home page to reach receipts.
   Deliberately unlike the storefront - the panel refunds money and files permanent tax records. */

.admin-shell { display: flex; min-height: 100vh; align-items: stretch; }

.admin-sidebar {
  width: 15rem; flex: none; display: flex; flex-direction: column;
  background: var(--admin-shell-bg); color: #fff; position: sticky; top: 0; height: 100vh;
}

.admin-brand { display: block; padding: var(--space-4); color: #fff; text-decoration: none; border-bottom: 1px solid rgba(255,255,255,.12); }
.admin-brand__mark { display: block; font-weight: 800; letter-spacing: .04em; }
.admin-brand__sub { display: block; font-size: .75rem; opacity: .65; margin-top: .125rem; }

.admin-side-nav { flex: 1 1 auto; overflow-y: auto; padding: var(--space-3) 0; }
.admin-side-nav__group { margin-bottom: var(--space-4); }
.admin-side-nav__label {
  font-size: .6875rem; text-transform: uppercase; letter-spacing: .08em;
  opacity: .5; padding: 0 var(--space-4) var(--space-1);
}
.admin-side-nav__link {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  padding: .5rem var(--space-4); color: #fff; text-decoration: none; font-size: .9375rem;
  border-inline-start: 3px solid transparent;
}
.admin-side-nav__link:hover { background: rgba(255,255,255,.07); }
/* Blazor's NavLink adds .active to whichever section is open. */
.admin-side-nav__link.active { background: rgba(255,255,255,.12); border-inline-start-color: var(--brand-300); font-weight: 600; }

.admin-side-nav__badge {
  background: var(--danger-500); color: #fff; font-size: .75rem; font-weight: 700;
  min-width: 1.25rem; padding: 0 .375rem; border-radius: 999px; text-align: center;
}

.admin-sidebar__foot { flex: none; padding: var(--space-4); border-top: 1px solid rgba(255,255,255,.12); font-size: .8125rem; }
.admin-env { display: inline-block; padding: .125rem .5rem; border-radius: 999px; font-size: .6875rem; font-weight: 700; margin-bottom: var(--space-2); }
.admin-env--production { background: rgba(255,255,255,.9); color: #1c6b3a; }
.admin-env--sandbox { background: rgba(255,255,255,.9); color: #8a5a00; }
.admin-sidebar__user { opacity: .6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: var(--space-2); }
.admin-sidebar__links { display: flex; gap: var(--space-3); }
.admin-sidebar__links a { color: #fff; opacity: .8; text-decoration: underline; }
.admin-sidebar__links a:hover { opacity: 1; }

.admin-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.admin-content { flex: 1 1 auto; max-width: var(--content-width); width: 100%; margin: 0 auto; padding: var(--space-5) var(--space-4); }
.admin-foot { border-top: 1px solid var(--border); padding: var(--space-4); font-size: .8125rem; color: var(--text-muted); text-align: center; }

/* Denser tables: an operator scanning orders wants more rows visible than a buyer does. */
.admin-content .data th, .admin-content .data td { padding-block: .5rem; }

@media (max-width: 60rem) {
  .admin-shell { display: block; }
  .admin-sidebar { width: auto; height: auto; position: static; flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); }
  .admin-brand { border-bottom: 0; padding: 0; margin-inline-end: auto; }
  .admin-side-nav { flex: 1 1 100%; display: flex; gap: var(--space-2); overflow-x: auto; padding: var(--space-2) 0; }
  .admin-side-nav__group { display: flex; gap: var(--space-2); margin: 0; }
  .admin-side-nav__label { display: none; }
  .admin-side-nav__link { border-inline-start: 0; border-bottom: 2px solid transparent; white-space: nowrap; padding: .25rem .5rem; }
  .admin-side-nav__link.active { border-inline-start: 0; border-bottom-color: #fff; }
  .admin-sidebar__foot { flex: 1 1 100%; border-top: 0; padding: 0; display: flex; align-items: center; gap: var(--space-3); }
  .admin-env, .admin-sidebar__user { margin-bottom: 0; }
}

/* Stat tiles for the admin overview. A row of numbers, not cards in a two-column grid - the point is
   comparing them at a glance, and the attention state is what draws the eye when it matters. */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--space-3); }
.stat { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: var(--space-4); }
.stat__label { font-size: .8125rem; color: var(--text-muted); line-height: 1.3; }
.stat__value { font-size: 2rem; font-weight: 700; line-height: 1.1; margin-top: var(--space-2); font-variant-numeric: tabular-nums; }
.stat--attention { border-color: var(--danger-200); background: var(--danger-50); }
.stat--attention .stat__value { color: var(--danger-700); }

/* ---- Blazor framework UI -----------------------------------------------------------------------
   Moved here from MainLayout.razor.css, which was scoped CSS. Scoped styles only match elements
   carrying that component's generated attribute, so the display:none never applied to AdminLayout's
   own copy of #blazor-error-ui - leaving a permanently visible error bar on every admin page. A
   global rule matches both. Tokenised while it moved; the old lightyellow needed
   `color-scheme: light only` to survive dark mode, which the tokens make unnecessary. */

#blazor-error-ui {
  display: none;
  position: fixed; bottom: 0; left: 0; width: 100%; z-index: 1000; box-sizing: border-box;
  padding: .6rem 1.25rem .7rem;
  background: var(--warn-50); color: var(--warn-700);
  border-top: 1px solid var(--warn-200);
  box-shadow: 0 -1px 2px rgba(0,0,0,.2);
}
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: .75rem; top: .5rem; }

/* Numbers stay in the sans, and tabular, whatever the surrounding type. A serif figure in a total is
   decoration on a page where the number is the entire point, and proportional digits make a column of
   prices fail to line up. */
.stat__value, .offer__price, .summary__total, .stepper__value, .qty__value, .qty__total,
table.data td.num, table.data th.num, .num, code {
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
}
code { font-family: var(--font-mono); }

/* ---- programme accents -------------------------------------------------------------------------
   risefoundation.am gives each programme area its own accent, and a buyer handed over from bebras.am
   should still see something familiar. The accent slot is already the right shape for this: a fill
   plus its ink, never touching an interactive control.

   Fill and ink are always set together, because a dark accent needs light ink and a light one needs
   dark - the pair is the unit, and setting the fill alone is how a flag ends up unreadable.

   Where this may appear: .offer__flag and the handover banner. Where it may NOT: .btn--primary, any
   .steps state, any .badge variant. Those encode meaning or spend money, and the button that spends
   money must look the same however the buyer arrived - otherwise "which thing do I click" moves with
   the referrer, and AA has to be re-derived per source. */

[data-source="bebras"]   { --accent-500: #e08526; --accent-700: #3a1c02; }  /* ink on fill 5.6:1 */
[data-source="codzilla"] { --accent-500: #0f5e86; --accent-700: #eaf3f8; }  /* 6.3:1 */
[data-source="stories"]  { --accent-500: #8e4708; --accent-700: #fdf4e6; }  /* 6.3:1 */
/* A direct visit keeps the foundation's own amber from :root - 5.7:1. */

/* The handover banner used to reuse .env-banner--production, which in the admin panel means "real
   money mode". One class, two unrelated meanings, on the two surfaces where being misread matters
   most. */
.env-banner--handover {
  background: var(--brand-50);
  color: var(--brand-700);
  border-bottom: 1px solid var(--brand-200);
}

/* ---- language switcher ------------------------------------------------------------------------ */

/*  A globe button that opens a short menu, matching risefoundation.am.

    Built on <details>/<summary>, so it works with no JavaScript at all - which matters because Terms,
    Privacy, Error and NotFound render statically and never get a Blazor circuit. */

.lang-switch {
    position: relative;
    flex-shrink: 0;
}

.lang-switch__button {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.5rem 0.625rem;
    border-radius: var(--radius-sm, 6px);
    color: var(--ink-500);
    cursor: pointer;
    user-select: none;
    line-height: 1;
    list-style: none;          /* Firefox */
}

/*  The default disclosure triangle, removed in both spellings browsers use for it. */
.lang-switch__button::-webkit-details-marker { display: none; }
.lang-switch__button::marker { content: ""; }

.lang-switch__button:hover,
.lang-switch__button:focus-visible {
    color: var(--brand-700);
    background: var(--ink-50);
}

.lang-switch[open] > .lang-switch__button {
    color: var(--brand-700);
    background: var(--ink-50);
}

.lang-switch__globe {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
}

.lang-switch__current {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}

.lang-switch__menu {
    position: absolute;
    top: calc(100% + 0.375rem);
    right: 0;                  /* Right-aligned: the switcher sits at the end of the header, and a
                                  left-aligned menu would hang off a narrow screen. */
    z-index: 40;
    min-width: 11rem;
    padding: 0.25rem;
    background: var(--surface);
    border: 1px solid var(--ink-200);
    border-radius: var(--radius-sm, 6px);
    box-shadow: 0 8px 24px rgb(28 34 38 / 12%), 0 2px 6px rgb(28 34 38 / 8%);
}

.lang-switch__option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0.625rem;
    border-radius: var(--radius-sm, 6px);
    font-size: 0.875rem;
    color: var(--ink-700);
    text-decoration: none;
    white-space: nowrap;
}

.lang-switch__option:hover,
.lang-switch__option:focus-visible {
    color: var(--brand-700);
    background: var(--ink-50);
    text-decoration: none;
}

/*  Marked by weight and a tick as well as colour - never by colour alone. */
.lang-switch__option.is-current {
    color: var(--brand-700);
    font-weight: 600;
}

.lang-switch__tick {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
}

@media (max-width: 40rem) {
    .lang-switch__button {
        padding: 0.5rem;
    }

    .lang-switch__current {
        display: none;         /* The globe alone on a phone; the menu still names every language. */
    }
}

/* ---- product images ---------------------------------------------------------------------------- */

/*  A fixed aspect ratio, so a catalogue of covers photographed at different sizes still lines up and
    the page does not reflow as each one loads. object-fit: contain rather than cover: a book cover
    cropped to fill a box loses its title, which is the one thing on it that matters. */
.product__image {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: contain;
    background: var(--ink-50);
    border-radius: var(--radius-sm, 6px);
    margin-bottom: 0.75rem;
}

/*  What a product with no cover gets. A named tile rather than a broken-image icon or a gap, so a
    half-photographed catalogue looks unfinished rather than broken. */
.product__image--empty {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    text-align: center;
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--ink-400);
    border: 1px dashed var(--ink-200);
}
