/* EduFlow — "paper" art direction, shared across the public web surfaces.
   ═══════════════════════════════════════════════════════════════════════════
   Extracted 2026-09-09 (BL-194) from web/psychometric.html, which is the
   REFERENCE and is NOT edited: every value below is copied from that page's
   :root verbatim so the two can be diffed literally. The trigger was an outside
   reader calling the previous landing page "ממש AI" (LESSON_LOG 2026-09-03,
   class:landing-ai-look — the verdict there is explicit that the "AI dark-mode"
   cluster is a rejection on EVERY web surface, not only that one page).

   WHO LOADS THIS
     web/watch.html                      — the zero-install reel feed (chrome only;
                                           the player itself stays black, see below)
     src/api/public_preview.py::_render_html — GET /c/{course_id}
     scripts/build_learn_pages.py CSS    — web/learn/*.html (45 pages + 2 hubs)

   RELATIONSHIP TO tokens.css
     tokens.css stays the brand SSOT (--accent, --grad, --font-brand/Outfit for
     the wordmark) and is still linked first by the pages that linked it. This
     file is the art-direction layer on top: it renames nothing in tokens.css and
     overrides nothing there except by defining its own --paper/--ink namespace.
     Load order is tokens.css → paper.css.

   THE TWO RULES THAT ARE EASY TO BREAK
     1. --accent has exactly TWO jobs: links, and the primary button. It is not a
        background wash, not a gradient, not a glow. A third use erodes both.
     2. No gradients as decoration. The brand --grad from tokens.css survives ONLY
        as a fill behind white in the logo mark; a gradient button or a gradient
        heading is the generated-page tell this direction exists to remove.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Type pairing (2026-09-03). Display: Secular One — a heavy Hebrew geometric with
   an unmistakably Israeli voice, whose even stroke holds at 32px on a 390px phone.
   Body: Rubik, which tokens.css already names as the site's Hebrew text face.
   NOT Frank Ruhl Libre — the serif that made these pages read as a template.
   @import rather than a per-page <link> so that linking THIS file is sufficient;
   tokens.css sets the same precedent for Outfit. `display=swap` means text paints
   in the fallback stack immediately, so a blocked font host costs nothing but the
   face. Same host as tokens.css → no new CDN dependency. */
@import url('https://fonts.googleapis.com/css2?family=Secular+One&family=Rubik:wght@400;500;600;700&display=swap');

:root {
  /* ── Ground ───────────────────────────────────────────────────────────────
     Warm, not violet-tinted: a violet-grey band is the thing that makes a light
     page still read as "generated". --paper is tokens.css --bg unchanged. */
  --paper:       #FFFDFB;
  --paper-2:     #F7F4EE;

  /* ── Ink — tokens --text / --text-muted / --text-dim ──────────────────────
     --ink-3 is the tokens value already measured at 5.23:1 on --paper (AA). */
  --ink:         #1A1430;
  --ink-2:       #4A4360;
  --ink-3:       #6E6880;

  /* ── Rules. Warm neutrals so hairlines read as printed rules. ───────────
     MEASURED on --paper (BL-236, 2026-09-09): --rule 1.29:1, --rule-2 1.65:1.
     Both are DECORATIVE by construction — a notebook rule, a table hairline, a
     card edge whose card already carries text at 5.23:1. They are fine there
     and must stay light, because a printed rule that reads as a drawn border
     is the thing this direction is made of.
     What they are NOT allowed to be is the ONLY boundary of a control. WCAG
     1.4.11 asks 3:1 of the visual information needed to identify a component,
     and a ghost button on paper has nothing else: no fill, no shadow, just its
     border. That is what --rule-strong is for — 3.32:1, same warm family (h≈40,
     low sat), so a ghost button reads as drawn in the same ink as the rules
     rather than as a foreign grey. Decorative → --rule / --rule-2. Sole
     boundary of something you can click or type into → --rule-strong. */
  --rule:        #E6E0D6;
  --rule-2:      #CFC7B9;
  --rule-strong: #948B7A;

  /* ── THE accent — tokens --accent, measured 5.62:1 on --paper ─────────── */
  --accent:      #7C3AED;
  --accent-deep: #6D28D9;
  --accent-tint: #F4EFFE;
  --accent-edge: #DCCCFB;

  /* ── Signal — deadlines and warnings, nothing else. ───────────────────────
     Two values because one cannot do both jobs: --signal is TEXT (5.90:1 on
     paper) and --signal-fill is the 3-4px rule and dot, where contrast does not
     apply and the colour has to actually read yellow. */
  --signal:      #A14A08;
  --signal-fill: #F2B33A;
  --signal-tint: #FDF4E4;
  --signal-edge: #EFDFC2;

  /* ── Correct / confirmed. Same construction as --signal: text vs fill. ─── */
  --ok:          #08725A;
  --ok-tint:     #E8F5F1;
  --ok-edge:     #BFE0D6;

  /* ── Type stacks ─────────────────────────────────────────────────────────
     The full system fallback is load-bearing, not decoration: web/learn/* used
     to name "Frank Ruhl Libre" with no font link at all, so on every phone
     without it installed the pages silently rendered in a system serif. */
  --font-display: "Secular One", "Rubik", -apple-system, "Segoe UI", system-ui, sans-serif;
  --font-text:    "Rubik", -apple-system, "Segoe UI", system-ui, sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* ── Squared-notebook paper (Owner direction 2026-09-03: «מחברת משבצות —
     מוסיף לאווירה הלימודית»). A fine pale-blue grid like an Israeli school
     notebook, faint enough that body text keeps its measured contrast. ───── */
  --grid:      rgba(88, 118, 176, .15);
  --grid-size: 26px;

  --ease:      cubic-bezier(.22, .61, .36, 1);
  --radius:    12px;
  --radius-lg: 14px;
}

