/* Octralis AI Workforce — Phase 0 design tokens
   Derived from the design review, 26 August 2026.
   Contrast ratios are measured against --ground (#E8ECF0), which is the colour
   every page shell renders. Values that carry text or state clear WCAG 2.2 AA;
   values that only draw structure do not need to and are marked.            */

:root {
  /* ---- Neutrals -------------------------------------------------------- */
  --ground:            #E8ECF0;  /* page shell. 1.20:1 against surface, so a card
                                    has an edge even with its border removed    */
  --surface:           #FFFFFF;  /* cards, rows, anything holding content       */
  --surface-sunken:    #F1F3F5;  /* selected row, popover, worked example       */

  --text:              #131920;  /* 14.9:1 — primary                            */
  --text-secondary:    #4B5663;  /*  6.3:1 — supporting prose                   */
  --text-label:        #616974;  /*  4.8:1 — smallest label size, 10.5px caps   */

  --line:              #D5DAE0;  /* card edge. Structure only, never state      */
  --quote:             #4B5663;  /* 3px bar on quoted content: a prompt example,
                                    a learner's own words, a finding. Deliberately
                                    NOT --unrecorded: that grey carries three
                                    semantic meanings, and a quote is neither an
                                    absence nor progress. It takes the secondary
                                    text colour because a quote is somebody's
                                    words. Structure only, no ratio requirement.  */
  --line-hairline:     #EDEFF2;  /* row rule. Structure only, never state       */

  /* ---- Semantic: fixed, never tenant-coloured -------------------------- *
   * Each mark means exactly one thing at every scale. Never colour alone:  *
   * fill, texture, dash pattern or glyph carries the meaning first.        */
  --evidence:          #253039;  /* 11.3:1 — a level demonstrated. Solid ink.
                                    NEVER used for progress or completion      */
  --gap-line:          #8A5A00;  /*  5.0:1 — below requirement                  */
  --gap-fill:          #F3E2C7;  /* paired with --gap-line at a 45° hatch,
                                    one shared angle everywhere it appears      */
  --unrecorded:        #7C8590;  /*  3.1:1 — nothing recorded here. Dotted.
                                    Covers "not yet assessed" and "requirement
                                    not set": both are absence, not zero        */
  --above:             #7C8590;  /*  3.1:1 — above requirement. Dashed, unfilled */
  --progress:          #7C8590;  /*  3.1:1 — a step finished, a role set up.
                                    Deliberately not --evidence: progress is
                                    not evidence                                */
  --warning-line:      #A33A1C;  /*  5.5:1 — validation. Solid, never hatched,
                                    so it can never read as a competency gap    */
  --warning-fill:      #F9E6E0;
  --met:               #1F5136;  /*  7.8:1 — at requirement. UNDER REVIEW: the
                                    recommendation is to remove green entirely
                                    and use ink plus a check, because a green
                                    tenant primary collides with it             */

  /* ---- Interface status (brief §8.1) ----------------------------------- *
   * Four statuses, each carrying a colour, an icon AND a text label. Never  *
   * one of the three alone: colour fails in a board pack, an icon fails in  *
   * a text browser, a label alone fails at a glance. Icons are four         *
   * different SHAPES, not one shape in four colours.                        *
   *                                                                        *
   * Tenant colour never reaches this palette. That is what allows error to  *
   * be red at full strength: a bank's green cannot turn an error into a     *
   * success. Retreating to grey and blue is the failure, not the safe path. */
  --status-error:      #A33A1C;  /* 5.5:1 — stops the action                  */
  --status-error-bg:   #F9E6E0;  /* + 4px left edge. Blockers get a ground    */
  --status-warn:       #8A5A00;  /* 5.0:1 — proceeds, with a consequence.
                                    SOLID always: --gap-line shares this hue
                                    and is ALWAYS hatched at 45°. Texture is
                                    what separates them, not colour          */
  --status-warn-bg:    #FBF1DC;
  --status-ok:         #1F5136;  /* 7.8:1 — confirms an action. INTERFACE
                                    ONLY: a competency at its required level
                                    is ink and a check, never green          */
  --status-ok-bg:      #E4EFE7;
  --status-info:       #4B5663;  /* 6.3:1 — worth knowing, changes nothing.
                                    Neutral rather than blue, because blue is
                                    the tenant's and a note is not theirs to
                                    recolour. No ground, no edge             */

  /* Two rules with no token:
     - A blocker outranks a note visually AND in document order.
     - A disabled control explains itself where it sits, not elsewhere.
     - Emphasis inside a sentence is WEIGHT, never colour. Blue is a link and
       nothing else, or a pale gold tenant makes the emphasis unreadable.   */

  /* ---- Annotation: canvas only, never shipped -------------------------- */
  --annotation:        #5B4B8A;  /*  6.2:1 — provisional, open question         */

  /* ---- Four values workforce.css needed and the set did not have ------- *
   * Added rather than left raw: a raw hex in a component stylesheet is the
   * drift the type-scale pass existed to remove.                          */
  --tick:              #616974;  /*  4.8:1 — a non-required track tick, and the
                                    label on an inert control. One step lighter
                                    than --text-label, and the floor for 10px  */
  --gap-text:          #6B4600;  /*  6.6:1 — text on --gap-fill. Darker than
                                    --gap-line, which draws rather than reads   */
  --met-fill:          #E4EFE7;  /*  paired with --met. The SUCCESS status only,
                                    never competency data                       */
  --line-strong:       #C6CDD5;  /*  1.55:1 — a nested control's edge, one step
                                    inside --unrecorded so an indented option reads
                                    as subordinate without changing its type       */
  --rule:              #B9BDB6;  /*  a drawn rule between steps in a stepper, and
                                    the divider in a standing head. Structure    */
  --inert:             #8B939C;  /*  3.11:1, and NEVER ON DATA. This is the label on
                                    a control that cannot be pressed: not text
                                    somebody needs to read, but a shape that has to
                                    look unavailable, and every inert control in this
                                    product states its reason in adjacent text at
                                    --text-secondary.

                                    A datum somebody reads is text however
                                    unremarkable it is: a zero in a queue column and
                                    the word Never in a retention column are both
                                    facts an operator scans for, and 3.11 is under AA
                                    for text. A quiet datum takes --text-secondary at
                                    6.3:1, which still recedes against ink.

                                    An earlier version of this comment also claimed
                                    2.4:1, from a round when the value was different.
                                    One token, one ratio: a comment carrying two is a
                                    comment nobody can check against the hex.       */
  --annotation-text:   #5B6672;  /*  5.5:1 — the review canvas's own prose: artboard
                                    intros and standing heads. NOT a product token.
                                    It appeared on rendered surfaces in 71 places,
                                    which was drift; those are --text-secondary now.
                                    If this value turns up in a template, it is a
                                    canvas note that has escaped into the product.  */

  /* ---- Tenant branding (ADR 0003) -------------------------------------- *
   * Computed once at provisioning from the supplied primary, never chosen  *
   * per screen. Octralis default #1D4ED8 when a tenant supplies nothing.   */
  --t-raw:   #0B2C5A;  /* the supplied value, used flat: header, primary fill   */
  --t-fg:    #0B2C5A;  /* darkened until it clears 4.5:1 on --ground; used for
                          links, active nav, focus ring                         */
  --t-on:    #FFFFFF;  /* text on --t-raw: white where it clears 4.5:1 on the
                          fill, otherwise #131920. Gold and teal take ink       */
  --t-edge:  transparent; /* a drawn boundary when --t-raw is under 3:1 against
                          --ground, so a pale fill still has an edge            */

  /* ---- Type ------------------------------------------------------------ *
   * System stack only. No webfont: the byte budget comes from a bandwidth  *
   * argument and the learner pays for the bytes.                           */
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
       /* mono earns its place: it keeps 31/54 aligned down a column       */

  /* Twelve steps, and they now contain every size the canvases draw with.
     The previous scale had nine names against thirty rendered sizes, so most
     inline values matched no token and could not be tokenised. Sizes below
     15px rose in the consolidation: design-brief.md §1 puts the learner at
     English as a second or third register, reading on a phone, and small
     type costs that reader more than it costs us. Nothing above 15px was
     lowered except where two neighbours were one decision drawn twice.

     WAS -> IS, all thirty:
       8.5, 9, 9.5, 10        -> 10    micro
       10.5, 11               -> 11    caps
       11.5, 12               -> 12    label
       12.5, 13, 13.5         -> 13.5  meta   (12.5 was carrying whole pages)
       14, 14.5               -> 14    body-sm
       15, 15.5               -> 15    body
       16, 17                 -> 17    body-lg
       18, 19                 -> 19    h3
       20, 21, 22             -> 21    h2
       23, 24                 -> 24    h1
       25, 26, 27, 28         -> 26    display
       40, 44                 -> 44    canvas title, not product

     Added after: --size-figure 30px, a count that leads a row. It was in
     workforce.css before it was in the scale, which is the direction that
     produces drift — a value the stylesheet ships and the scale does not
     name is a value every board is free to approximate.                 */

  --size-canvas:   44px;  /* artboard titles on the review canvas only      */
  --size-figure:   30px;  /* a count that LEADS a row: the dashboard's shortfalls,
                             20a's four figures, 21a's two. Larger than --size-display
                             because it is read as a magnitude beside a sentence
                             rather than as a heading above one, and tabular-nums
                             makes a column of them scan. It is what workforce.css
                             ships as .figure__count, and the stylesheet governs, so
                             the scale names it rather than the boards drifting to it */
  --size-display:  26px;
  --size-h1:       24px;
  --size-h2:       21px;
  --size-h3:       19px;
  --size-body-lg:  17px;  /* course reading. Never smaller: people read this
                             for forty-five minutes                        */
  --size-body:     15px;  /* learner surfaces                              */
  --size-body-sm:  14px;  /* was 13.5                                      */
  --size-meta:     13.5px;/* was 12.5. The record and admin surfaces are
                             mostly captions, so this one size carries them */
  --size-label:    12px;
  --size-caps:     11px;  /* small-caps mono section labels. Was 10.5       */
  --size-micro:    10px;  /* floor. Mono caps and track ticks only, never
                             a sentence. A required track tick reads
                             "▲ REQ" rather than "▲ L3 REQ" because the
                             longer form wrapped at 360px                  */

  /* ---- The PRINT SCALE, and why it is a second one ---------------------- *
   * The board pack is paper. 13.5px on a screen somebody is a foot from is
   * not 13.5px on a sheet somebody is holding, so the pack runs its own
   * steps at 96dpi.
   *
   * DECLARING IT IS THE POINT. An undeclared second scale is
   * indistinguishable from drift: 12.5 and 11.5 survived on screen boards
   * looking like decisions until review measured them against the thirteen,
   * and nothing said they were print. A value off the screen scale is a
   * defect unless it is inside a print page, and this block is what makes
   * that checkable.
   *
   * These are print-only and must not appear on a screen surface, which is
   * the other half of the same rule.                                      */

  --print-micro:    9px;  /* legends and the page footer                    */
  --print-caps:    10px;  /* small-caps section labels                      */
  --print-legend: 10.5px; /* the matrix legend                              */
  --print-label:   11px;  /* a figure's caption                             */
  --print-body:  11.5px;  /* the matrix cells and row names                 */
  --print-value:   12px;  /* body prose on a page                           */
  --print-note:  12.5px;  /* the one-page pack's own rows                   */
  --print-h3:      19px;  /* a section head on a page                       */
  --print-figure:  22px;  /* a shortfall count                              */
  --print-h2:      24px;  /* the day-one pack's headline                    */
  --print-h1:      32px;  /* the tenant's name on the title block           */

  /* ---- Space: 4-based -------------------------------------------------- */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  /* Two densities, stated: learner rows pad 13 to 16px, admin cells 8 to 10px.
     This note is ABOVE the line because it describes the scale rather than any one
     step, and a comment trailing eight declarations belongs to none of them. */
  --s-5: 20px; --s-6: 28px; --s-7: 40px; --s-8: 56px;

  --radius: 0;  /* a record, not a card                                        */

/* ---- Not tokens, but they belong beside them -------------------------- *
 * An attempt has a lifetime, set per assessment and pinned when the
 * learner starts. Two hours by default. Nothing on screen is timed and
 * stopping is always safe, but the safety has an edge, so the copy states
 * the real window rather than promising none:
 *
 *   "Nothing here is timed, and there is no pass mark on the baseline.
 *    You can stop after any question and come back, and your place is
 *    kept for two hours from when you start."
 *
 * A baseline is scored, reaches no verdict and charges no cooldown. It
 * has its own result screen (Assessment.dc.html#18a) rather than
 * borrowing the passing one: "demonstrated" is reserved for a level that
 * produced an evidence record, and a baseline states a starting point.  */
}

