feat(appearance): add Calm/Signature visual style, readability mode, and chart palette (#1407)

* feat(appearance): add Calm/Signature visual style, readability mode, and chart palette

Turn the "too intense / italic headers hurt / the security graph fights my
eyes" feedback into a token-driven Visual style with Calm as the new default
and Signature one click back to the prior look.

- Heading family routes through a `.font-heading` utility driven by
  `--font-heading`/`--heading-style`: operational headings render upright in the
  interface face under Calm and italic Instrument Serif under Signature. Base
  rule sets family + style only, so each call site keeps its own weight/tracking
  and Signature stays a true no-op; the Calm lift is a `[data-headings="clean"]`
  descendant rule. Brand lockup, empty-state heroes, and onboarding stay serif.
- Severity charts resolve through `--sev-*` tokens with Muted, Heat, and
  Signature palettes; FindingsByType routes its series through the severity ramp
  plus a neutral so no brand-cyan sits next to rose. The risk trend flattens its
  gradient under Muted/Heat/reduced and keeps the gradient under Signature.
- Appearance settings gain Visual style cards, a Security visualization palette,
  a Readability master toggle, a Motion & effects group, and a "Reset to default"
  button (restores the Calm axes, disabled while readability is on). Contrast
  moves under Readability and Ambient glow under Motion & effects. A card is
  selected only while the stored sub-axes match its preset, so a custom
  combination de-selects both.
- The topbar Theme quick-switch swaps the interface/data font pickers for a
  Visual style switch and a Readability toggle (text size kept); its footer
  Settings link jumps straight to Appearance.
- Readability is a sticky master that forces the calm resolution and a contrast
  lift at apply time without mutating the stored sub-axes.
- New users default to Calm; any pre-existing persisted appearance state keeps
  the Signature look. The pre-paint script mirrors the store.
- SegmentedControl gains a `disabled` prop and a nullable value (no active
  segment for a custom combination, with a roving-tabindex keyboard anchor).
  Adds unit/component coverage for the store, migration, chart shape logic, the
  disabled control, the reset/de-selection, and the quick-switch.

* fix(appearance): migrate Blueprint serif headings and surface readability locks

- Migrate the two operational Blueprint headings (catalog tile name, drift-policy
  option title) from font-serif italic to the .font-heading utility; the first
  pass only covered font-display, so Calm still left these italic. font-serif and
  font-display both resolve to the same display face, so this is the same fix.
- Lock the Visual style cards under Readability (parity with the topbar switch and
  the on-screen guidance to turn Readability off to choose a style by hand).
- Lock the Border brightness slider under Readability and show its forced +0.03
  readout, since Readability overrides the stored value; dragging it previously
  appeared to do nothing.
- Correct the Appearance docs sentence for the topbar quick switch (it listed
  fonts; the quick switch now carries visual style, readability, and text size).
This commit is contained in:
Anso
2026-06-22 00:19:57 -04:00
committed by GitHub
parent 31aa1d2d37
commit 8d9e6574cc
39 changed files with 1191 additions and 166 deletions
+67
View File
@@ -84,6 +84,15 @@
--chart-2: var(--warning);
--chart-3: var(--destructive);
/* Severity / chart palette (Signature default = today's saturated semantics).
Colours only; per-palette fill/gradient/stroke live in JS (SecurityCharts).
[data-chart-style="muted"|"heat"] override these; signature needs no rule. */
--sev-critical: var(--destructive);
--sev-high: var(--warning);
--sev-medium: color-mix(in oklch, var(--warning) 52%, var(--stat-icon));
--sev-low: color-mix(in oklch, var(--stat-icon) 72%, var(--well));
--sev-vuln: var(--brand);
/* Sparkline / data-line styling (centralized) */
--data-line-width: 1.25px;
--data-peak: var(--warning);
@@ -224,6 +233,13 @@
--font-serif: 'Instrument Serif', Georgia, serif;
--font-display: 'Instrument Serif', Georgia, serif;
/* Operational heading family. Signature default = the display serif, italic;
family + style ONLY so migrated headings keep their own weight/tracking and
stay a true no-op in Signature. [data-headings="clean"] flips to the sans
face and the Calm weight/tracking lift lands via the .font-heading rule. */
--font-heading: var(--font-display);
--heading-style: italic;
/* Shape */
--radius: 0.5rem;
@@ -388,6 +404,57 @@
--terminal-bg: oklch(0.12 0 0);
}
/* ─────────────────────────────────────────────────────────────
CALM / READABILITY REFRESH
Three appearance attributes on <html> switch the heading family, the
severity-chart palette, and material effects. Signature (the defaults in
:root) needs no rule; Calm flips them. Placed after the theme blocks so the
reduced-effects --card-bevel override wins in every theme.
───────────────────────────────────────────────────────────── */
/* Clean headings: the readability fix. Operational headings drop the display
serif for the upright interface face. */
[data-headings="clean"] {
--font-heading: var(--font-sans);
--heading-style: normal;
}
/* Muted: desaturated severity semantics, no brand/destructive clash. */
[data-chart-style="muted"] {
--sev-critical: oklch(0.605 0.105 28);
--sev-high: oklch(0.715 0.085 70);
--sev-medium: oklch(0.675 0.045 88);
--sev-low: oklch(0.565 0.018 250);
--sev-vuln: oklch(0.605 0.045 235);
}
/* Heat: a single warm sequential ramp with zero complementary vibration. */
[data-chart-style="heat"] {
--sev-critical: oklch(0.565 0.135 30);
--sev-high: oklch(0.675 0.115 48);
--sev-medium: oklch(0.770 0.080 70);
--sev-low: oklch(0.825 0.040 82);
--sev-vuln: oklch(0.660 0.100 45);
}
/* Reduced effects: flatten the material (Calm only). Charts read the reduced
flag from the store; here we flatten the real card top-bevel token. */
[data-effects="reduced"] {
--card-bevel: none;
}
/* Heading utility: every operational title routes through this. Base sets only
family + style (Signature parity); the Calm-only descendant rule lifts weight
and tightens tracking for the sans face, beating any single tracking or weight
utility on the element. */
.font-heading {
font-family: var(--font-heading);
font-style: var(--heading-style);
}
[data-headings="clean"] .font-heading {
font-weight: 600;
letter-spacing: -0.006em;
}
/* ─────────────────────────────────────────────────────────────
TAILWIND THEME MAPPING
───────────────────────────────────────────────────────────── */