/* ── The notebook ground ────────────────────────────────────────────────────
   A CLASS, not a bare `body` rule: web/watch.html is a full-bleed video feed
   whose slides must stay black, and a global body background would be painted
   under a 9:16 letterboxed reel. Cards, navs and tables stay opaque --paper so
   they read as sheets laid on the notebook. */
.paper-ground {
  background-color: var(--paper);
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: var(--grid-size) var(--grid-size);
  background-position: center top;
}

/* ── Display face ───────────────────────────────────────────────────────────
   Single weight by design — Secular One is already heavy, so there is no
   fake-bold risk. Tracking is 0: negative letter-spacing on Hebrew closes the
   gaps that separate ק/ר and ב/כ, a legibility cost paid for a Latin habit. */
.paper-display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: 0;
}

/* ── RTL number runs ────────────────────────────────────────────────────────
   MEASURED, twice (LESSON_LOG 2026-08-21 + 2026-09-01, class:
   rtl-number-run-inversion): `unicode-bidi:isolate` ALONE IS NOT ENOUGH — the
   Council reproduced "38 → 40" rendering as "40 → 38", i.e. growth read as a
   drop. What actually fixes it is <bdi> (dir=auto is what resolves the run as
   LTR), or U+2066/U+2069 isolates inside the text itself. This rule dresses
   <bdi> and the .num helper; it does not replace them. NEVER verify Hebrew
   bidi by eye — measure glyph order in the browser. */
bdi,
.num {
  direction: ltr;
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
}

/* ── Primitives ─────────────────────────────────────────────────────────── */

/* Eyebrow: a small caps label with a printed rule before it. */
.paper-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.paper-eyebrow::before {
  content: "";
  width: 24px;
  height: 2px;
  background: var(--ink);
}

/* Buttons. Square-ish (10px), never pill: the pill + gradient pair is the
   generated-page tell. Min 46px so the tap target clears WCAG 2.5.8. */
.paper-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 46px;
  padding: 0 22px;
  border: 1px solid transparent;
  border-radius: 10px;
  font-family: inherit;
  font-weight: 600;
  font-size: 15px;
  line-height: 1.1;
  cursor: pointer;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
.paper-btn--primary { background: var(--accent); color: #fff; }
.paper-btn--primary:hover { background: var(--accent-deep); }
/* --rule-strong, not --rule-2: transparent fill means the border IS the button,
   so it is a 1.4.11 boundary and has to clear 3:1 (BL-236). */
.paper-btn--ghost {
  background: transparent;
  border-color: var(--rule-strong);
  color: var(--ink);
}
.paper-btn--ghost:hover { border-color: var(--ink); background: var(--paper-2); }

/* Focus ring — one definition for every surface. */
.paper-btn:focus-visible,
a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Masthead. Opaque --paper, not a translucent blur: a backdrop-filter over the
   notebook grid smears the rules into a grey haze. */
.paper-nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
.paper-brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-weight: 600;
  font-size: 16px;
  color: var(--ink);
  min-width: 0;
}
/* The logo mark is the one place the brand violet appears as a fill. */
.paper-brand-icon {
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: var(--accent);
  display: grid;
  place-items: center;
  color: #fff;
  flex-shrink: 0;
}
.paper-brand .name {
  font-family: var(--font-brand, "Outfit", system-ui, sans-serif);
  letter-spacing: .2px;
  font-weight: 700;
}
.paper-brand .sep  { color: var(--rule-2); font-weight: 400; }
.paper-brand .vert { color: var(--ink-3); font-weight: 500; font-size: 14px; }

/* Colophon footer. Ink, deliberately: a light page needs a terminus, and the
   legal disclaimer that has to be on every page is better set as a colophon
   than as another grey paragraph on paper. */
.paper-footer {
  background: var(--ink);
  color: #B9B2CE;
  padding: 40px 0 36px;
}
.paper-footer a { color: #DAD5E8; }
.paper-footer a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.paper-foot-links {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  font-size: 14px;
}
.paper-foot-links a { display: inline-block; padding: 11px 0; }
.paper-disclaimer {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, .14);
  font-size: 13px;
  color: #9E97B4;
  line-height: 1.7;
  max-width: 900px;
}

/* ── Motion ─────────────────────────────────────────────────────────────────
   Nothing here animates by default. Pages that add an entrance must use a CSS
   animation with `both` fill rather than JS-added classes: a background tab
   throttles rAF, so a JS-gated reveal can paint an empty page to a visitor
   arriving from an in-app browser. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .paper-btn { transition: none; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