/* ---- Rules that are not colours ---------------------------------------- *
 * These are load-bearing and easy to lose in implementation.               */

.hatch-gap {
  background-color: var(--gap-fill);
  border: 1px solid var(--gap-line);
  background-image: repeating-linear-gradient(
    45deg, var(--gap-line) 0 1.5px, transparent 1.5px 5px);
}

/* Status banner: one shape for all four. Tinted fill, 4px bar down the left in the
   status line colour, no border on the other three sides. The fill is what makes a bar
   enough, which is why INFORMATION uses --surface-sunken rather than --surface: a white
   fill on a white card would leave the bar carrying the container alone. Its bar is
   --unrecorded at 3.1:1, not --line at 1.29 — a status marker is not decoration.
   Inside: a small-caps label, the sentence that stops you at weight 600, detail, then
   what to do. ERROR, WARNING and SUCCESS use the status word, because for those the
   severity IS the information. INFORMATION uses a label naming what the message means
   (SAFE TO LEAVE, NOT AN INVITATION FOR YOU), because the word "information" tells the
   reader nothing they cannot already see. */
.banner        { border-left: 4px solid; padding: 14px 16px; display: flex; gap: 12px;
                 align-items: flex-start; }
.banner-error  { background: var(--warning-fill);  border-left-color: var(--warning-line); }
.banner-warn   { background: var(--gap-fill);      border-left-color: var(--gap-line); }
.banner-ok     { background: #E4EFE7;              border-left-color: var(--met); }
.banner-info   { background: var(--surface-sunken); border-left-color: var(--unrecorded); }

/* A 3px bar is quoted content, not a status: a prompt example, a learner's own words,
   a finding. The two widths are the distinction, so neither reads as the other. */

.unrecorded { background: var(--surface); border: 1.5px dotted var(--unrecorded); }
.above      { background: var(--surface); border: 1.5px dashed var(--above); }
.evidence   { background: var(--evidence); border: 1px solid var(--evidence); }

/* Status blocks. The 4px edge is what says "this one stops you". */
.status-error { background: var(--status-error-bg); border-left: 4px solid var(--status-error); }
.status-warn  { background: var(--status-warn-bg);  border-left: 4px solid var(--status-warn); }
.status-ok    { background: var(--status-ok-bg);    border-left: 4px solid var(--status-ok); }
.status-info  { background: transparent; border: 0; }
.swatch-progress { background: var(--progress); border: 1px solid var(--progress); }
     /* RENAMED from .progress, which collided with workforce.css's block container:
        a swatch paints a fill and a container paints nothing, so the swatch's grey
        showed through wherever the blocks did not fill the row — My Learning's rows
        since handover 14, and 14b. This file's four .hatch-gap / .unrecorded / .above
        / .evidence classes are swatches too; .progress was the one whose name a
        component also wanted, and the component's use is the truer one. */

/* ---- Interactive states ----------------------------------------------- *
 * Hover reaches a person with a pointer; focus is the only state a keyboard
 * user gets, so it is not optional. One ring on every control, in ink, so
 * a focused primary button cannot draw a gold ring on a gold fill.        */

:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }

