/* TAU design tokens — v8
 *
 * Load this BEFORE style.css and report.css. Section 4 aliases the two
 * legacy vocabularies onto these tokens, so the existing ~800 var()
 * references retheme without being touched. Migration order:
 *
 *   1. <link> this file first, delete the :root blocks in style.css,
 *      report.css and dashboard.html. App rethemes, no component edits.
 *   2. Fix the 9 inline styles and 24 stray hexes that bypass var().
 *   3. Rewrite components onto --tau-* names, deleting section 4 aliases
 *      as each legacy name reaches zero references.
 *
 * Section 4 is scaffolding. It is finished when it is empty.
 */

:root {
  color-scheme: light dark;

  /* ---------------------------------------------------------------
   * 1. BRAND
   * Forest is the only accent. It earns four jobs and no others:
   * interactive text, primary fills, meter fills, and the rule that
   * marks a system message. Sage is fill-only — it fails contrast as
   * text and must never carry any.
   * --------------------------------------------------------------- */
  --tau-forest:      #1F4D3A;
  --tau-forest-lift: #2A6349;
  --tau-sage:        #3D7A5A;
  --tau-on-forest:   #FFFFFF;

  /* ---------------------------------------------------------------
   * 2. GROUND — a faint forest wash, with card surfaces left white.
   * Forest is the brand colour, not just an accent (revised
   * 2026-07-21) — v7's fully-neutral ground was the "white-washed
   * with a green accent" problem, not the fix for it. The wash stays
   * whisper-quiet (chroma 0.006–0.010, same hue as forest) so it
   * reads as identity, not as v7's saturated brand-demo tint: --tau-
   * surface (cards, panels) stays pure white so content still pops
   * off the ground, and body-text contrast ratios are unchanged
   * because only chroma moved, not lightness.
   * --------------------------------------------------------------- */
  --tau-bg:        oklch(0.992 0.006 162);
  --tau-surface:   #FFFFFF;
  --tau-surface-2: oklch(0.968 0.008 162);
  /* Respaced 2026-08-22 (later the same day) onto M3's container tones —
     100 / 96 / 94 / 90 — so the four steps sit at even intervals instead of
     three crowded ones plus a gap. Was 0.938. See --tau-shell below for what
     this cost and why it was taken anyway. */
  --tau-surface-3: oklch(0.952 0.010 162);

  /* The app shell — the rail and the pane behind the content, as ONE
     surface. Added 2026-08-22.

     It exists because the light ramp above runs the OPPOSITE DIRECTION
     to the dark one. Dark ascends from near-black (#16181A → #2D3134),
     so a higher step is lighter and reads RAISED. Light descends from
     white, so a higher step is darker and reads RECESSED. A card filled
     with --tau-surface-2 therefore means "raised" in dark and "sunken"
     in light off one declaration — which is why the teacher dashboard's
     sage bands read flat, and why adding a shadow made it worse rather
     than better: the shadow lit an inset, and its penumbra bled out of
     an edge with only a ~3% lightness step to define it.

     The ramp cannot fix this from the inside: 0.938–1.0 is about 6% of
     lightness for four steps, so three ordered surfaces leave ~2.4%
     between neighbours, which IS the low-contrast edge. This value sits
     below the ramp instead, buying a ~10% step under the sage bands so
     they read raised without changing the cards at all.

     CHROMA. 0.018 is past the 0.006–0.010 the light-theme ground wash
     was granted under (designsystem.md, 2026-07-21). That cap was set
     against a WHITE-GROUND ramp where a deeper wash had no job; on a
     shell whose whole purpose is to sit under the content, chroma has
     to track lightness or the ground greys out and the wash stops
     reading as forest at all. It follows the ramp's own trend
     (0.006 → 0.008 → 0.010 as L falls) rather than being dialled
     independently — a ground that gains saturation faster than it loses
     lightness is what reads as a brand demo.

     Dark takes --tau-bg's value: dark's shell is already the darkest
     thing on screen, so the relationship it encodes is unchanged there
     and only light needed a new step.

     REVISED to 0.920 / chroma 0.014, later on 2026-08-22, after an M3
     review (app/web/m3-lab.html §4). The argument above is unchanged and
     still correct — what changed is the whole ramp underneath it. With
     surface-3 respaced to 0.952 the ramp now runs 1.0 / 0.968 / 0.952 /
     0.920, which is M3's container spacing (tones 100/96/94/90) at even
     intervals, and 0.865 sat below M3's entire container range.

     THE COST, MEASURED, because it is the one thing this trade gives up:
     a --tau-surface-2 band on the shell separated by 10.3 points of
     lightness at 0.865 and separates by 4.8 at 0.920. That is a real
     reduction in exactly the quantity the earlier fix on this line was
     bought to add. It is still well clear of the ~3% edge that started
     all this, and it is the spacing M3 uses between its own low and
     highest containers — but if Home reads flat again, THIS LINE is the
     first place to look, and reverting it to 0.865 restores the earlier
     behaviour without touching anything else.

     Chroma follows the ramp's trend down from 0.018 to 0.014 with the
     lightness rise, for the reason the paragraph above gives. */
  --tau-shell:     oklch(0.920 0.014 162);

  --tau-ink:       #16191C;
  --tau-ink-soft:  #545B63;
  --tau-ink-faint: #767D85;

  /* Group-label colour for .eyebrow only. Faint reads as a grouping label on
     a dark ground (dark theme keeps it) but washes out on white — light
     theme needs ink-soft's extra weight to stay legible as a divider. */
  --tau-ink-label: var(--tau-ink-soft);

  --tau-line:        oklch(0.895 0.008 162);
  --tau-line-strong: oklch(0.815 0.010 162);

  /* ---------------------------------------------------------------
   * 3. SAMR BANDS
   * Foreground lightness steps down monotonically 1 → 4, so the
   * sequence survives greyscale, colour-blindness and a photocopier.
   * Do not reorder these or the ramp stops carrying meaning on its own.
   * Student-facing labels are words, not levels — see --tau-band-N-label
   * in the product copy, not here.
   * --------------------------------------------------------------- */
  /* Hues 280/205 (not 18/68 — those are --tau-attention/--tau-caution, and
     reusing them made the two lower bands read as warning/error states,
     contradicting "none of the four is a pass or a fail". Also clear of 300
     (--tau-auditor's own hue) so a band chip never reads as the auditor
     voice either. */
  --tau-band-1-bg: oklch(0.951 0.018 280);  --tau-band-1-fg: oklch(0.42 0.058 280);
  --tau-band-2-bg: oklch(0.953 0.022 205);  --tau-band-2-fg: oklch(0.38 0.058 205);
  --tau-band-3-bg: oklch(0.948 0.018 242);  --tau-band-3-fg: oklch(0.34 0.052 244);
  --tau-band-4-bg: oklch(0.948 0.022 162);  --tau-band-4-fg: oklch(0.30 0.048 162);

  /* --tau-scale-N — THE ORDINAL RAMP. Graduated from dashboard-lab.html
   * 2026-08-14. Used wherever four bands are PLOTTED TOGETHER as magnitude
   * (.comp, .dbar). --tau-band-N-* keeps its own job, unchanged —
   *
   *   --tau-band-N-*  identifies a band.   One at a time. A chip.
   *   --tau-scale-N   orders four of them. Together. A chart.
   *
   * The band tokens cannot do this second job: all four sit at L 0.948-0.953,
   * a 0.005 spread, so four of them side by side have no ordinal reading.
   *
   * One hue (242 — the only hue that is neither a semantic tier nor a voice).
   * Polarity in the diverging bar is carried by POSITION relative to the seam,
   * never by hue, so a class's skepticism never renders as red-versus-green.
   * Validated in the ordinal mode against the real tau surfaces: monotone
   * lightness, adjacent ΔL >= 0.06, light end clearing 2:1.
   *
   * DIRECTION: band 1 is the step furthest from the ground in both themes —
   * darkest on white, lightest on dark. Deliberately opposite to
   * --tau-band-N-fg's "step down in lightness 1->4", because the finding this
   * chart carries is where the mass sits at the LOW end, so weight belongs on
   * absence. Different token, different job. */
  --tau-scale-1: #1a5780;  --tau-scale-1-ink: var(--tau-surface);
  --tau-scale-2: #44769b;  --tau-scale-2-ink: var(--tau-surface);
  --tau-scale-3: #6a96b7;  --tau-scale-3-ink: var(--tau-ink);
  --tau-scale-4: #91b6d4;  --tau-scale-4-ink: var(--tau-ink);

  /* --tau-agency-N — THE PER-TURN RAMP, on one student's own turns.
   * Added 2026-08-18 for the report's turn map (report.css, .turnplot).
   *
   * A fifth ramp, and it exists because neither of the others can do this job.
   * --tau-band-N identifies ONE band at a time and all four sit within a 0.005
   * lightness spread, so forty-four of them side by side have no ordinal
   * reading. --tau-scale-N orders four bands as magnitude, but its documented
   * direction puts the darkest step on band 1 — correct for the cohort chart it
   * was built for, where the finding is where the mass sits at the LOW end, and
   * wrong here, where the subject is one student and that direction would put
   * the visual weight on their worst moments.
   *
   * Hue 162 — the same hue as --tau-origin-you — so more forest reads as more
   * of the student's own thinking, which the report's origin encoding already
   * teaches. Monotone lightness, strongest at the top.
   * --------------------------------------------------------------- */
  --tau-agency-1: #D8E2DB;  --tau-agency-1-ink: var(--tau-ink);
  --tau-agency-2: #96B7A5;  --tau-agency-2-ink: var(--tau-ink);
  --tau-agency-3: #4F8468;  --tau-agency-3-ink: #FFFFFF;
  --tau-agency-4: #1F4D3A;  --tau-agency-4-ink: #FFFFFF;

  /* The shared chart grid. .comp and .dbar are two partitions of the same
   * cohort, so a length must mean the same student count in both. Both lay
   * out `gutter | track`, so one gutter width is what makes the two 1fr
   * tracks resolve to the same px. Change it and BOTH charts move. */
  --tau-chart-gutter: 1.6rem;

  /* ---------------------------------------------------------------
   * 4. SEMANTIC
   * Kept off the accent hue deliberately. Never applied to a student's
   * own score — a level is a position on a path, not a verdict.
   * Reserved for direction of travel and teacher-side signals.
   * --------------------------------------------------------------- */
  --tau-positive:  oklch(0.50 0.10 158);
  --tau-caution:   oklch(0.52 0.11 68);
  --tau-attention: oklch(0.48 0.10 18);

  --tau-positive-bg:  oklch(0.96 0.022 158);
  --tau-caution-bg:   oklch(0.96 0.024 72);
  --tau-attention-bg: oklch(0.96 0.022 18);

  /* ---------------------------------------------------------------
   * 5. AUDITOR — the second voice.
   * Separated from the coach by hue AND by form (squared corners,
   * ruled edge, monospace label). Hue alone is not enough: the
   * distinction has to survive a colour-blind reader.
   * --------------------------------------------------------------- */
  --tau-auditor:    oklch(0.42 0.09 300);
  --tau-auditor-bg: oklch(0.965 0.015 300);

  /* ---------------------------------------------------------------
   * 5a. TOOL-INFO — a second, distinct voice for the teacher dashboard.
   * The auditor hue (300) is reserved for the Auditor persona's own
   * evaluative voice and, on the teacher side, for a teacher's own
   * quoted words (an assignment's rubric-style note) — see
   * teacher-dashboard-design.md's Visual Language section. Once the
   * dashboard needed to show the *tool's own* generated synthesis next
   * to a teacher's quoted words on the same page, both being violet
   * conflated two different speakers. This is that second voice: same
   * lightness/chroma construction as the auditor token, hue 205 instead
   * of 300 (reusing --tau-band-2's existing hue rather than inventing
   * one from nothing).
   * --------------------------------------------------------------- */
  --tau-tool-info:    oklch(0.42 0.09 205);
  --tau-tool-info-bg: oklch(0.965 0.015 205);

  /* ---------------------------------------------------------------
   * 5b. ORIGIN — where an idea in the essay came from.
   * Student-facing, so it inherits the coach-voice rule: this axis
   * describes authorship, not quality. The previous green/amber/red
   * ramp made "the coach said it first" read as an error, which is
   * the exact verdict the tool promises not to deliver.
   * Same you → together → coach vocabulary as the conversation map,
   * so the two visuals teach one encoding rather than two.
   * Always paired with a text label — never colour alone.
   * --------------------------------------------------------------- */
  --tau-origin-you:      var(--tau-forest);
  --tau-origin-together: var(--tau-sage);
  --tau-origin-coach:    var(--tau-ink-faint);

  /* Chip fills. Text on these stays ink — sage and faint grey both
     fail contrast as text, so the hue rides the fill and the dot. */
  --tau-origin-you-bg:      oklch(0.955 0.022 162);
  --tau-origin-together-bg: oklch(0.962 0.014 162);
  --tau-origin-coach-bg:    var(--tau-surface-2);

  /* ---------------------------------------------------------------
   * 6. CONVERSATION MAP
   * Encoding: lane = one idea, x = turn order, weight = live or set
   * aside, colour + dash = who opened it, end marker = outcome.
   * Nothing here encodes quality; a coach-started thread is not worse.
   * --------------------------------------------------------------- */
  --tau-map-you:        var(--tau-forest);
  --tau-map-coach:      var(--tau-ink-faint);
  --tau-map-coach-dash: 1 4;
  --tau-map-live:       5px;
  --tau-map-quiet:      1.5px;
  --tau-map-grid:       var(--tau-line);
  --tau-map-kept:       var(--tau-forest);
  --tau-map-dropped:    var(--tau-ink-faint);

  /* ---------------------------------------------------------------
   * 7. TYPE
   * The UI face is a system stack until one is self-hosted. Leading
   * with Helvetica Neue — as v7 did — degrades to Liberation Sans on
   * Chromebooks, the dominant device in this market.
   * --------------------------------------------------------------- */
  --tau-font-ui:    system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --tau-font-serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --tau-font-mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* The dashboard leads on one figure at 50px. Without a token for it
     that size gets typed as a literal and drifts per surface. */
  --tau-text-display: 50px;

  /* LABEL ROLES, added 2026-08-22 (m3-lab §6). Eight uppercase treatments at
     five sizes and four tracking values existed across the sheets, all doing
     the one job of naming a group, plus six unofficial sizes below
     --tau-text-xs (9, 9.5, 10, 10.5, 11, 12.5). A component references a ROLE
     now, never a pixel value — the same argument --tau-text-display already
     makes one block down.

     SENTENCE CASE, not uppercase: M3's type scale has no all-caps role (that
     was M2's overline). A label is demoted by size, weight and colour, which
     is three channels and enough. Uppercase survives in exactly two places
     that are not labels — .turn-speaker and the auditor's mono eyebrow, where
     caps are a voice, not a hierarchy. */
  --tau-text-label-sm: 11px;
  --tau-text-label-md: 12px;

  --tau-text-xs:  11.5px;
  --tau-text-sm:  13px;
  --tau-text-md:  14.5px;
  --tau-text-lg:  15.5px;
  --tau-text-xl:  19px;
  --tau-text-2xl: 24px;
  --tau-text-3xl: 30px;

  --tau-leading-tight: 1.25;
  --tau-leading-snug:  1.45;
  --tau-leading-body:  1.55;
  --tau-track-caps:    0.1em;
  --tau-track-label:   0.06em;

  /* ---------------------------------------------------------------
   * 8. SPACE / SHAPE
   * --------------------------------------------------------------- */
  --tau-s1: 4px;  --tau-s2: 8px;  --tau-s3: 12px; --tau-s4: 16px;
  --tau-s5: 20px; --tau-s6: 24px; --tau-s7: 32px; --tau-s8: 40px;
  --tau-s9: 56px; --tau-s10: 72px;

  --tau-r-sm: 6px; --tau-r-md: 10px; --tau-r-lg: 14px; --tau-r-xl: 20px;
  --tau-r-pill: 999px;

  /* A dialog is the one surface where the corner carries "this is a separate
     plane," so it takes M3's own dialog corner (28dp) rather than the next
     rung of this scale. Added 2026-08-22 (m3-lab §9). */
  --tau-r-dialog: 28px;

  /* Minimum interactive target. Not advisory — v7 claimed 44px while
     shipping 20px chips, which is the failure this token prevents.

     It is a TARGET, not a height. Added 2026-08-22 (m3-lab §3): the two
     tokens below are what a control is DRAWN at, and a control smaller than
     --tau-target reaches the floor with a transparent expansion (an ::after
     at inset -Npx) rather than by growing its box. Six visual heights existed
     across one toolbar family — 44/36/36/32/32/22 — four of them under the
     floor while the largest was over-sized to meet it. */
  --tau-target: 44px;

  /* M3 baseline button is 40dp and its chip is 32dp. Two heights, and the
     difference between them means something: a control versus a filter. */
  --tau-h-control: 40px;
  --tau-h-chip:    32px;

  /* One width for every vertical rail in the app. The four surfaces that
     grew a rail independently landed on 292 / 290 / 240 / 224, none of them
     derivable from anything in this file. 272 is the narrowest width that
     still holds the student rail's two-line rows without wrapping and gives
     the teacher rail ~30 characters of class name before it ellipses. It is
     a judgement call, not a derivation — the system has no rule that
     produces a rail width, and that is a real gap. */
  --tau-rail-w: 272px;

  --tau-shadow:      0 1px 2px #16191C0F, 0 8px 24px -16px #16191C2E;
  --tau-shadow-lift: 0 2px 4px #16191C14, 0 18px 40px -22px #16191C3D;

  /* 3px, not 2px, since 2026-08-22 — M3's focus indicator is 3dp at a 2dp
     offset, and 2px was thin enough that on a field it competed with the
     border-colour change rather than replacing it. */
  --tau-focus-ring: 3px solid var(--tau-forest);
  --tau-focus-gap:  2px;

  /* ---------------------------------------------------------------
   * 9. STATE
   * Hover on a forest fill is --tau-forest-lift, never filter:
   * brightness() — brightness lightens in light mode and blows out
   * the already-light dark-mode forest, so one rule needs two
   * opposite behaviours. A second token is the only thing that works
   * in both themes.
   * --------------------------------------------------------------- */
  /* STATE LAYERS, added 2026-08-22 (m3-lab §1). M3's mechanism: a state is a
     translucent overlay of the component's OWN CONTENT COLOUR, at a fixed
     opacity, so one declaration works on every ground.
     Use as: background: color-mix(in oklab, currentColor var(--tau-state-hover), transparent)
     Prefer this over --tau-hover-surface for anything that sits on more than
     one ground. Four hover fills existed across the dashboard's rows because
     each ground needed its own, and components.css:1052 recorded the dead end
     it produces: "--tau-hover-surface is unusable here: it resolves to
     --tau-surface-2, which is the rail's own background."
     --tau-hover-surface is kept for the fixed-ground cases that already use
     it correctly; it is not deprecated, it is just no longer the default. */
  --tau-state-hover: 8%;
  --tau-state-focus: 10%;
  --tau-state-press: 10%;

  --tau-hover-surface: var(--tau-surface-2);
  --tau-disabled:      0.55;
  --tau-scrim:         #16191C66;

  /* The unfilled part of a meter is a lighter step of the same ramp,
     so state reads across the whole bar. This stays inside forest's
     "meter fills" job rather than opening a fifth one. */
  --tau-meter-track: oklch(0.945 0.020 162);

  /* ---------------------------------------------------------------
   * 10. MOTION
   * Duration and easing values are Material 3's, not invented here —
   * M3's motion system is a published, tested answer to exactly this
   * problem and there's no reason to guess our own numbers. We take
   * two rungs of M3's duration scale (short3, medium2) rather than
   * the full short/medium/long/extra-long ladder — this system has
   * no large-surface or expressive transitions (page transforms,
   * shared-element hero motion) for the slower rungs to serve, and an
   * unused rung is just a third value someone eventually reaches for
   * out of habit.
   * short   — a state change with no distance to travel: hover,
   *           press, a toggle's colour/background.
   * medium  — something moves or resizes on screen: a disclosure
   *           opening, a panel sliding, a card lifting.
   * Easing: standard for anything symmetric (the same motion plays in
   * reverse — most hover/press states); decelerate for something
   * entering or appearing (arrives fast, settles slow); accelerate
   * for something leaving (starts slow, exits fast). M3's full
   * "emphasized" curve is a two-segment path built from exactly these
   * accelerate/decelerate halves — we use the halves directly on
   * whichever edge of a transition needs them rather than approximate
   * the whole path as one cubic-bezier, which is what M3's own CSS
   * guidance recommends for single-property transitions.
   * --------------------------------------------------------------- */
  --tau-dur-short:  150ms;  /* M3 short3 */
  --tau-dur-medium: 300ms;  /* M3 medium2 */

  --tau-ease-standard:    cubic-bezier(0.2, 0, 0, 1);       /* M3 standard */
  --tau-ease-decelerate:  cubic-bezier(0.05, 0.7, 0.1, 1);  /* M3 emphasized-decelerate */
  --tau-ease-accelerate:  cubic-bezier(0.3, 0, 0.8, 0.15);  /* M3 emphasized-accelerate */
}

