/* Self-hosted Inter variable (Cyrillic + Latin subsets from Google Fonts v20) */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Brand design tokens — DESIGN_SYSTEM.md canonical palette */
:root {
  /* Neutrals */
  --n0: #F0EFEF;
  --n1: #D9D9D9;
  --n2: #9E9E9E;
  --n3: #686868;
  --n4: #4C4C4C;

  /* Chromatic accents */
  --orange: #F95E1B;
  --orange-hover: #E0530F;   /* orange −6% — button hover */
  --orange-active: #C74A0D;  /* orange −12% — button active / pressed */
  --coral: #FF4D4D;
  --green: #065339;

  /* tramplin.pro site green — the customer (dark) theme's brand accent.
     Mirrors the live site (bg #1a1a1a, soft-white text, green accent). Applied
     ONLY under body.dark-page (below); admin/teacher surfaces stay orange. */
  --green-web: #00663a;
  --green-web-hover: color-mix(in srgb, var(--green-web) 92%, #000);   /* ≈ −6% */
  --green-web-active: color-mix(in srgb, var(--green-web) 84%, #000);  /* ≈ −12% */

  /* Semantic */
  --bg: var(--n0);
  --text: var(--n4);
  --text-secondary: var(--n3);
  --text-muted: var(--n2);
  --surface: #FFFFFF;
  --border: var(--n1);
  --primary: var(--orange);
  --danger: var(--coral);
  --success: var(--green);

  /* Status fills */
  --status-success-bg: #e3faf0;
  --status-success-border: #a2e5c8;
  --status-success-text: #167a4e;
  --status-neutral-bg: #e2e2e5;
  --status-neutral-border: #c3c3c8;
  --status-neutral-text: #555;
  --status-alert-bg: #ffe3e3;
  --status-alert-border: var(--coral);
  --status-alert-text: var(--coral);

  /* Landing dark palette (DESIGN_SYSTEM §1 dark/noise) */
  --dark-bg: #2A2A2A;
  --dark-text: #D9D9D9;
  --dark-text-muted: #bbb;
  --dark-border: #555;
  --dark-border-hover: #999;

  /* Geometry */
  --radius-pill: 999px;
  --radius-card: 18px;
  --radius-popover: 12px;
  --radius-sm: 8px;
  --radius-xs: 4px;
  --radius-2xs: 2px;     /* progress bars / fine corners */
  --radius-full: 50%;    /* circles — avatars, icon buttons, dots */

  /* Minimum interactive tap target — WCAG 2.5.5 / DESIGN_SYSTEM §0a bullet 5.
     Not on the --space ramp: it is an accessibility floor, not a spacing step. */
  --tap-min: 44px;

  /* SVG icon glyph box — the drawn size of a repeated inline icon (the <svg>/__ic
     element), NOT its tap-target button (that is --tap-min). Two steps because the
     glyphs cluster at two sizes; one-off glyph sizes (15/26px) stay raw per §6f. */
  --icon-sm: 20px;   /* player/prev-next + chat send */
  --icon-md: 22px;   /* bottom-nav · notif-bell · carousel chevrons */

  /* Initials avatar — the identity circle (admin shell account chip + roster
     list). One size, purpose-named: no fabricated scale. The filter-row
     add-button is 28px only by coincidence (a control box, not an avatar) and
     stays raw in the §6f residual so it never moves with avatars. */
  --avatar-size: 28px;
  --avatar-lg: 48px;   /* the personnel details-page header identity avatar (D59) */

  /* Layout measure caps — a recurring content-width ceiling. Only the values used
     on 2+ live selectors earn a token; one-off caps stay raw (§6f residual). */
  --measure-content: 480px;   /* single-column page/funnel content measure */
  --measure-workspace: 1080px; /* details/settings workspace body (DESIGN_PATTERNS §2b) */

  /* Fixed sticky rail beside a workspace's flexible column (DESIGN_PATTERNS §2b). */
  --rail-width: 300px;

  /* Spacing scale — use these, never ad-hoc px */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  /* Elevation */
  --shadow-fab: 0 12px 25px var(--orange);
  --shadow-modal: 0 18px 40px rgba(0, 0, 0, 0.18);
  --shadow-popover: 0 12px 30px rgba(0, 0, 0, 0.18);
  /* Gentle lift for a hovered card: tight blur so it can't bleed onto neighbours,
     warm-neutral (not pure black), layered for softness. Pairs with a -2px rise. */
  --shadow-card-hover: 0 4px 14px rgba(20, 20, 20, 0.16), 0 1px 4px rgba(20, 20, 20, 0.10);

  /* Typography — rem ramp from the brand scale */
  --font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --fs-xs: 0.75rem;   /* 12px */
  --fs-sm: 0.875rem;  /* 14px */
  --fs-base: 1rem;    /* 16px */
  --fs-md: 1.125rem;  /* 18px */
  --fs-lg: 1.375rem;  /* 22px */
  --fs-xl: 2rem;      /* 32px */
  --fs-2xl: 4rem;     /* 64px */
  --fw-light: 300;
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* Letter-spacing (tracking) — the fifth type axis, previously untokenised.
     Negative tightens large/brand headings; positive spaces small caps and the
     monospace OTP/code affordances. em (scales with the element's font-size). */
  --tracking-tight: -0.02em;   /* brand/display heading */
  --tracking-wide: 0.04em;     /* uppercase small-caps labels */
  --tracking-wider: 0.15em;    /* dev/code display */
  --tracking-widest: 0.2em;    /* OTP / code glyphs */

  /* ================================================================
     Semantic roles (Material-mapped) — added D31, unified-DS pass.
     Brand identity is unchanged: orange primary, green secondary/
     success, coral alert. These are NAMED roles so every screen
     references intent, not raw hex. All derived shades use color-mix
     over the brand tokens (AGENTS §6: no raw rgba in component CSS —
     new shades live here, in the token layer).
     ================================================================ */
  --primary-hover: var(--orange-hover);
  --primary-active: var(--orange-active);
  --primary-container: color-mix(in srgb, var(--orange) 12%, var(--surface));
  --on-primary: #FFFFFF;          /* text/icon on a filled primary button */
  --secondary: var(--green);
  --secondary-container: color-mix(in srgb, var(--green) 12%, var(--surface));
  --accent: var(--orange);
  --accent-soft: color-mix(in srgb, var(--orange) 12%, transparent);  /* orange tint fill */
  --on-accent: #FFFFFF;           /* text/icon on a filled accent / chip / coral modal */
  --white: #FFFFFF;               /* a true-white surface (e.g. button on coral) */
  --info: #4A90D9;
  --warning: #E0A030;
  --surface-elevated: var(--surface);   /* light: elevation comes from shadow, not fill */
  --surface-muted: var(--n0);           /* warm-grey fills: inputs, tags, hover */
  --surface-inverse: var(--dark-bg);
  --divider: var(--border);             /* alias — hairline rules between rows/sections */
  --surface-hover: var(--n0);           /* row / card hover (light theme) */
  --scrim: rgba(0, 0, 0, 0.5);          /* modal / overlay backdrop */
  --scrim-soft: rgba(0, 0, 0, 0.3);     /* lighter backdrop (admin log modal) */
  --overlay-soft: rgba(0, 0, 0, 0.15);  /* faint inset wash */

  /* Info status (light fills + a lighter text shade for dark surfaces) */
  --info-bg: #e8f0fe;
  --info-border: #b3d1f7;
  --info-text: #1a4f8b;
  --info-text-dark: #93c5fd;

  /* Warning status (amber family) */
  --warning-bg: #fff4e6;        /* peach — time-off entries */
  --warning-bg-soft: #fffbe6;   /* yellow — dev banners */
  --warning-border: #f0d060;
  --warning-text: #b35c00;

  /* ---- Dark (customer) surface hierarchy — names the translucent
     white-on-dark fills the funnel/portal repeat everywhere ---- */
  --dark-surface: rgba(255, 255, 255, 0.06);   /* pills, chips, fields, day strip */
  --dark-surface-strong: rgba(255, 255, 255, 0.10);
  --dark-card: rgba(255, 255, 255, 0.05);      /* elevated card on dark */
  --dark-inset: rgba(255, 255, 255, 0.04);     /* recessed (photo frame) */
  --dark-surface-hover: rgba(255, 255, 255, 0.08);
  --dark-text-faint: rgba(255, 255, 255, 0.12);  /* ghost wordmark */
  --dark-overlay: rgba(0, 0, 0, 0.18);           /* inset panel (audio player) */
  --dark-nav-bg: rgba(42, 42, 42, 0.58);         /* floating-nav frosted glass (= --dark-bg @ 58%) */
  /* Translucent decorations over a filled accent (the coral login modal) */
  --on-accent-muted: rgba(255, 255, 255, 0.6);
  --on-accent-faint: rgba(255, 255, 255, 0.45);
  --on-accent-border: rgba(255, 255, 255, 0.5);
  --on-accent-fill: rgba(255, 255, 255, 0.15);

  /* ---- Spacing — the 4px-grid ramp (use these, never ad-hoc px/rem) ----
     Primary ramp: --space-1..8 = 4 8 12 16 24 32 48 64.
     Half-steps (Tailwind-style) cover the in-between values the UI genuinely
     uses (pill/chip padding, tight gaps) so EVERY spacing value is a token. */
  --space-7: 48px;
  --space-8: 64px;
  --space-1-5: 6px;
  --space-2-5: 10px;
  --space-3-5: 14px;
  --space-4-5: 20px;

  /* ---- Border widths ---- */
  --stroke: 1.5px;     /* interactive control borders (inputs, pills, chips) */
  --hairline: 1px;     /* dividers, table rules, subtle borders */

  /* ---- Motion — durations (easing keyword stays per-use; default ease) ----
     Animate transform/opacity only (AGENTS §6). M3-aligned short durations. */
  --dur-stagger: 0.03s;   /* per-item delay step for sequenced list fade-in */
  --dur-fast: 0.1s;       /* tactile :active press */
  --dur-base: 0.15s;      /* default hover/colour transition */
  --dur-moderate: 0.2s;   /* larger state changes */
  --dur-slow: 0.25s;      /* enter/slide transitions */
  --dur-slower: 0.35s;    /* screen-level motion (view transitions) */
  --dur-slowest: 0.5s;    /* graceful large-travel slide (carousel card) */
  --dur-pulse: 2.4s;      /* gentle looping opacity pulse (live status dot) */
  --ease-standard: ease-out;
  /* Fluid-motion curves (2026-07-17). --ease-decel: true decelerate — fast
     start, long soft landing (same curve the shop coverflow proved). --ease-spring:
     gentle single-overshoot "spring" for release/settle of momentum-flavoured
     motion (press release, carousel card) — transform-only, never on colour. */
  --ease-decel: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);

  /* ---- Z-index layers — the ONLY place stacking order is defined.
     Reach for a layer token, never a raw z-index. (Landing's internal
     decorative 1–4 ordering is a page-local stacking context — see
     DESIGN_SYSTEM §6f.) ---- */
  --z-raised: 5;            /* floating in-content (carousel nav pill) */
  --z-nav: 20;             /* fixed page nav */
  --z-sticky-cell: 40;     /* sticky table body cell */
  --z-sticky: 80;          /* sticky table header row */
  --z-sticky-header: 100;  /* sticky app / section header bar */
  --z-overlay: 100;        /* landing login backdrop (page-local) */
  --z-sticky-col: 120;     /* sticky corner cell, above the header row */
  --z-modal: 1000;         /* dialog / overlay backdrop */
  --z-popover: 1200;       /* popover above a dialog */
  --z-grain: 9999;         /* fixed grain texture, always topmost */

  /* ---- Elevation roles — M3 levels 0–5 (dp 0/1/3/6/8/12), brand-toned
     lighter than M3 baseline to preserve the house "mostly flat" feel.
     Shadow stays reserved (cards mostly use borders); use level3+ for
     menus/popovers/dialogs. ---- */
  --elevation-0: none;
  --elevation-1: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.08);   /* 1dp */
  --elevation-2: 0 1px 2px rgba(0, 0, 0, 0.10), 0 2px 6px 2px rgba(0, 0, 0, 0.08);  /* 3dp */
  --elevation-3: 0 1px 3px rgba(0, 0, 0, 0.12), 0 4px 8px 3px rgba(0, 0, 0, 0.10);  /* 6dp */
  --elevation-4: 0 2px 3px rgba(0, 0, 0, 0.12), 0 6px 10px 4px rgba(0, 0, 0, 0.10); /* 8dp */
  --elevation-5: 0 4px 4px rgba(0, 0, 0, 0.14), 0 8px 12px 6px rgba(0, 0, 0, 0.12); /* 12dp */
  --elevation-modal: var(--shadow-modal);     /* reserved (DESIGN_SYSTEM §1) */
  --elevation-popover: var(--shadow-popover);

  /* ================================================================
     Material 3 system layer (D31b) — fetched from the material-web
     source and ADAPTED to the brand. Faithful where it fits; we keep
     orange/green/coral. Intentionally OMITTED (would read as default
     Material on a brand with no such hue): `tertiary*` and the
     cross-theme `*-fixed` roles. M3 is the grammar, not the skin.
     ================================================================ */
  /* Tonal pairs (on-* = accessible text/icon on the matching container) */
  --on-primary-container: var(--orange-active);            /* deep orange on soft-orange */
  --on-secondary-container: var(--green);
  --error: var(--coral);
  --on-error: var(--white);
  --error-container: var(--status-alert-bg);
  --on-error-container: var(--status-alert-text);

  /* Surface roles + M3 tonal container ramp (light theme) */
  --on-surface: var(--text);
  --surface-variant: var(--surface-muted);                 /* tinted surface */
  --on-surface-variant: var(--text-secondary);             /* muted text/icons */
  --surface-tint: var(--primary);                          /* tonal-elevation tint */
  --surface-container-lowest: var(--white);
  --surface-container-low: var(--surface);
  --surface-container: var(--n0);
  --surface-container-high: color-mix(in srgb, var(--n0) 55%, var(--n1));
  --surface-container-highest: var(--n1);

  /* Outline: interactive border vs. decorative divider (M3 split) */
  --outline: var(--n2);                                    /* ≥3:1 interactive edges */
  --outline-variant: var(--n1);                            /* hairline dividers (= --border) */

  /* Inverse + scrim/shadow */
  --inverse-surface: var(--dark-bg);
  --inverse-on-surface: var(--dark-text);
  --inverse-primary: color-mix(in srgb, var(--orange) 72%, white);
  --shadow: rgba(0, 0, 0, 1);                              /* umbra colour (used via alpha) */

  /* State-layer opacities — verbatim from material-web md-sys-state.
     Apply as: color-mix(in srgb, currentColor calc(var(--state-*)*100%), transparent),
     or over a role colour for hover/press washes. */
  --state-hover: 0.08;
  --state-focus: 0.12;
  --state-pressed: 0.12;
  --state-dragged: 0.16;
  --state-disabled-content: 0.38;
  --state-disabled-container: 0.12;
}

/* Dark (customer) theme swaps theme-scoped role variables so shared
   components (e.g. .card--link, .status-chip) adapt without per-screen CSS. */
body.dark-page {
  /* ---- Unite with tramplin.pro: darker bg, brighter text, green accent ----
     The site is #1a1a1a bg / soft-white text / #00663a green accent. Admin/teacher
     (light, no .dark-page) keep orange untouched.
     NOTE on CSS semantics: the accent ROLE tokens (--primary, --accent, …) are
     declared at :root against --orange, so their var(--orange) is already
     substituted (to orange) and merely inherited here — overriding --orange alone
     does NOT retro-change them. So we re-declare the roles below. We also override
     the --orange* primitives for the two consumers that reference them directly on
     dark pages (the focus ring in app.css, the chat-send hover in chat.css). */
  --dark-bg: #1a1a1a;                      /* was #2A2A2A */
  --dark-text: #f5f2f2;                     /* was #D9D9D9 — site soft-white */
  --dark-nav-bg: rgba(26, 26, 26, 0.58);   /* floating-nav glass = site bg @ 58% */

  /* Accent roles → site green (customer theme only) */
  --primary: var(--green-web);
  --primary-hover: var(--green-web-hover);
  --primary-active: var(--green-web-active);
  --primary-container: color-mix(in srgb, var(--green-web) 12%, var(--surface));
  --accent: var(--green-web);
  --accent-soft: color-mix(in srgb, var(--green-web) 12%, transparent);
  --surface-tint: var(--green-web);
  /* Green for TEXT on the dark bg. --green-web itself is a FILL colour: at
     2.45:1 on --dark-bg it fails WCAG AA for text, so a green link painted with
     it is brand-correct and unreadable. Lightened toward --dark-text to 5.59:1
     (measured), which clears AA for body text and still reads unmistakably green. */
  --accent-on-dark: color-mix(in srgb, var(--green-web) 60%, var(--dark-text));
  --on-primary-container: var(--green-web-active);
  --shadow-fab: 0 12px 25px var(--green-web);
  /* Primitives — for the direct-reference consumers (focus ring, chat hover) */
  --orange: var(--green-web);
  --orange-hover: var(--green-web-hover);
  --orange-active: var(--green-web-active);

  --surface-hover: var(--dark-surface-hover);
  --surface-elevated: var(--dark-card);
  /* M3 surface roles, dark (customer) theme */
  --on-surface: var(--dark-text);
  --on-surface-variant: var(--dark-text-muted);
  --surface-variant: var(--dark-surface);
  --outline: var(--dark-border-hover);
  --outline-variant: var(--dark-border);
  --surface-container-lowest: var(--dark-bg);
  --surface-container-low: var(--dark-inset);
  --surface-container: var(--dark-card);
  --surface-container-high: var(--dark-surface);
  --surface-container-highest: var(--dark-surface-strong);
}

/* ================================================================
   v2 shop (ADR D54) — coverflow geometry + shop-only shades.
   Shop-scoped raw values live HERE (tokens.css is the one file
   allowed raw values, DESIGN_SYSTEM §0c); shop.css consumes tokens
   only. Shades derive from the customer green family; the bright
   #0E8A52 / #00804A / #7FD7AC steps come from the blessed mockup
   (docs/mockups/shop-v2.html — the UX contract). Scoped under
   body.dark-page: the shop always renders dark (ADR §3).
   ================================================================ */
body.dark-page {
  /* Shades */
  --shop-green-hi: #0E8A52;        /* bright accent (plan select, glow core) */
  --shop-green-bright: #7FD7AC;    /* banner «Оплатить →» text */
  --shop-buy: #00804A;             /* solid-fill buy button (no translucency, ADR §2.3) */
  --shop-buy-active: var(--shop-green-hi);
  --shop-cover-bg: #161815;        /* cover-face base under the glow gradients */
  --shop-ticket-bg: #171916;       /* ticket face */
  --shop-surface: #1C1E1B;         /* neutral shop card (how-it-works steps) */
  --shop-stroke: color-mix(in srgb, var(--dark-text) 14%, transparent);
  --shop-text-muted: color-mix(in srgb, var(--dark-text) 62%, transparent);
  --shop-text-faint: color-mix(in srgb, var(--dark-text) 38%, transparent);
  --shop-num-stroke: color-mix(in srgb, var(--dark-text) 30%, transparent);
  --shop-green-soft: color-mix(in srgb, var(--shop-green-hi) 16%, transparent);
  --shop-banner-border: color-mix(in srgb, var(--shop-green-hi) 45%, transparent);

  /* Coverflow geometry (ADR §3: card 250×380, stage 470, perspective 1300) */
  --shop-card-w: 265px;   /* +6% (Mark, 2026-07-15: room to breathe) */
  --shop-card-h: 403px;   /* +6% */
  --shop-stage-h: 498px;  /* tracks the +6% card */
  --shop-persp: 1300px;

  /* Shop display type — sizes with no --fs equivalent (giant outlined lesson
     count, ~90px discipline watermark per ADR §2.3, tier title) */
  --shop-fs-display: 118px;
  --shop-fs-watermark: 90px;
  --shop-tracking-display: -0.05em;    /* tighter than --tracking-tight: display-size only */
  --shop-tracking-watermark: -0.04em;
  --shop-fs-tier: 27px;
  --shop-watermark-bottom: 159px;  /* lower third, above the tier title (tracks +6%) */

  /* Motion (ADR §3: ~.55s coverflow settle; .6s ticket flip) */
  --shop-dur-flow: 0.55s;
  --shop-dur-flip: 0.6s;
}
