/* ═══════════════════════════════════════════════════════════════════════════
   TOKENS — the vocabulary. Nothing here does work beyond :root.

   The design language is the International Typographic Style. One grotesque,
   set flush left. A grid nothing escapes. Rules instead of boxes, and boxes
   with square corners when a box is unavoidable. No gradient, no shadow, no
   translucency, no ornament: hierarchy is made out of size, weight, rule and
   position, and colour is spent only where it carries meaning.

   The institution issues certificates. Swiss is the language certificates,
   timetables and signage are already written in — objective, legible at a
   glance, and unbothered by fashion. That is the whole argument for it.

   One local rule outranks the style. This is a back-office tablet in a hotel
   in Copán and a phone on a ten-minute break: touch targets stay at 48px and
   body text never goes below 15px, whatever a Swiss grid would prefer.

   Every value below is read by shell.css and patterns.css. Change it here and
   both move together; that is the whole point of the file.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── the faces ────────────────────────────────────────────────────────────
   One family carries the interface. Archivo is a grotesque in the Akzidenz
   line — the closed apertures and the flat terminals are the point, and it
   holds a 15px body on a cheap tablet screen, which Helvetica does not.

   Self-hosted, and deliberately not from a font CDN: a hotel in Copán on a
   bad line should not be waiting on Google to find out whether it passed its
   inspection.

   Plex Mono is not a second voice. It is used only where a string is a code
   rather than a word — folios, credential seals, course numbers — because a
   code set in the text face invites people to read it as language. */