/* ===================================================================
 * DARK
 * Charcoal, not forest. A dark theme tinted toward the brand becomes
 * a green room; the accent stops reading as an accent.
 * =================================================================== */
@media (prefers-color-scheme: dark) {
  :root {
    --tau-forest:      #6FBF95;
    --tau-forest-lift: #8CD1AC;
    --tau-sage:        #4F9973;
    --tau-on-forest:   #12211A;

    --tau-bg:        #16181A;
    --tau-surface:   #1C1F21;
    --tau-surface-2: #232729;
    --tau-surface-3: #2D3134;
    /* Dark's shell is already the darkest thing on screen. */
    --tau-shell:     #16181A;

    --tau-ink:       #E9EBEC;
    --tau-ink-soft:  #A2A9AE;
    --tau-ink-faint: #858C92;
    --tau-ink-label: var(--tau-ink-faint);

    --tau-line:        #2D3134;
    --tau-line-strong: #3E4448;

    --tau-band-1-bg: oklch(0.26 0.030 280);  --tau-band-1-fg: oklch(0.82 0.070 280);
    --tau-band-2-bg: oklch(0.26 0.034 205);  --tau-band-2-fg: oklch(0.85 0.075 205);
    --tau-band-3-bg: oklch(0.26 0.032 242);  --tau-band-3-fg: oklch(0.83 0.065 242);
    --tau-band-4-bg: oklch(0.26 0.034 162);  --tau-band-4-fg: oklch(0.86 0.070 162);

    /* The ordinal ramp, SELECTED against the dark surface, not flipped.
       Band 1 stays the step furthest from the ground — lightest here. */
    --tau-scale-1: #c2e6ff;  --tau-scale-1-ink: var(--tau-surface);
    --tau-scale-2: #8ec0e4;  --tau-scale-2-ink: var(--tau-surface);
    --tau-scale-3: #5c8fb3;  --tau-scale-3-ink: var(--tau-surface);
    --tau-scale-4: #325f80;  --tau-scale-4-ink: var(--tau-ink);

    /* Same direction as light: step 4 is the strongest, furthest from the
       ground. On a dark ground that means lightest, not darkest. */
    --tau-agency-1: #2C3A33;  --tau-agency-1-ink: var(--tau-ink);
    --tau-agency-2: #4E6B5B;  --tau-agency-2-ink: #FFFFFF;
    --tau-agency-3: #7FB397;  --tau-agency-3-ink: #12211A;
    --tau-agency-4: #B8E3CB;  --tau-agency-4-ink: #12211A;

    --tau-positive:  oklch(0.76 0.11 158);
    --tau-caution:   oklch(0.79 0.11 72);
    --tau-attention: oklch(0.74 0.10 18);

    --tau-positive-bg:  oklch(0.26 0.032 158);
    --tau-caution-bg:   oklch(0.26 0.034 72);
    --tau-attention-bg: oklch(0.26 0.032 18);

    --tau-auditor:    oklch(0.80 0.09 300);
    --tau-auditor-bg: oklch(0.25 0.035 300);

    --tau-tool-info:    oklch(0.80 0.09 205);
    --tau-tool-info-bg: oklch(0.25 0.035 205);

    --tau-origin-you-bg:      oklch(0.27 0.035 162);
    --tau-origin-together-bg: oklch(0.25 0.022 162);

    --tau-meter-track: oklch(0.30 0.030 162);
    --tau-scrim:       #00000099;

    --tau-shadow:      0 1px 2px #0006, 0 8px 24px -16px #0009;
    --tau-shadow-lift: 0 2px 4px #0006, 0 18px 40px -22px #000c;
  }
}

