/*
 * Design tokens — the single source for colour, spacing, typography, and radius.
 * Every stylesheet and template consumes these; nothing else restates the values.
 *
 * The palette is the Next.js prototype's (`hamagakuen-ai-edu`, `src/app/globals.css`
 * `:root`) — the UI the school chose at the demo on 2026-08-03 (ADR-020 §Decision 2).
 * That supersedes both seeds this file carried before: the Microsoft Fluent 2 ramp
 * (ADR-011, issue #29) and the Hamagakuen logo blue #0395DA (client, 2026-07-30).
 * Values are copied, never re-derived; the only permitted difference is a WCAG AA
 * nudge, and every one records the prototype's original value and the measured
 * ratio at the token (ADR-020 §Decision 3).
 *
 * Every ratio below names its reference background, because the prototype has two:
 * the page --background #f8fafc and the raised surface --card-bg #ffffff. WCAG 2.1
 * AA thresholds: 4.5:1 for body text, 3:1 for large text and for the boundaries
 * that identify a control.
 *
 * The type / spacing / layout scales at the bottom are still the Fluent ones. They
 * are not colour and nothing about them was rejected on 2026-08-03; every
 * hand-written stylesheet consumes them, so they retire with their last reference,
 * not here. The colour bridge and the Fluent radius ramp reached zero references in
 * the sweep (#137) and are gone.
 */

/*
 * Noto Sans JP, self-hosted — **可変フォント1本**（wght 400〜700）。
 *
 * --font-family-base は #29 からこの名前を書いていたのに font が無く、全画面が
 * Hiragino / Yu Gothic の fallback で出ていた（#128）。fonts.googleapis.com /
 * fonts.gstatic.com には実行時に一切取りに行かない: ADR-006 は front-end の資産を
 * 実ファイルとして vendor する決まりで、未成年の個人情報を映す画面のページ
 * ビューを第三者に渡すことにもなる。
 *
 * **静的3ウェイトから可変1本に替えた**（PM 2026-08-31）。400/500/700 を別々の
 * ファイルで持つと日本語だけで 3.30MB あり、どの画面も3つとも要る（見出し700・
 * ラベル500・本文400）ので初回に全部落ちていた。可変にすると 1.92MB、6ファイルが
 * 2ファイルになる。収録している文字は1文字も変えていない（下の subset は前と
 * 同じ codepoint 集合から作った）。
 *
 * 軸は 400〜700 に狭めてある。画面が使うのはその3つで、範囲外のデルタは
 * 落とせるぶんだけ小さくなる。軸そのものは残るので、間の太さも出せる。
 *
 * Source:  google/fonts @ 66a36c8c94b1a5d992ee4e7f392fccfe4945767c —
 *          ofl/notosansjp/NotoSansJP[wght].ttf
 *          sha256 c2f3b4d463500a2ddcd3849cded1fceeb9fd6d1c32e6cbecd568453ba50fc68f
 *          Version 2.004（font 自身の name ID 5）。Google Fonts が css2 v56 で
 *          配っているものと同じ。
 * Licence: SIL Open Font License 1.1 — ../vendor/fonts/OFL.txt。ほかの vendored
 *          資産と同じく docs/project-config.md §9 にも記録。
 * Built:   fontTools（一度きり。ADR-020 が許すビルド手順は Tailwind の1つだけで、
 *          これはそれではない。committed な2ファイルが成果物である）:
 *            1. instancer.instantiateVariableFont(font, {"wght": (400, 700)},
 *                   updateFontNames=True)
 *            2. pyftsubset <上の出力> --flavor=woff2
 *                   --name-IDs=0,1,2,3,4,5,6,13,14 --unicodes=<下の集合>
 *          作り直したら tests/test_static_assets.py の sha256 も同じコミットで
 *          張り替える。
 *
 * latin と japanese の2つに割るのは Google 自身の latin unicode-range で、
 * **範囲は重ならない**（テストが計算で確かめている）。日本語の字が1つも無い画面は
 * 24KB で済み、1.92MB を落とさない。
 *
 * japanese 側は CP932（Windows-31J = JIS X 0208 ＋ NEC/IBM 拡張）と、この画面群が
 * 使う記号ブロックを収録する。生徒の名前の 髙 / 﨑 / 德 が fallback ではなく本物の
 * 書体で出るのはこのため。宣言している U+4E00-9FFF はファイルの中身より意図的に
 * 広い: unicode-range が決めるのは**どのファイルを落とすか**であって、8,410 個の
 * codepoint をここに書き並べても読めるものにならない。CP932 より珍しい漢字は
 * --font-family-base の次の家族に落ちる。
 */