.btn-primary:hover   { box-shadow: inset 0 0 0 999px rgba(19,25,32,0.14); }
     /* an inset wash, never a darker hex: --t-raw is the tenant's variable,
        and one wash deepens a navy and a pale gold in the same direction  */
.btn-secondary:hover { background: var(--line-hairline); border-color: var(--text); }
     /* the border moving is the load-bearing half; a fill change alone is
        a colour-only signal                                               */
.btn-danger:hover    { background: var(--warning-fill); }

.btn-primary:active  { box-shadow: inset 0 0 0 999px rgba(19,25,32,0.26); }
     /* the same wash, deeper. No translate: a 1px drop feels responsive on
        a laptop and reads as a rendering fault on a slow repaint          */

[disabled], [aria-disabled="true"] {
  background: var(--line-hairline); color: var(--text-label);
  border: 1px solid var(--line); box-shadow: none; cursor: default;
}
     /* Still focusable and announced as disabled, never removed from the tab
        order: a keyboard user who cannot reach it cannot read why it is
        there. The reason goes BESIDE the control, never in a tooltip — a
        tooltip on something nobody can press is a reason nobody can reach. */
a:hover              { text-decoration: underline; text-underline-offset: 2px; }
     /* the colour does not move: links sit inside sentences               */

/* Nothing hovers that cannot be pressed: no table rows, competency tracks,
   matrix cells or status banners. Nothing moves on hover either — no lift,
   no shadow, no transform. Motion is the first thing to fail on a low-end
   Android, and a record does not need to feel springy.                    */

/* Print: the dashboard goes into board packs in black and white, so every
   state above must survive losing colour. It does, because fill, texture and
   dash pattern carry the meaning and colour only reinforces it.            */