/* A reader's explicit choice outranks the OS in both directions. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --tau-forest: #6FBF95; --tau-forest-lift: #8CD1AC; --tau-sage: #4F9973; --tau-on-forest: #12211A;
  --tau-bg: #16181A; --tau-surface: #1C1F21; --tau-surface-2: #232729; --tau-surface-3: #2D3134; --tau-shell: #16181A;
  --tau-ink: #E9EBEC; --tau-ink-soft: #A2A9AE; --tau-ink-faint: #858C92; --tau-ink-label: var(--tau-ink-faint);
  --tau-line: #2D3134; --tau-line-strong: #3E4448;
  --tau-band-1-bg: oklch(0.26 0.030 280); --tau-band-1-fg: oklch(0.82 0.070 280);
  --tau-band-2-bg: oklch(0.26 0.034 205); --tau-band-2-fg: oklch(0.85 0.075 205);
  --tau-band-3-bg: oklch(0.26 0.032 242); --tau-band-3-fg: oklch(0.83 0.065 242);
  --tau-band-4-bg: oklch(0.26 0.034 162); --tau-band-4-fg: oklch(0.86 0.070 162);

  /* The ordinal ramp, SELECTED against the dark surface, not flipped.
     Band 1 stays the step furthest from the ground — lightest here. */
  --tau-scale-1: #c2e6ff;  --tau-scale-1-ink: var(--tau-surface);
  --tau-scale-2: #8ec0e4;  --tau-scale-2-ink: var(--tau-surface);
  --tau-scale-3: #5c8fb3;  --tau-scale-3-ink: var(--tau-surface);
  --tau-scale-4: #325f80;  --tau-scale-4-ink: var(--tau-ink);

  /* The agency ramp keeps its own direction in both themes: step 4 is the
     strongest and sits furthest from the ground, so lightest here. */
  --tau-agency-1: #2C3A33;  --tau-agency-1-ink: var(--tau-ink);
  --tau-agency-2: #4E6B5B;  --tau-agency-2-ink: #FFFFFF;
  --tau-agency-3: #7FB397;  --tau-agency-3-ink: #12211A;
  --tau-agency-4: #B8E3CB;  --tau-agency-4-ink: #12211A;

  --tau-positive: oklch(0.76 0.11 158); --tau-caution: oklch(0.79 0.11 72); --tau-attention: oklch(0.74 0.10 18);
  --tau-positive-bg: oklch(0.26 0.032 158); --tau-caution-bg: oklch(0.26 0.034 72); --tau-attention-bg: oklch(0.26 0.032 18);
  --tau-auditor: oklch(0.80 0.09 300); --tau-auditor-bg: oklch(0.25 0.035 300);
  --tau-tool-info: oklch(0.80 0.09 205); --tau-tool-info-bg: oklch(0.25 0.035 205);
  --tau-origin-you-bg: oklch(0.27 0.035 162); --tau-origin-together-bg: oklch(0.25 0.022 162);
  --tau-meter-track: oklch(0.30 0.030 162);
  --tau-scrim: #00000099;
  --tau-shadow: 0 1px 2px #0006, 0 8px 24px -16px #0009;
  --tau-shadow-lift: 0 2px 4px #0006, 0 18px 40px -22px #000c;
}