@font-face {
  font-family: "Noto Sans JP";
  font-style: normal;
  /* 1本で 400〜700 を担う。ここを単一の値にすると、ブラウザは残りの太さを
     合成する（偽ボールド）ので、見出しが本物の Bold でなくなる。 */
  font-weight: 400 700;
  /* **swap ではなく optional**（PM 2026-08-31）。swap は「間に合わなくても、届いた
     瞬間に差し替える」なので、cache が無い1回目は必ず一瞬 Hiragino で描かれてから
     入れ替わる。実測でその差は 59ms（FCP 1208ms / 日本語 font 1267ms）。preload で
     400〜550ms から縮めたが、1.92MB は最初の描画に間に合わない。

     optional は「間に合わなければ、その1回は fallback のまま**最後まで**通す」。
     入れ替わりが起きないので、ちらつきは仕様として消える。

     払う代償は1画面だけ: **まっさらなブラウザで最初に開く画面＝ログイン**が
     Hiragino で出る。その裏で font は落ち終わって immutable で cache されるので、
     ID とパスワードを打ち終えた次の画面から先は、最初の描画から Noto になる。
     日々使う画面が fallback で出ることはない。 */
  font-display: optional;
  src: url("../vendor/fonts/noto-sans-jp-2.004-var-latin.dc7b79d100c9.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: "Noto Sans JP";
  font-style: normal;
  font-weight: 400 700;
  /* **swap ではなく optional**（PM 2026-08-31）。swap は「間に合わなくても、届いた
     瞬間に差し替える」なので、cache が無い1回目は必ず一瞬 Hiragino で描かれてから
     入れ替わる。実測でその差は 59ms（FCP 1208ms / 日本語 font 1267ms）。preload で
     400〜550ms から縮めたが、1.92MB は最初の描画に間に合わない。

     optional は「間に合わなければ、その1回は fallback のまま**最後まで**通す」。
     入れ替わりが起きないので、ちらつきは仕様として消える。

     払う代償は1画面だけ: **まっさらなブラウザで最初に開く画面＝ログイン**が
     Hiragino で出る。その裏で font は落ち終わって immutable で cache されるので、
     ID とパスワードを打ち終えた次の画面から先は、最初の描画から Noto になる。
     日々使う画面が fallback で出ることはない。 */
  font-display: optional;
  src: url("../vendor/fonts/noto-sans-jp-2.004-var-japanese.684b8b1eae55.woff2") format("woff2");
  unicode-range: U+0370-03FF, U+0400-04FF, U+2100-2121, U+2123-2190, U+2192,
    U+2194-2211, U+2213-2214, U+2216-23FF, U+2460-24FF, U+2500-257F, U+25A0-25FF,
    U+2600-26FF, U+2700-27BF, U+3000-30FF, U+31F0-31FF, U+3200-33FF, U+4E00-9FFF,
    U+F900-FAFF, U+FF00-FFEF;
}

:root {
  /* The prototype's 12 properties. tools/tailwind/src.css maps these into
     Tailwind's theme with @theme inline, so bg-primary and text-[var(--muted)]
     resolve to the same values the rules below use. */
  /* The PAGE ground, painted once on body (app.css). White since the exams
     flow review (PM, 2026-08-16): the cards on it are separated by a hairline
     --border, so a grey ground under a white card only adds a second edge.
     --background below stayed the faint FILL it also was, because a zebra row,
     a disabled button and a sticky grid head all read it that way. */
  --page-bg: #ffffff;

  /* The faint fill: zebra rows, disabled controls, sticky heads, tab strips.
     Not the page ground any more — that is --page-bg. */
  --background: #f8fafc;
  --card-bg: #ffffff;

  /* The DATA TABLE's heading row (components/grid.html). Picked by the teachers
     on 2026-08-23, by hex: they wanted the row of column names to read as the
     table's own furniture rather than as a first, paler row of data.

     Its own token and not --accent, which is a step off it (#eff6ff) and means
     something else — --accent is "this one is selected". Two values that happen
     to look alike must not become one name, or moving the selection tint moves
     every table heading with it. Not --background either, which is the value
     this replaces and is still what a disabled control and a sticky panel wear.

     It costs one thing, and .c-grid__cell--head pays it: --muted is 4.26:1 here,
     under the 4.5 body floor, so the heading row holds a darker grey of its own.
     A column name is the label a whole column is read through — it is the last
     text on the screen allowed to be borderline. */
  --grid-head-bg: #eef3f8;
  /* The height of the OPTIONAL upper heading row (components/grid.html
     header_groups). The second row's sticky offset is this value: a sticky
     offset cannot be measured off a sibling, so the row is given a height
     instead of taking one. */
  --grid-group-row-h: 2.25rem;
  /* The two columns 取込プレビュー keeps in place while the 科目 scroll past
     (components.css .c-grid__cell--pin). Fixed, because a sticky `left` offset
     cannot be measured off the column beside it — and because .c-grid sizes
     columns to their content, so without these the second one would drift.
     Wide enough for 「3年12組40番」 and a full 氏名; longer text wraps rather
     than being cut, which keeps the width — and the offset — exact. */
  /* A column whose 科目 the teacher has changed and not yet confirmed
     (取込プレビュー). Orange, and NOT --warning: warning already means 未対応 on
     the same table, and two states in one hue would be one state.

     A rim and a fill, never the text colour: the box holds a 科目名 a person
     reads, and the ink stays ink — 10.3:1 on the fill below.

     Colour is not the only carrier here (WCAG 1.4.1): the value in the box has
     visibly changed, and a line above the table says the marked ones are not
     saved yet. */
  --pending-mark: #ffbe0b;
  --pending-bg: #fef29b;

  /* And the row this import will not write. Its own token rather than
     --danger-bg: that one is the app's error fill, on eight other screens, and
     a row of a table is not an error message. Both pairs are lifted from the
     alert component the PM chose (2026-08-29) — the pale kind, so a whole row
     can carry it without shouting over the numbers on it. */
  --refused-bg: #febab6;
  /* The rim on a control inside that ground. */
  --refused-mark: #ff0700;

  /* A 志望校 this import WOULD change (取込プレビュー・ADR-037). The opposite of
     --refused-bg and deliberately quieter than it: most of that table is rows
     that already agree with the master, so what is marked here is the handful a
     teacher is actually deciding about — not a warning. */
  --changed-bg: #e8f4fd;

  /* The focus halo for each state of that control. A HALO, not a second
     outline: the control already wears a rim, and the global blue outline sat
     outside it as a separate ring — two frames around one box (PM, 2026-08-29).
     Same trick --warning-halo uses for the 配点 field: the colour is the
     control's own and focus is marked by AREA. */
  --refused-halo: rgba(255, 7, 0, 0.28);
  --pending-halo: rgba(255, 190, 11, 0.4);
  --select-halo: rgba(30, 41, 59, 0.22);

  --grid-pin-1: 9rem;
  /* 氏名（CSV）. The 個人成績表 prints a name in KATAKANA, which runs about twice
     the character count of the same name in kanji — 12 full-width characters at
     --font-size-caption1 is 144px, and the column held 128. The name ran under
     the next column, which is the one place on this screen a teacher is checking
     one name against another. */
  --grid-pin-2: 11rem;

  /* The INK, and only the ink. 13.98:1 on --background, 14.63:1 on --card-bg.

     Navy #032b43 until 2026-08-23. It was the school's own colour, but it was
     also --primary, which meant the text, the buttons, the active tab and every
     icon were one value: a screen with a single dark tone and nothing on it able
     to stand out. Splitting the two is the whole of this change (see --primary).

     Slate rather than a lighter navy because the rest of the file was already
     written against it — the 偏差値 band ramp below records its ratios against
     #1e293b, and every one of the seven now measures exactly what it claims to
     again. Those numbers were right when the demo was ported and went stale when
     the ink moved; they were never re-measured. */
  --foreground: #1e293b;

  /* 4.55:1 on --background, 4.76:1 on --card-bg. Both clear the 4.5 body floor,
     and the first one only just — so this is the value --background may not get
     any lighter under, and a screen that wants quieter text than this has to
     want a smaller job for it instead. */
  --muted: #64748b;
  /* 本文の2番目。--muted より1段濃く、--foreground より薄い——「読ませる字だが
     題ではない」ところ（PM 2026-09-20: 志望校の画面の説明文がここへ移った）。
     --muted は、そこからさらに落として「添える字」に残す。 */
  --foreground-secondary: #475569;

  /* The ACCENT. The primary button, the active tab, "you are here", the sorted
     column's mark. 4.94:1 on --background, 5.17:1 on --card-bg; white on it is
     5.17:1, which is what the primary button is.

     Blue, from 2026-08-23. The school looked at the three candidates on six
     screens side by side and picked this one — the reference design's own
     #2563eb (ADR-020's prototype), which is also --chart-series-1, so the
     headline series and the primary control have been the same value all along
     and only now say so.

     This supersedes the 2026-08-16 decision that put the palette's navy here.
     The navy is not gone: it was always the INK's job, and --foreground keeps
     doing it. */
  --primary: #2563eb;
  /* 3.52:1 on --background, 3.68:1 on --card-bg — graphical objects and borders
     only (WCAG 1.4.11 wants 3:1), never a letter. The focus ring and a hovered
     card's edge. */
  --primary-light: #3b82f6;
  /* The pressed and hovered primary. 6.70:1 on --card-bg, so it is also readable
     as text — which is why --link below is this same value rather than a third
     blue nobody can tell from the other two. */
  --primary-dark: #1d4ed8;
  /* The accent FILL: selected rows, the sticky grid head's tint, a chip's
     ground. Now the blue's own faintest step rather than a neutral one — with a
     blue --primary, a grey-blue fill under it read as two different families. */
  --accent: #eff6ff;

  /* Decorative: card frames, table rules, separators. 1.23:1 on --card-bg, which
     is below 1.4.11's 3:1 — so it is never the boundary that identifies a
     control. That job belongs to --border-strong below.

     The reference design's own slate-200. It was #e1e7ee, the same grey mixed
     towards the old navy; with the ink on slate now, that tint pulled the frames
     one hue away from everything they framed. Identical in weight — 1.23:1
     either way — so nothing that was legible stopped being. */
  --border: #e2e8f0;

  /* The status three, from the reference design and held to the body floor.

     The school's 2026-08-16 family (D00000 · FFBA08 · 3F88C5 · 032B43 · 136F63)
     stood here until 2026-08-23. Its navy moved to --foreground and its blue to
     --primary's family; these three moved to the reference design's, because a
     screen carrying a blue primary and a teal "confirmed" reads as two products.

     All three are TEXT (text-[var(--success)] ×30, --danger ×21, --warning ×9),
     so each is the reference's colour NUDGED to clear 4.5:1 — and each is nudged
     against the fill it actually sits on, not against white. That distinction is
     not academic: the reference's red clears on white (4.83:1) and fails on its
     own badge (#dc2626 on #fef2f2 is 4.41:1), which is where this app puts it. */
  /* NUDGED from the reference's #16a34a (3.15:1 on its fill — tools/tailwind/
     src.css already recorded that). 5.02:1 on --card-bg, 4.79:1 on its own
     #f0fdf4 fill; white on it is 5.02:1. */
  --success: #15803d;
  /* NUDGED from #dc2626, which fails on the fill it is used on. 6.47:1 on
     --card-bg, 5.91:1 on its own #fef2f2 fill. */
  --danger: #b91c1c;
  /* NUDGED from the reference's #f59e0b (2.15:1 on white — it cannot be a
     letter). 5.02:1 on --card-bg, 4.80:1 on --background, 4.84:1 on its own
     #fffbeb fill. */
  --warning: #b45309;
  /* The unnudged #f59e0b, for the places warning is a MARK and not a letter:
     the dot on a chip, a card's edge, an input's outline. Text on it is
     --foreground, 6.81:1. */
  --warning-mark: #f59e0b;

  /* The blue as a GRAPHICAL object — the focus ring, a box drawn on a scan, a
     chart stroke. 3.68:1 on --card-bg (1.4.11 wants 3:1), never a letter. An
     alias now rather than a sixth blue: it and --primary-light are the same
     thing said twice, and the two drifting apart is how an app ends up with a
     focus ring that does not match the control it rings. */
  --blue: var(--primary-light);
  /* The one place the blue has to be READ. 5.17:1 on --card-bg.

     An alias for --primary, not a sixth blue: a link and the primary control are
     the same colour saying the same thing ("this does something"), and the two
     drifting apart is how #2a669a and #3f88c5 ended up looking like a mistake
     beside each other. A link DARKENS on hover, to --primary-dark — which only
     works while the resting state is the lighter of the two. */
  --link: var(--primary);

  /* "A teacher has confirmed this" — the sky the school picked for the state a
     question card and its box on the paper share, so one question is one colour
     wherever it appears. 2.13:1 on white: a fill, an edge and a dot, never a
     letter; the label on it is --foreground. --success stays the stepper's
     "this step is done", which is a different sentence. */
  --confirm: #48bfe3;
  --confirm-bg: #eaf7fb;

  /* The focus halo for a control that is ITSELF yellow (a 配点 waiting for its
     number). The global --focus-ring is the blue, which lands as a blue box
     around a yellow one; this keeps the control one colour and marks focus by
     the halo's AREA instead. --warning-mark at 30% — the ring is 3px, so the focused
     state is unmistakable beside an unfocused neighbour even though the amber on
     white is only 2.15:1. */
  --warning-halo: rgba(245, 158, 11, 0.3);

  /* 「この枠はいま私の手の中にある」——用紙の上で掴んでいる枠、そして位置合わせで
     引き直した枠（exam_setup.css .es__box--active）。

     黄（--warning-mark、PM 2026-08-24）。ここは --confirm の水色だった——「確認済」の
     カードと同じ色で「いまこの設問」を言うつもりだったが、掴んでいない枠は --primary の
     青なので、紙の上には濃い青と薄い青の枠が並んだ。2px の線と小さな札では、どちらも
     ただ「青」に見える——そしてその2つを見分けることが、この画面の仕事そのものだった。
     紫を一度試し、色は分かれたが「編集中」には見えないと戻された（PM）。黄は書類に
     引く蛍光ペンの色で、「ここに手を入れている」を説明なしで言う唯一の色。

     六番目の色は作らない——アプリが既に持っている黄をそのまま借りる。--warning ではなく
     --warning-mark なのは、これが文字ではなく印だからで、その定義どおりの使い方:
     線と札の地に使い、上に載る番号は --foreground（黄の上で 6.81:1）。

     線そのものは白紙の上で 2.15:1 と 1.4.11 の 3:1 に届かない。届かせるために色を
     濁らせるより、状態を線だけに担わせないほうを選んだ——番号の札は黄で塗りつぶされ、
     中は黄のベールが敷かれるので、「掴んでいる」は面で読める。 */
  --picked: var(--warning-mark);
  --picked-veil: rgba(245, 158, 11, 0.14);

  /* A card's own edge states it: waiting (--warning-mark at 45%) or confirmed
     (the sky at 40%). Hairlines, so they sit under 1.4.11's 3:1 on purpose — the
     word in the card says the same thing, and hover raises each to its full
     colour. */
  --line-todo: #fad391;
  --line-done: #b6e5f4;

  /* The chart series palette — CATEGORICAL, and deliberately not the status
     colours above.

     A line per 科目 walking --success / --danger paints 英語 green and 国語 red,
     and a teacher reads a verdict the data never gave: on this screen the only
     thing separating one 科目 from another is which one it is. The prototype
     keeps its own chart map for exactly this reason
     (dashboard/students/[id] chartColors), and these are its values — the first
     is --primary because the headline series there is 総合.

     Contrast is not measured on these: they are 2px strokes and 4px points, which
     WCAG 1.4.11 treats as graphical objects against --card-bg, and each is read
     with its own legend label beside it rather than by hue alone.

     Six is where a palette stops being distinguishable; a seventh series wraps
     rather than invents one. */
  --chart-series-1: #2563eb;
  --chart-series-2: #8b5cf6;
  --chart-series-3: #f97316;
  --chart-series-4: #14b8a6;
  --chart-series-5: #ec4899;
  --chart-series-6: #3b82f6;

  /* The REFERENCE a series is read against — 合格最低点の水準 and its like. Not
     part of the walk above: it is not another series, it is the thing the series
     is measured by, and it has to be told apart from the data at a glance rather
     than by reading a legend.

     Orange because the data is blue. It sat at --primary-light (a second blue)
     and then at --muted (a grey too faint to find), and both were reported as
     unreadable — this is the complement of --chart-series-1, which is as far
     from it as the wheel goes. Green and red are the two it may NOT be: a
     threshold is not a verdict, and this app never paints one (ADR-007). */
  --chart-reference: #f97316;

  /* A bar is an AREA; a line is a 2px stroke. --chart-series-1 at full strength
     reads as a series when it is a stroke and as a slab when it fills a bar, and
     a slab swallows whatever is drawn over it — which is exactly what the
     reference line is. So a bar takes this tint as its FILL and keeps
     --chart-series-1 as its edge: same series, same identity, less ink.

     #93c5fd is the prototype's own blue-300, two steps below the series colour.
     One tint, because every bar chart in the app draws a single series today; a
     multi-series bar chart needs a ramp here and there is no reason to invent
     one before the screen that asks for it exists. */
  --chart-bar-fill: #93c5fd;

  /* 添削のホームの「ホーム」タブ（correction/student/home.html）。**科目ではない**ので
     --chart-series-* からは取らない: あの並びは「別の系列」としか言っておらず、
     ここは「全部」を指す製品の色である。生徒の shell の --brand（#00bc7d）とは
     6/255 だけ違う——PM が指定した値がこちらで（2026-09-10）、値の置き場は
     tokens.css の1箇所という決まりに従ってここに置いてある。 */
  --tensaku-home: #06bc7d;

  /* The 偏差値 band ramp — 科目ごとの散らばり (#191 follow-up).

     Not --chart-series-*: that palette is CATEGORICAL and says only "a different
     series". These seven say WHERE on the scale, and they diverge about 50,
     because 50 is the 偏差値's real midpoint and not an arbitrary one. Walking
     the categorical six here would paint 45〜50 pink and 50〜55 orange and tell a
     teacher nothing about which is the low end.

     The two hues are the reference the school picked for data on 2026-08-13
     (danluu.com's own chart palette): #e41a1c below 50, and above it #377eb8 —
     the `--resume` blue of that palette's 「Medium iteration paths vs. Ultra」
     figure, picked by the school on 2026-08-14. It replaces #1a365d, which was
     the same palette's `--static`: navy survives a 12% tint as a grey, and a
     teacher reading 65以上 in grey was told a good score is a dull one. Every
     value below is its hue composited over --card-bg #ffffff at a stated
     strength, so the ramp is reproducible rather than eyeballed.

     A band is a FILL with a head-count printed on it, so each is measured
     against --foreground #1e293b, which is the text that sits on it. Blue tints
     lighter than navy at the same strength, so the four steps are spread wider
     (14/32/50/70) to keep 65以上 the heaviest step on the scale — at 70% it is
     still 5.57:1, further from the 4.5 floor than the navy it replaces. */
  /* #e41a1c at 45% — 6.80:1 with --foreground. */
  --viz-band-1: #f39899;
  /* #e41a1c at 28% — 9.17:1. */
  --viz-band-2: #f7bfbf;
  /* #e41a1c at 12% — 12.09:1. */
  --viz-band-3: #fce4e4;
  /* #377eb8 at 14% — 12.33:1. */
  --viz-band-4: #e3edf5;
  /* #377eb8 at 32% — 9.75:1. */
  --viz-band-5: #bfd6e8;
  /* #377eb8 at 50% — 7.52:1. */
  --viz-band-6: #9bbedc;
  /* #377eb8 at 70% — 5.57:1, the floor this ramp stops at. */
  --viz-band-7: #73a5cd;

  /* クラスの強み・弱み's two directions. The reference the school picked for data
     on 2026-08-13 (danluu.com) rather than --success / --danger: those are the
     STATUS colours, and 「学年より上」 is a position, not a verdict. The 科目別
     table's 差 cell used the status pair for this number and is gone with the
     table, so nothing on the screen colours it the other way any more.

     Two values per direction, because the same colour does two jobs here. The
     BAR is a graphical object read with its own legend label beside it (the
     same reasoning --chart-series-* records), so it carries the reference hue.
     The number at its tip is TEXT and is held to 4.5:1 — and #38b2ac reaches
     only 2.58:1 on --card-bg, so the ink is the same hue taken darker. */
  --viz-above: #38b2ac;
  /* #38b2ac darkened until it clears the body floor — 5.14:1 on --card-bg. */
  --viz-above-ink: #1a7a75;
  /* 4.71:1 on --card-bg, so the fill and the ink can be the one value. */
  --viz-below: #e41a1c;
  --viz-below-ink: #e41a1c;

  /* 成績マトリクスの ▲ — 「前回より上がった」を帯の上で言う印（学校からの指摘,
     2026-08-18）。上の teal ではなく緑なのは、読めないからである: セルの地は 50以上が
     青の帯（--viz-band-4〜7）で、#38b2ac はその上でほぼ消える（band-7 で 1.02）。

     鮮やかな緑（#16a34a）を選び、暗く沈めた緑（#1b5e20, band-7 で 3.00）は採らなかった
     ——10px の字画では黒に見えて、「上がった」の合図にならない。縁取りも付けない: 印が
     紙に載ったシールのように見える（PM, 2026-08-18）。

     残るトレードは測って受け入れたもの。65以上の帯の上でだけ 1.25 に落ちるが、その
     セルが表す数字は title と 前回差 の列にそのまま出ている。 */
  --viz-move-up: #16a34a;

  /* The row 成績マトリクス has a カルテ open for. Translucent on purpose — it lies
     over the band fills, and an opaque mark would take the 偏差値's colour off
     the row a teacher is looking at, which is the one row they most need to
     read. The only rgba in this file, and it is here for that reason.

     Orange because nothing else on these screens is: the bands are red↔blue, the
     directions teal/red, so a warm wash cannot be read as a value. #ff7f00 at 9%
     is the reference layout's own (danluu.com palette, 2026-08-13).

     Measured over every band against --foreground, which is the text that sits
     on it: the darkest step (--viz-band-7) goes 5.57 → 5.44, and the whole ramp
     stays over 4.5. The mark is redundant anyway — the panel beside it names the
     student — so it is a confirmation, never the only way to know. */
  --viz-picked: rgba(255, 127, 0, 0.09);

  /* The 0 line of クラスの強み・弱み. The four ticks beside it are --border, this
     app's own hairline; the axis is that same neutral taken darker, because 0 is
     what every bar in the figure is measured from and a tick that happens to sit
     in the middle does not say so.

     NOT --border-strong (= --muted, 4.76:1). That is the weight WCAG 1.4.11 asks
     of a form CONTROL's boundary, and drawn down the middle of a chart it reads
     as a black bar rather than as the strongest of five gridlines. 1.4.11 is not
     what applies here: the figure prints its own scale under the bars and the
     value at each bar's tip carries its own sign, so no reader depends on seeing
     this line to know which side of 0 a 科目 is on.

     An ALIAS and not a second literal — slate-400 is the step this file already
     holds, the same way --scrollbar-thumb-hover takes it. */
  --viz-axis: var(--foreground-disabled);

  /* 設置区分 — the bar colours of 志望校の集まり. Three values from the same
     reference palette (danluu.com, picked 2026-08-13), and CATEGORICAL: 国立 and
     私立 are two kinds of school, not two ends of a scale, so this is not the
     band ramp above and must not be read as one.

     Not --chart-series-*: those six are "a different series" and carry no
     meaning of their own, whereas these three name a thing a teacher already
     knows, and 国立 has to stay the same colour on every screen that draws it.

     The three are separated by LIGHTNESS as well as hue — 12.14:1, 4.34:1 and
     2.58:1 on --card-bg — so they stay three different bars in greyscale and for
     a red-green deficiency. That matters more here than each one's own contrast
     with the card, because these bars are compared with each other. They are
     also never the ONLY carrier of the 設置区分: each bar states it in its
     accessible name, and the count beside it is --foreground text.

     設置区分 not stated on the master row is drawn as an OUTLINE rather than a
     fourth colour (home.css .home-asp__bar--unknown). A grey light enough not to
     compete with the three would sit at the same lightness as the teal, and "not
     recorded" reading as "no ink" is the honest picture anyway. */
  --viz-founding-national: #1a365d;
  --viz-founding-public: #377eb8;
  --viz-founding-private: #38b2ac;

  /* The roles the prototype expresses as Tailwind utility classes rather than as
     properties of its own. Each is named for the job it does, not for the value
     that fills it today: --border-strong is the boundary that identifies a
     control, and it only happens to equal --muted. Until #137 these lived in a
     bridge layer under --color-* names, aliasing the twelve above one-for-one;
     that layer went when its last reference did, and the names that survived are
     the ones that mean something the palette does not already say. */

  /* slate-400, 2.56:1 on --card-bg. The prototype has no disabled colour — it
     dims with disabled:opacity-50/60 — and WCAG 1.4.3 exempts inactive
     components from the contrast requirement. */
  --foreground-disabled: #94a3b8;
  --primary-foreground: #ffffff;

  /* The scrollbar thumb (tools/tailwind/src.css ::-webkit-scrollbar-thumb).
     slate-300, and its own value rather than a reuse: --border at 1.23:1 is too
     faint to aim at, and --border-strong is darker than any scrollbar on these
     screens. The hover state is an ALIAS and not a second literal — the
     prototype's two thumb greys are consecutive steps of one ramp, and the
     darker one is the grey this file already holds. */
  --scrollbar-thumb: #cbd5e1;
  --scrollbar-thumb-hover: var(--foreground-disabled);

  /* A line that has to be FOUND: 3.36:1 on --card-bg, 3.21:1 on --background —
     the lightest grey clearing WCAG 1.4.11's 3:1 with room to spare.

     It was --muted (slate-500, 4.76:1), the first step of the ramp over the
     line — slate-400 reaches only 2.56:1 and the retired Fluent #a9abb2 only
     2.29:1. It now sits between those two steps and so is its own value rather
     than an alias, because the ramp has none where the useful colour is.

     What it is no longer: the form-field border. Fields took --border on
     2026-08-23 (PM), which lowers 1.4.11 below its floor deliberately —
     components.css .c-field carries that decision and the reasoning. What still
     names this token is a line nobody chose to make quiet: the select's arrow,
     a dashed drop zone, the rules between columns in 進路指導's tables, the
     numbered step on the 採点 pipeline. */
  --border-strong: #7d8ea1;
  /* The blue, not the ink: a navy ring on a navy button is not a ring. */
  --focus-ring: var(--blue);

  /* Status fills and borders come from the prototype's own badge classes. The
     three colours themselves are --success / --warning / --danger above, and
     each fill is the one its colour was measured against — move a fill here and
     the ratio recorded up there stops being true. */
  --success-bg: #f0fdf4;
  --success-border: #bbf7d0;
  --warning-bg: #fffbeb;
  --warning-border: #fde68a;
  --danger-bg: #fef2f2;
  --danger-border: #fecaca;
  /* The prototype has no info status: .highlight-info is primary on accent
     (4.75:1), and its border is the blue-200 the prototype uses elsewhere. All
     three members are kept even though two are aliases, so a screen spells the
     fourth status exactly like the other three.

     --info is --primary now rather than --link: on a fill this pale the two are
     one step apart, and the one that matches the button beside it is the one to
     use. */
  --info: var(--primary);
  --info-bg: var(--accent);
  --info-border: #bfdbfe;

  /* Decorative tints — 資料管理's five document kinds, and nothing else in the
     app may name them.

     This is the one place the file holds a hue that means NOTHING. Telling
     模試成績表 from 出席・学習記録 at a glance is worth a colour, and the status
     palette cannot lend one: a card painted --success says the upload went well,
     which is a sentence about something that has not happened yet. The rule this
     replaces said no sixth hue may be invented for decoration, and it held the
     screen to one coloured tile beside four grey ones — because four of the five
     kinds have no importer yet and there were only ever five semantic colours to
     go round. The school lifted it on 2026-08-23 with the palette.

     Each pair is a reference-design hue and its own faintest step. All five
     clear the 4.5 BODY floor on their own fill, not merely 1.4.11's 3:1 — which
     is what lets 対応形式 be written in the card's own colour instead of grey.
     The pink is a step darker than the reference's #db2777 for exactly that
     reason: at 4.21:1 it was a mark and not a letter.

     A sixth kind takes one of these again rather than adding a hue. Past five
     nobody tells them apart, and the label beside the tile is what actually
     names the card. */
  /* 4.75:1 on its fill. */
  --deco-blue: #2563eb;
  --deco-blue-bg: #eff6ff;
  /* 5.02:1. */
  --deco-purple: #9333ea;
  --deco-purple-bg: #faf5ff;
  /* 5.21:1. */
  --deco-emerald: #047857;
  --deco-emerald-bg: #ecfdf5;
  /* 4.84:1 — the same pair --warning uses, because amber is amber. */
  --deco-amber: #b45309;
  --deco-amber-bg: #fffbeb;
  /* 5.53:1. NUDGED from the reference's #db2777 (4.21:1). */
  --deco-pink: #be185d;
  --deco-pink-bg: #fdf2f8;

  /* 予定と試験の種別色 — 7つ（PM, 2026-09-17）。6つは「これは何の日か」を言い、
     最後の1つ（自分の予定）だけが「これは誰が書いたか」を言う。
     カレンダーが最初に使い、成績票・試験一覧・志望校もこの名前を使う。色を
     替えるならここだけを替える。

     上の装飾色とは別に持つ。あちらは資料管理の5種類が名指しで持っているもので、
     意味を持たないと書いてある。こちらは意味そのもの——「模試」の色は、模試が
     出てくる画面すべてで同じでなければならない。

     **7つは色覚の上限を超えている。** 21組を OKLab ΔE×100 で、正常と Machado
     2009 の3型ぶん測った: いちばん弱い組が 4.6（受験と模試、3型）。8以上が目標、
     6〜8が「色だけに頼らなければ可」の帯なので、下を回っている組がある。だから
     **札は必ず字を連れて歩く**——`.c-kind` は字を描く箱で、色だけの札を作れない
     形にしてある。印（5pxの点・3pxの帯）は、必ずその字の近くにしか置かない。

     測った上で、**弱い組は同じ話の中に寄せた**。いちばん近いのは 出願 と 受験
     （正常 10.7）で、この2つは昨日まで同じ1色だった——生徒にとっては「大学に
     出して、受けに行く」一続きの話である。種別をまたぐ組は 13.6 以上。

     **7つとも地の色で、字の色ではない。** 渡された7色は彩度が高く、白の上の字に
     すると4つが 4.5:1 を切る（橙 3.03 / 青 3.09 / 桃 3.02 / 黄 1.43）。地にして
     字をその上に乗せると7つとも floor を超えるので、**hex は1つも動かしていない**
     ——各色の字を白か --foreground のどちらにするかだけを、測って決めてある。 */
  /* 出願 — 逃すとその年が終わる締切。白字 4.50:1。 */
  --kind-apply: #ec111a;
  --kind-apply-ink: #ffffff;
  /* 受験 — 試験の当日。出願と同じ暖色に置いてある（上記）。濃い字 4.83:1。 */
  --kind-sit: #fb6330;
  --kind-sit-ink: var(--foreground);
  /* 定期テスト。白字 6.10:1。 */
  --kind-teiki: #7849b8;
  --kind-teiki-ink: #ffffff;
  /* 実力テスト。濃い字 10.25:1 — 7つでいちばん読みやすい札である。 */
  --kind-jitsuryoku: #ffd42f;
  --kind-jitsuryoku-ink: var(--foreground);
  /* **印だけの例外。** 5px の点と 3px の帯は字を持たない図形なので、白地に対して
     1.4.11 の 3:1 が要る。この黄色は白に対して 1.43:1 で、点にすると消える。
     明度だけを 40% 落として 3.02:1 にした値で、色相と彩度は上のまま——札の地は
     渡された #ffd42f のままである。他の6色は地のままで 3:1 を超えている。 */
  --kind-jitsuryoku-mark: #b59000;
  /* 模試。濃い字 4.84:1。 */
  --kind-moshi: #f2609e;
  --kind-moshi-ink: var(--foreground);
  /* 学校行事。濃い字 4.73:1。 */
  --kind-school: #009dd6;
  --kind-school-ink: var(--foreground);
  /* 自分の予定 — **生徒が書いたものは全部これ**（PM 2026-09-18）。活動記録も
     ここに入る: どちらも生徒が打った字で、学校から降ってきた予定ではない。
     別の色にしていた頃は、同じ人が同じ画面から入れた2つが、盤の上で別の話に
     見えた。緑は活動が持っていた色である。白字 4.64:1。 */
  --kind-mine: #138468;
  --kind-mine-ink: #ffffff;

  --font-family-base: "Noto Sans JP", "Hiragino Kaku Gothic ProN", "Hiragino Sans",
    "Yu Gothic UI", Meiryo, system-ui, sans-serif;
  --font-family-mono: ui-monospace, SFMono-Regular, Menlo, Consolas,
    "Noto Sans Mono", monospace;

  /* Fluent 2 type ramp. */
  --font-size-caption2: 10px;
  --line-height-caption2: 14px;
  --font-size-caption1: 12px;
  --line-height-caption1: 16px;
  --font-size-body1: 14px;
  --line-height-body1: 20px;
  --font-size-body1-strong: var(--font-size-body1);
  --line-height-body1-strong: var(--line-height-body1);
  --font-size-subtitle2: 16px;
  --line-height-subtitle2: 22px;
  --font-size-subtitle1: 20px;
  --line-height-subtitle1: 28px;
  --font-size-title3: 24px;
  --line-height-title3: 32px;
  --font-size-title2: 28px;
  --line-height-title2: 36px;
  --font-size-title1: 32px;
  --line-height-title1: 40px;
  --font-size-large-title: 40px;
  --line-height-large-title: 52px;
  --font-size-display: 68px;
  --line-height-display: 92px;

  /* Noto Sans JP ships 400 / 500 / 700 — Fluent's 600 "strong" maps to 700. */
  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-strong: 700;

  /* Spacing — 4px base. */
  --space-none: 0;
  /* Half a step, and the only one below the base. It exists for data grids
     (careers' university list, #211): a reference table a teacher scans column
     against column wants Excel's row height, and 4px of vertical padding on
     12px type is already 50% taller than that. Reach for it ONLY for cell
     padding and the gaps inside a grid header — a layout that wants 2px between
     two blocks is a layout that wants --space-xs. */
  --space-xxs: 2px;
  --space-xs: 4px;
  --space-s: 8px;
  --space-m: 12px;
  --space-l: 16px;
  --space-xl: 20px;
  --space-xxl: 24px;
  --space-xxxl: 32px;
  --space-xxxxl: 48px;

  /* A grid row, and the reason it is a token rather than padding.

     A row used to be as tall as its padding made it — 2px above and below 12px
     type, which came out at 21px. That is Excel's height, and it was chosen
     deliberately while the grid was meant to read as a spreadsheet. It no longer
     is (PM, 2026-08-23), and a height is now stated instead of accumulated, so
     one number moves the whole app's lists and every row is the same height
     whatever a cell happens to contain.

     ふつう is this value. The scale it belongs to is 32 / 40 / 52 — 詰めて for a
     table somebody reads a column of at a time, ゆったり for a short list on a
     wide screen. Only ふつう is defined because only ふつう is offered: the
     density control is not built, and a token nothing reads is a promise the
     next person has to check. */
  --grid-row-h: 40px;

  /* ONE corner for the whole app, and two named exceptions. Nothing else.

     --radius is it. Buttons, fields, cards, modals, panels, banners, tabs,
     chips, badges, avatars, dropdowns — everything that draws a box (PM,
     2026-08-10: 「テーブルデータ以外は全部同じ」). There is deliberately no
     second token holding the same number: this file used to carry --radius-card
     beside --radius-control, both meaning "the app's corner", and a second name
     for one value is the indirection #137 retired the colour bridge over. It
     also made the bug this replaces possible — the surfaces stayed at 0 while
     the controls moved to 6px, and every screen showed both.

     It supersedes #216's "every corner square". That decision was made when the
     alternative was rounded CARDS over square TABLES, which is two shape
     languages on one page; a single corner everywhere is not that.

     --radius-grid — square, for an edge that has to MEET something exactly. The
     name is historical: it was the data grid's furniture, back when the grid was
     a spreadsheet and its square cells asked for square furniture around them
     (PM, 2026-08-09). The grid stopped being that on 2026-08-23 and its frame,
     pager, menu and search box now take --radius with the rest of the app.

     What still names this token is not a table at all: the 出願条件との距離 bar's
     inner end, which starts AT the axis and would open a notch if it rounded;
     the 試験設定 row, a full-width band between two rules; the underline tab,
     whose tint must reach the edges of the strip it sits in. Square, and
     separately named because that is a DECISION, not a leftover — it must not
     follow --radius the day that number moves.

     --radius-circular — a PERCENTAGE, so it is a shape and not a size: "a circle,
     whatever this box measures". Exactly one thing on these screens genuinely is
     one — the DOT on the 出願条件との距離 band and the swatch tying each figure
     below it to that dot. A plotted point is round in every chart the app draws,
     and a squircle among them reads as a bug, which is how it was reported. A
     label, a chip or a badge naming this token is a mistake; a marker naming it
     is the point.

     No RULE writes a literal radius any more — that is what makes a change to
     any of these a one-line edit, and it is now true of tools/tailwind/src.css
     too (.card and .stat-card carried the prototype's 0.75rem until this). The
     one literal left is the scrollbar thumb's 3px, and it is not an exception
     worth naming: the thumb is 6px wide, so 3px is "half of me" rather than a
     corner anyone chose. A token would make it follow a number it must not. */
  --radius: 6px;
  --radius-grid: 0;
  --radius-circular: 50%;
  /* Both ends fully round, whatever the length — a pill (switch track, filter chip). */
  --radius-pill: 999px;

  --border-width-thin: 1px;
  --border-width-thick: 2px;

  /* The prototype's control transition (`transition: background 0.15s ease`).
     A duration is neither a colour, a size, nor a radius, so the token-purity
     test would not have caught it as a literal — it lives here because the rule
     this file states is that values live here. */
  --duration-fast: 0.15s;

  /* How far apart two things arrive when a group is revealed one item at a time
     (.c-doccards). Short on purpose: at 40ms five cards are all in within 160ms,
     which reads as one movement with a direction. Anything near 100ms and the
     last card looks late rather than last. */
  --stagger-step: 40ms;

  /* Picking a row up and putting it down (static/js/row-reorder.js). Both are
     short enough not to be waited on and long enough to be followed by the eye.
     The easings are decelerations — fast at the start, settling at the end,
     which is what a thing with weight does. The drop's is the stronger of the
     two because a released row should look like it is finding its slot rather
     than sliding to it; the numbers are react-beautiful-dnd's drop curve, which
     is the one everybody's hands are already trained on. */
  --duration-lift: 0.16s;
  --ease-lift: cubic-bezier(0.2, 0, 0, 1);
  --duration-drop: 0.22s;
  --ease-drop: cubic-bezier(0.2, 1, 0.1, 1);

  /* The content column, header and <main> alike (.site-column). Issue 131 dropped
     the cap for full width on the argument that a roster wants every pixel; #216
     put it back (PM) — what full width produced was a card stretched across
     1920px, and a table wider than the column has its own scroll box to live in.

     1344, not the prototype's 1280, since 2026-09-07 (PM): `box-sizing` is
     border-box, so this figure INCLUDES .site-column's own padding. That padding
     went from 16px to 48px a side, and had the cap stayed at 1280 the wider margin
     would have been taken out of the CONTENT — every table 64px narrower than the
     day before. 1344 = 1248 of content (exactly what 1280 − 2×16 gave) + 2×48 of
     margin, so the page's edge moves outward into space that was empty and nothing
     inside it changes width. Move the two together or not at all. */
  --layout-content-max-width: 1344px;

  /* How much vertical room is NOT available to a .c-solo card (components.css) —
     what the sticky header and <main>'s own padding-block take before the card
     gets to centre itself in the rest.

     Measured, like --layout-toast-top below and for the same reason: the header
     is content-driven, so its height is not derivable from a token. It is also
     APPROXIMATE — the two header bands are 74px and .site-main pads 16px a side,
     which is 106, and this is 96. Reserving 10px too few lets the box run 10px
     past the bottom, so the card sits 5px BELOW true centre — which is why it
     has gone unnoticed since 216e73f wrote it as `--space-xxxxl` twice. Kept at
     96 rather than corrected here: moving it moves the login screen, and this
     change is meant to leave that screen exactly where it is. Re-measure both
     numbers if the header gains a band. */
  --layout-solo-reserve: 96px;

  /* Where the floating flash region starts (components/toast.html). It has to
     clear the sticky header, whose height is content-driven — two bands, 74px
     as they stand — so this is a measured number rather than a derived one.
     Getting it wrong is cosmetic in one direction only: too large just floats
     the toasts lower, while too small puts them over the account menu, which a
     warning that waits to be dismissed would then block. Re-measure it if the
     header gains or loses a band. */
  --layout-toast-top: 90px;
  /* Standing notices (.c-float-stack). Measured, like the line above, and for
     the same reason — there is no way to ask CSS where a screen's header ends.
     Two things had to be cleared on the two screens that use it: the topbar,
     because 戻る lives in that corner and a notice that stays put may not
     cover a control, and the facts band under it, whose labels it sat on at
     168px. Below both, it lands on the empty right-hand half of the row the
     action buttons occupy. */
  --layout-float-notice-top: 250px;

  /* The sticky header's own height — the two bands, measured. Two comments in
     this file already quote 「74px」 in prose; this is that number given a name,
     so a rule that has to clear the header can say so instead of guessing.
     Re-measure it with the other two if the header gains or loses a band. */
  --layout-header-height: 74px;

  /* Five elevations, and the names say which is which (issue 132). The card
     shadow is the prototype's own, copied from .card in src.css — barely there,
     because a card is on the page rather than over it. */
  --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
  /* .stat-card's, which is --shadow-card's first layer and nothing else. It gets
     its own name rather than folding into --shadow-card because it IS a
     different value: pointing .stat-card at the two-layer shadow would deepen
     every stat card on the home screen, and that is a design change, not a
     de-duplication. Whether the prototype meant the two to differ is a question
     for the PM; until it is asked, the screens keep the shadow they have. */
  --shadow-card-flat: 0 1px 3px rgba(0, 0, 0, 0.04);
  /* .card-hover, the only card on these screens that answers the pointer: the
     same two-layer shape, deeper, and tinted rather than neutral — rgb(37 99 235)
     is --primary #2563eb, which is why a hovered card reads as leaning toward the
     cursor instead of just getting darker. Written out rather than mixed from
     var(--primary) at 10%/6%: this file's job is to hold values, and a
     color-mix() in a box-shadow would hide two of them behind arithmetic. */
  --shadow-card-hover: 0 4px 12px rgba(37, 99, 235, 0.1), 0 2px 4px rgba(37, 99, 235, 0.06);
  /* 飾りの accent と、それが光るときの輪。**読むものには載らない**——ロゴの印、
     カードの縁、hover の光。文字にも、押せることを示す枠にも使わない（それは
     --primary と --primary-light の仕事で、あちらには床がある）。

     床が無いぶん、生徒の shell はここに製品の色そのものを載せられる
     （html.shell-student の #00bc7d）。先生の側は --primary-light と同じ青で、
     カードの扱いだけが両方で揃う——同じ形、値だけ違う。

     輪を別の値として持つのは、影の中で色を混ぜないため（--shadow-card-hover の
     注記と同じ理由: box-shadow の中の color-mix() は値を算術の裏に隠す）。 */
  --brand: #3b82f6;
  --shadow-brand-glow: 0 0 0 3px rgba(59, 130, 246, 0.25), 0 6px 16px rgba(59, 130, 246, 0.18);

  /* 「いま選んでいる」タブの4つ。ヘッダの下線の帯（.c-navtabs--underline）と、
     区切りタブの丸（.c-tabs--segmented）が読む（components.css）。

       --tab-active-bg     丸の面。下線の帯もこれ
       --tab-active-bg-hover  押したときの面
       --tab-active-ink    丸の**上に載る**字（面との差が要る）
       --tab-active-label  下線のタブの字（面が無いので、白地の上で読まれる）

     この file の --primary は2つの仕事を兼ねている: 字として読まれる色と、面として
     塗られる色。青ではどちらも #2563eb で足りたので区別する理由が無かったが、緑では
     足りない。分けたのはその1点だけで、下の4行が先生の側で今までと同じ値を指して
     いるのはそのためである（1ピクセルも動かない）。 */
  --tab-active-bg: var(--primary);
  --tab-active-bg-hover: var(--primary-dark);
  --tab-active-ink: var(--primary-foreground);
  --tab-active-label: var(--primary);
  /* What floats over the page: menu panels, flyouts, the field-error bubble.
     Unchanged in value — it only stopped being called --shadow-card, which it
     never was. */
  --shadow-overlay: 0 1px 3px rgba(28, 29, 33, 0.08), 0 4px 16px rgba(28, 29, 33, 0.12);
  /* What is HELD, not merely floating: the row under a dragging finger. It has
     to read as picked up at a glance and against a striped table, which the
     overlay shadow does not — it is a panel shadow, and on a wide row it was
     invisible (reported 2026-08-12). The close, dark contact shadow is what says
     "off the surface"; the wide soft one gives it height. Both are darker than
     anything else here on purpose: this is the only element the pointer is
     carrying. */
  --shadow-lifted: 0 2px 4px rgba(28, 29, 33, 0.16), 0 12px 28px rgba(28, 29, 33, 0.22);
}

/* ── 生徒の shell ────────────────────────────────────────────────────────────
   同じ製品の2つ目の顔。**上のトークンを1つも消さず、accent だけ差し替える。**
   先生の画面が青、生徒の画面が緑（PM 2026-09-09）で、プロトタイプも2つの入口を
   そう塗り分けている（src/app/student は emerald、dashboard は blue）。

   どこに付くかは <html class="{{ shell }}">（core.context_processors.shell）。
   :root ではなく html.shell-student に書いてあるので、同じ session の同じ人が
   どの画面を開いても色は変わらない——画面ごとに決めると、生徒が 大学 を開いた
   瞬間に先生の色になる。

   **色は #00bc7d（PM 2026-09-10）。** ただしそれが載るのは --brand で、--primary
   ではない。この2つを分けるのは妥協ではなく、上の --primary / --primary-light /
   --border が青の側でとっくにしている区別と同じものである:

     #00bc7d は白に対して **2.47:1**。ロゴと飾りには十分で、文字には足りない
     （本文の床 4.5:1、図形の床 3:1 — WCAG 1.4.11）。この色をタブの文字や
     ボタンの地にすると、明るい教室の iPad で「緑がかった灰色」になる。

   なので同じ色相（H≈160）で3段を作り、役割ごとに配る。生徒が **見る** 緑は
   #00bc7d のままで、**読む** 緑がその濃い側にいる、という配り方である。

   グラフの1本目まで替えるのは、上の --primary の注記が言うとおり「見出しの系列と
   主要な操作は同じ値」だからで、そこだけ青のまま残すと、緑の画面に青い線が1本
   走ることになる。2本目以降（科目の色）は替えない: あれは「別の系列」としか
   言っておらず、青緑紫橙桃はプロトタイプの 理解度推移 と同じ並びである。 */
html.shell-student {
  /* 学校に見せる色そのもの。ロゴの印、カードの縁、その光——**読むものには載らない**
     ので床が無い（ロゴは WCAG 1.4.3 / 1.4.11 の対象外）。 */
  --brand: #00bc7d;
  --shadow-brand-glow: 0 0 0 3px rgba(0, 188, 125, 0.28), 0 6px 16px rgba(0, 188, 125, 0.22);
  /* タブの「いま」。**プロトタイプから実測した値をそのまま置いている**
     （hamagakuen-ai-edu.vercel.app/student/record を Chrome で読んだ、2026-09-10）:
     丸は #00bc7d に白字、下線の帯は #00bc7d の2px、そのタブの字は #009966。

     **ここは AA を下回る。** 白と #00bc7d の差は 2.47:1、#009966 と白地の差は
     3.65:1 で、本文の床（4.5:1）に届かない。一度は墨の字（5.91:1）にしてあったが、
     PM が見本を示して「見本どおりに」と決めた（2026-09-10）——この製品を選んだのは
     その見本で、色の軽さはそこで選ばれたものである。**知らずに落ちたのではなく、
     測ったうえで置いた**ことを、次に読む人のためにここに書いておく。戻すなら
     --tab-active-ink を var(--foreground)、--tab-active-label を var(--primary)
     にするだけで、他は動かない。

     押したときの #009966 は見本のパレットの1段（下線の字と同じ値）で、こちらが
     発明した色ではない。白との差は 3.65:1 で、静止時よりは上がる。 */
  --tab-active-bg: var(--brand);
  --tab-active-bg-hover: #009966;
  --tab-active-ink: #ffffff;
  --tab-active-label: #009966;
  /* 文字・ボタン・現在のタブ。4.74:1 on --background, 4.96:1 on --card-bg;
     白文字 4.96:1 — 青の 4.94 / 5.17 / 5.17 と同じところで本文の床を越える。 */
  --primary: #00805a;
  /* 3.56:1 / 3.73:1 — 図形と枠だけ。文字には使わない（青の --primary-light と
     同じ役割・同じ床）。 */
  --primary-light: #00976a;
  /* 押した状態と hover。6.01:1 / 6.29:1 なので、--link としても読める。 */
  --primary-dark: #006e4d;
  /* accent の FILL: 選択行、固定ヘッダの地、chip の地。#00bc7d を白へ薄めた段。 */
  --accent: #e9faf3;
  /* 一覧の見出しの帯（PM, 2026-09-15）。既定の #eef3f8 は寒色の灰で、緑の画面に
     灰色の帯が1本渡って見える。--accent と同じ段の緑にして、表がこの画面の一部に
     見えるようにする。

     **行の地は替えない。** `.c-grid` は zebra を持たず（components.css に理由が
     ある）、替えるよう求められたのも見出しのほうである。見出しの字は
     --foreground のままで、この地の上でも本文の床を大きく越える（13:1）。 */
  --grid-head-bg: var(--accent);
  /* --link と --info はここに書かない。上で var(--primary) を指しているので、
     --primary を替えた時点で一緒に動く——書けば、動かない2つ目の緑ができる。 */
  /* 見出しの系列——成績票の 総合 の線。**見本の実測値**（プロトタイプの
     全国SS（偏差値）推移 の stroke、2026-09-10）。

     --primary でも --brand でもない3つ目の値なのは、これが見本から採った線の色
     だからで、こちらで導いた色ではない。タブの #00bc7d より一段明るく、白との差は
     2.54:1（線は図形なので床は 3:1）。

     **凡例の字はこの色で書かれる**（static/js/chart-theme.js — 数点しか離れて
     いない線の図で、語そのものが色を持っていないと線と語の対応を目で取ることに
     なる）。見本の凡例も同じ作りで、同じ比である。 */
  --chart-series-1: #10b981;
  /* 棒の面。青の --chart-bar-fill #93c5fd と同じ濃さの緑。 */
  --chart-bar-fill: #8ce1c4;
  --shadow-card-hover: 0 4px 12px rgba(0, 188, 125, 0.12), 0 2px 4px rgba(0, 188, 125, 0.08);
}