@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('../fonts/archivo-latin-400_700.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;
}
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('../fonts/archivo-latin-ext-400_700.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Plex Mono'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('../fonts/plexmono-latin-400.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2122, U+2212, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Plex Mono'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('../fonts/plexmono-latin-600.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2122, U+2212, U+FEFF, U+FFFD;
}

:root {
  /* ── grid ───────────────────────────────────────────────────────────────
     4px base. Every margin, padding and gap is a multiple, so things line up
     without anyone measuring. */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 20px;  --sp-6: 24px;  --sp-8: 32px;  --sp-10: 40px;
  --sp-12: 48px; --sp-16: 64px;

  /* ── radius ─────────────────────────────────────────────────────────────
     There is none. The tokens survive so that markup reaching for a corner
     gets a square instead of an undefined value — including the inline
     `var(--r-sm)` in forms.js. Do not give one of these a value: a single
     rounded control in a square interface reads as a mistake, not a choice. */
  --r-xs: 0; --r-sm: 0; --r-md: 0; --r-lg: 0; --r-xl: 0; --r-2xl: 0; --r-pill: 0;

  /* ── type ───────────────────────────────────────────────────────────────
     A closed scale. Nine sizes, no improvisation. 15px is the body floor and
     the small sizes are for labels and captions only — never for anything a
     learner has to read on a phone.

     `--font-display` is the same family, not a second one. It stays as a
     token because admin.js sets it inline, and because naming the display
     role separately is what lets it be changed in one place if it ever
     becomes a different cut of the same grotesque. */
  --font-ui:      'Archivo', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-display: 'Archivo', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono:    'Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --t-11: .6875rem;  /* caps label      */
  --t-12: .75rem;    /* caption, chip   */
  --t-13: .8125rem;  /* secondary       */
  --t-15: .9375rem;  /* body — floor    */
  --t-17: 1.0625rem; /* lead            */
  --t-20: 1.25rem;   /* pane title      */
  --t-24: 1.5rem;    /* section title   */
  --t-32: 2rem;      /* page title      */
  --t-44: 3rem;      /* figure          */

  --lh-tight: 1.06;
  --lh-snug: 1.3;
  --lh-body: 1.5;

  /* Swiss tracking: negative as size grows, positive only for caps. The caps
     tracking is wide on purpose — an uppercase label at 11px with normal
     tracking is a smudge. */
  --track-caps: .12em;
  --track-tight: -.008em;
  --track-tighter: -.024em;

  /* ── rule ───────────────────────────────────────────────────────────────
     The structural device. Three weights and nothing else: a hairline
     divides rows, a rule opens a section, and a heavy rule opens a page.
     Everything that would have been a border, a shadow or a card edge in
     another design is one of these. */
  --rule-hair: 1px;
  --rule: 2px;
  --rule-heavy: 3px;

  /* And the ink they are drawn in. A structural rule is punctuation, not
     content: a 3px bar of full ink over every section head, every figure and
     every table on a screen adds up to more black than the words do, and the
     eye starts reading the furniture. Two thirds of the ink is still
     unmistakably a rule and stops the page shouting its own scaffolding.
     Anything genuinely being said — a heading, a figure, a cell — keeps the
     full ink. */
  --rule-ink: color-mix(in oklab, var(--ink) 66%, var(--paper));

  /* ── motion ─────────────────────────────────────────────────────────────
     Almost none. Things appear, they do not arrive. One curve, two
     durations, and no decoration that moves on its own. */
  --ease: cubic-bezier(.2, 0, 0, 1);
  --fast: 90ms;
  --slow: 160ms;

  /* ── colour ─────────────────────────────────────────────────────────────
     Ink on paper, one blue, and one red kept in reserve.

     The blue is the institution's: it marks the seal, the screen you are
     standing on, the focus ring, and the current entry in the navigation.
     Blue is what a certificate, a timetable and a ministry sign are already
     printed in, and — unlike a red — it can sit on a screen all day without
     reading as a warning about something.

     Which is the point of separating the two. The red now does one job:
     something has gone wrong. It is the only colour in the system that
     means that, so it is never spent on identity, and it is deliberately
     not dimmed with the rest of the palette — an alarm that has been toned
     down to match the furniture is furniture.

     Black is still what a primary action is made of. */
  --brand:  #2b5f92;
  --red:    #c8342a;
  --green:  #256b4a;
  --amber:  #8a6210;
  --blue:   var(--brand);
  --graph:  #4d545c;   /* graphite — the fifth categorical slot */

  /* `--tint-a` is the accent as the rest of the system knows it. It is read
     from JS (viz.js) as well as from here. */
  --tint-a: var(--brand);

  /* ── the five accent slots ──────────────────────────────────────────────
     Course and credential pods carry `accent` as data, so these five names
     are a contract with the graph, not a palette decision made here. The
     values are a categorical set: five hues that separate on paper, on a
     projector and under deuteranopia, all of them at text contrast against
     the paper so a label may be set in one. */
  --clay: #a8443a;  --sage: var(--green);  --sea: var(--blue);
  --indigo: var(--graph);   /* `--amber` is already the slot's own name */

  --good: var(--green); --warn: var(--amber); --bad: var(--red);

  --rail: 15.5rem;
  --tab-h: 4.25rem;

  /* The measure. Prose past about 70 characters stops being scannable, and
     the reader's verso is the one place in the system with real prose. */
  --measure: 34rem;

  /* One margin for the whole reader. The bar, the page and the navigation
     all take their left edge from this, so a title, a heading and a button
     stand on the same line down the length of the document. Two gutters
     that differ by 8px is the difference between a grid and a coincidence. */
  --reader-gutter: clamp(var(--sp-5), 4vw, var(--sp-10));
}

/* ── light — the default ────────────────────────────────────────────────────
   Paper, and the ink is a very dark slate rather than black.

   Black on white is twenty to one. It is the right contrast for a printed
   certificate, which is looked at for ten seconds, and the wrong one for a
   console somebody is in front of for a shift: every rule, every heading and
   every hairline arrives at full strength and nothing is allowed to recede.
   Dropping the ink to a slate and warming the paper a quarter of a step
   costs nothing legible — everything here still clears 4.5:1, most of it
   clears 10:1 — and it lets the hierarchy be read as a hierarchy.

   `--chrome` is the one genuinely new idea in this block: the bars are not
   made of paper. A white bar over white content is not a bar, it is a strip
   of the page with a line under it, and at full white it is also the
   brightest thing on the screen — which is a poor use of the brightest thing
   on the screen for something nobody is reading. The chrome is a step down.
   The paper stays for the content, the reader and the credential, because
   those print. */

:root,
:root[data-theme="light"] {
  --paper:      #fcfcfb;
  --paper-2:    #f2f2f0;   /* sunken: a field, a track, a filled cell */
  --paper-3:    #e8e8e5;   /* pressed */
  --chrome:     #ededea;   /* the bars and the rail */
  --chrome-2:   #e2e2de;   /* and a control hovered inside one */

  --surface-1: var(--paper);
  --surface-2: var(--paper);
  --surface-3: var(--paper);
  --surface-sunken: var(--paper-2);
  --surface-solid:  var(--paper);

  --ink:   #25272a;
  --ink-2: #5e6167;
  --ink-3: #8b8e94;

  --hairline:   rgba(37, 39, 42, .15);
  --hairline-2: rgba(37, 39, 42, .08);

  color-scheme: light;
}

/* ── dark ───────────────────────────────────────────────────────────────────
   The same design inverted, not a second one. Ink and paper trade places, the
   blue lifts far enough off the ground to keep its contrast, and the chrome
   goes the other way from the light scheme: a bar in the dark is lighter than
   the page, not darker, because there is no darker left to go.

   The ink here comes off pure white for the same reason it comes off pure
   black in the light scheme, and it matters more: white text on a near-black
   ground haloes, and after twenty minutes of a shift that is what people mean
   when they say a screen is tiring. */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:   #16171a;
    --paper-2: #1f2125;
    --paper-3: #292c31;
    --chrome:  #1d2025;
    --chrome-2: #272b31;

    --surface-1: var(--paper);
    --surface-2: var(--paper);
    --surface-3: var(--paper);
    --surface-sunken: var(--paper-2);
    --surface-solid:  var(--paper);

    --ink:   #dcdee2;
    --ink-2: #a3a8b0;
    --ink-3: #787d85;

    --hairline:   rgba(220, 222, 226, .18);
    --hairline-2: rgba(220, 222, 226, .10);

    --brand: #7aabd8;
    --red:   #f4695b;
    --green: #62b489;
    --amber: #cba14a;
    --graph: #a3a8b0;
    --clay:  #d1786c;

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --paper:   #16171a;
  --paper-2: #1f2125;
  --paper-3: #292c31;
  --chrome:  #1d2025;
  --chrome-2: #272b31;
  --surface-1: var(--paper);
  --surface-2: var(--paper);
  --surface-3: var(--paper);
  --surface-sunken: var(--paper-2);
  --surface-solid:  var(--paper);
  --ink:   #dcdee2;
  --ink-2: #a3a8b0;
  --ink-3: #787d85;
  --hairline:   rgba(220, 222, 226, .18);
  --hairline-2: rgba(220, 222, 226, .10);
  --brand: #7aabd8;
  --red:   #f4695b;
  --green: #62b489;
  --amber: #cba14a;
  --graph: #a3a8b0;
  --clay:  #d1786c;
  color-scheme: dark;
}

/* ── chart colour ───────────────────────────────────────────────────────────
   Three categorical slots, assigned in fixed order and never cycled. Ink,
   blue, clay — in that order for a reason: `--viz-1` is also the
   single-series colour, used for every line and every bar that stands alone.
   A lone series is not a category and not an alarm; it is the data, and the
   data is ink.

   The alarm red is not among them. A dashboard drawn in the colour that
   means "something has gone wrong" is a dashboard reporting an emergency
   every day of the year — so the third slot is the muted clay, which reads
   as a category and not as a siren.

   The ground they land on is the paper itself — there is no translucent
   pane to composite against any more — so these are checked directly
   against `--paper` in both modes. All three clear 4.5:1 there, which means
   a series label may be set in its own colour, and all three separate by
   lightness as well as by hue, so they survive deuteranopia and protanopia.

   Do not nudge these by eye. */
:root {
  --viz-1: #25272a;
  --viz-2: #2b5f92;
  --viz-3: #a8443a;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --viz-1: #dcdee2;
    --viz-2: #7aabd8;
    --viz-3: #d1786c;
  }
}
:root[data-theme="dark"] {
  --viz-1: #dcdee2;
  --viz-2: #7aabd8;
  --viz-3: #d1786c;
}

/* ── the accent slots ─────────────────────────────────────────────────────
   `.a-*` sets `--accent` for a subtree. A course card, a credential and a
   reader all take their hue from the pod, not from where they are drawn. */
.a-sage  { --accent: var(--green); }
.a-amber { --accent: var(--amber); }
.a-clay  { --accent: var(--clay); }
.a-sea   { --accent: var(--blue); }
.a-ink   { --accent: var(--graph); }

/* ── high contrast ──────────────────────────────────────────────────────────
   There is no translucency to remove and no shadow to flatten, so the only
   thing left to give is weight: every hairline becomes ink. */
@media (prefers-contrast: more) {
  :root:root {
    --hairline:   color-mix(in oklab, var(--ink) 70%, transparent);
    --hairline-2: color-mix(in oklab, var(--ink) 45%, transparent);
    --ink-3: var(--ink-2);
  }
}