:root[data-theme="light"] {
  color-scheme: light;
  --tau-forest: #1F4D3A; --tau-forest-lift: #2A6349; --tau-sage: #3D7A5A; --tau-on-forest: #FFFFFF;
  --tau-bg: oklch(0.992 0.006 162); --tau-surface: #FFFFFF; --tau-surface-2: oklch(0.968 0.008 162); --tau-surface-3: oklch(0.952 0.010 162); --tau-shell: oklch(0.920 0.014 162);
  --tau-ink: #16191C; --tau-ink-soft: #545B63; --tau-ink-faint: #767D85; --tau-ink-label: var(--tau-ink-soft);
  --tau-line: oklch(0.895 0.008 162); --tau-line-strong: oklch(0.815 0.010 162);
  --tau-band-1-bg: oklch(0.951 0.018 280); --tau-band-1-fg: oklch(0.42 0.058 280);
  --tau-band-2-bg: oklch(0.953 0.022 205); --tau-band-2-fg: oklch(0.38 0.058 205);
  --tau-band-3-bg: oklch(0.948 0.018 242); --tau-band-3-fg: oklch(0.34 0.052 244);
  --tau-band-4-bg: oklch(0.948 0.022 162); --tau-band-4-fg: oklch(0.30 0.048 162);
  --tau-positive: oklch(0.50 0.10 158); --tau-caution: oklch(0.52 0.11 68); --tau-attention: oklch(0.48 0.10 18);
  --tau-positive-bg: oklch(0.96 0.022 158); --tau-caution-bg: oklch(0.96 0.024 72); --tau-attention-bg: oklch(0.96 0.022 18);
  --tau-auditor: oklch(0.42 0.09 300); --tau-auditor-bg: oklch(0.965 0.015 300);
  --tau-tool-info: oklch(0.42 0.09 205); --tau-tool-info-bg: oklch(0.965 0.015 205);
  --tau-origin-you-bg: oklch(0.955 0.022 162); --tau-origin-together-bg: oklch(0.962 0.014 162);
  --tau-meter-track: oklch(0.945 0.020 162);
  --tau-scrim: #16191C66;
  --tau-shadow: 0 1px 2px #16191C0F, 0 8px 24px -16px #16191C2E;
  --tau-shadow-lift: 0 2px 4px #16191C14, 0 18px 40px -22px #16191C3D;
}

/* ===================================================================
 * SECTION 4 — LEGACY BRIDGE  (temporary; delete as it empties)
 *
 * style.css and report.css grew separate vocabularies that happen to
 * agree on meaning: --border is always a hairline, --text always ink,
 * --muted always secondary. That agreement is what lets one bridge
 * serve both files.
 *
 * Track progress with:
 *   grep -rc 'var(--border' app/web/
 * When a legacy name hits zero, delete its line here.
 * =================================================================== */
:root {
  /* --- ground: both files --- */
  --bg:      var(--tau-bg);
  --surface: var(--tau-surface);   /* report.css */
  --surface2:var(--tau-surface-2);
  --border:  var(--tau-line);

  /* --- ink --- */
  --text:       var(--tau-ink);
  --muted:      var(--tau-ink-soft);
  --text-muted: var(--tau-ink-soft);
  --text-mid:   var(--tau-ink-soft);

  /* --- accent: was #2563eb / #3B3EA8 blue, now forest --- */
  --accent:       var(--tau-forest);
  --accent-fill:  var(--tau-forest-lift);

  /* --- report.css hue set. These named themselves after colours
         rather than roles, which is why they need interpreting:
         blue = neutral/structural, green = positive, terra = attention. --- */
  --blue:       var(--tau-band-3-fg);
  --blue-mid:   var(--tau-band-3-fg);
  --blue-light: var(--tau-band-3-bg);
  --blue-tint:  var(--tau-band-3-bg);
  --green:      var(--tau-positive);
  --green-tint: var(--tau-positive-bg);
  --amber:      var(--tau-caution);
  --amber-tint: var(--tau-caution-bg);
  --terra:       var(--tau-attention);
  --terra-light: var(--tau-attention-bg);
  --terra-tint:  var(--tau-attention-bg);
  --grey-tint:   var(--tau-surface-2);

  /* --- Agency level: was slate/blue/green/purple, four unrelated hues on an
         ordered scale. Now the ordered earth ramp. --- */
  --level-passive: var(--tau-band-1-fg);
  --level-reactive: var(--tau-band-2-fg);
  --level-directive: var(--tau-band-3-fg);
  --level-transformative: var(--tau-band-4-fg);

  /* --- turn labels. 17 pairs collapsed onto three semantic families,
         matching the existing positive / neutral / negative grouping
         already commented in report.css. --- */
  --label-challenge:  var(--tau-positive-bg);  --label-challenge-text:  var(--tau-positive);
  --label-rejection:  var(--tau-positive-bg);  --label-rejection-text:  var(--tau-positive);
  --label-refinement: var(--tau-positive-bg);  --label-refinement-text: var(--tau-positive);
  --label-claim:      var(--tau-positive-bg);  --label-claim-text:      var(--tau-positive);
  --label-conceptual: var(--tau-positive-bg);  --label-conceptual-text: var(--tau-positive);
  --label-narrative:  var(--tau-positive-bg);  --label-narrative-text:  var(--tau-positive);

  --label-pivot:      var(--tau-band-3-bg);    --label-pivot-text:      var(--tau-band-3-fg);
  --label-feedback:   var(--tau-band-3-bg);    --label-feedback-text:   var(--tau-band-3-fg);
  --label-extraction: var(--tau-band-3-bg);    --label-extraction-text: var(--tau-band-3-fg);

  --label-validation: var(--tau-caution-bg);   --label-validation-text: var(--tau-caution);
  --label-stuck:      var(--tau-caution-bg);   --label-stuck-text:      var(--tau-caution);

  --label-ai-content:     var(--tau-surface-2); --label-ai-content-text:     var(--tau-ink-soft);
  --label-ai-definition:  var(--tau-surface-2); --label-ai-definition-text:  var(--tau-ink-soft);
  --label-ai-argument:    var(--tau-surface-2); --label-ai-argument-text:    var(--tau-ink-soft);
  --label-ai-example:     var(--tau-surface-2); --label-ai-example-text:     var(--tau-ink-soft);
  --label-ai-instruction: var(--tau-surface-2); --label-ai-instruction-text: var(--tau-ink-soft);
  --label-ai-correction:  var(--tau-surface-2); --label-ai-correction-text:  var(--tau-ink-soft);
}

/* ===================================================================
 * BASELINE
 * The three accessibility defaults v7 asserted but did not ship.
 * =================================================================== */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: var(--tau-focus-ring);
  outline-offset: var(--tau-focus-gap);
  border-radius: var(--tau-r-sm);
}

/* Shared entrance for content that appears in place — a disclosure opening,
   a panel's content mounting. Native <details> snaps its content in with no
   transition of its own; this runs once the browser sets display:block, so
   it doesn't fight the toggle mechanics. Any surface can reuse it rather
   than writing its own reveal keyframes. */
@keyframes tau-reveal {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* 100vh is wrong on mobile Safari with the keyboard open — the exact
   condition a student writing on a phone hits. */
@supports (height: 100dvh) {
  .view, .full-height { height: 100dvh; }
}
