@flyos/design-system 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flyos/design-system",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "FlyOS design system — shared components, directives, pipes, services, and models for Business App developers.",
5
5
  "keywords": [
6
6
  "flyos",
@@ -299,6 +299,31 @@
299
299
  @include _degrade;
300
300
  }
301
301
 
302
+ // ── Content blur ─────────────────────────────────────────────────────────────
303
+ // The one sanctioned way for a surface INSIDE a window to blur the app's OWN
304
+ // content: scroll-edge toolbars, side panes, drawers over the app's canvas, and
305
+ // floating tool plates that keep the app's documented fill (chats'
306
+ // `--glass-bg-elevated` floaters are the reference consumers). It emits ONLY the
307
+ // thin blur tier plus the degradation ladder — no fill, border or shadow — so an
308
+ // app's measured, RULE-A-tracked plate/ink pairing survives the migration off
309
+ // raw `backdrop-filter` untouched.
310
+
311
+ // What this is NOT:
312
+ // · not a menu/listbox recipe — a true menu takes `popover($surface: menu)`,
313
+ // the material `fly-context-menu`/`fly-select` already ship;
314
+ // · not a way to reach the wallpaper. A window is a backdrop root (hazard 3 in
315
+ // the header), so inside one this blur samples the window's interior paint —
316
+ // the app content behind the surface. That IS the contract here, which is
317
+ // why this recipe is safe where a translucent quartet fill would read muddy.
318
+
319
+ // Include it AFTER the caller's own paint declarations: the ladder's
320
+ // reduced-transparency flat must be able to override the caller's translucent
321
+ // fill, and within one specificity tier that is decided by source order.
322
+ @mixin content-blur {
323
+ @include _backdrop(thin);
324
+ @include _degrade;
325
+ }
326
+
302
327
  // ── Light "vibrancy" material — RETIRED IN PLACE, no production callers ──────
303
328
  // DO NOT ADOPT THIS. S6.-1 reversed the ruling that motivated it: the light
304
329
  // theme is conventional dark-ink-on-pale-plate, and the white-ink-on-smoke
@@ -95,6 +95,41 @@ html.light-theme {
95
95
  --sys-green: #1B7355;
96
96
  --sys-purple: #6A3FC0;
97
97
 
98
+ // ── System TINTS ───────────────────────────────────────────────────────────
99
+ // The status-wash step the hue family was missing. Before these existed, 75
100
+ // feature-app call sites minted their own Tailwind-palette literal at a fixed
101
+ // alpha (`rgb(16 185 129 / 8%)` …) — one value for both themes, tuned against
102
+ // whichever plate the author happened to be looking at. A missing step makes
103
+ // every consumer mint their own (the `--font-family` trap), so the step is a
104
+ // NAMED TOKEN, not a documented idiom: two strengths, no percentage drift.
105
+ // ---
106
+ // · Derived via `color-mix` off the hue token so a tint always tracks its
107
+ // `--sys-*` parent — the same derivation the D7 danger ruling already
108
+ // spells for action-menu hovers (`color-mix(in oklab, var(--sys-red) 18%,
109
+ // transparent)`). Mixing toward `transparent` is colour-space-neutral: the
110
+ // result is the hue at that alpha.
111
+ // · Strengths are PER THEME (like `--tint-hover`/`--tint-sel` above): the
112
+ // light hues are deep, so 8% over the pale plate reads like the old
113
+ // Tailwind-500 at 10%; the dark hues are bright pastels over a near-black
114
+ // plate and need more ink to read as the same wash.
115
+ // · Pick by ROLE: `-tint` = resting wash (status rows, soft chips, added
116
+ // states); `-tint-strong` = emphasis (selected/hover status, danger
117
+ // surfaces, filled badges). Never mint a bespoke percentage for a
118
+ // BACKGROUND. Border rings and glows are not this step — spell those
119
+ // `color-mix(in srgb, var(--sys-*) N%, transparent)` at the use site.
120
+ --sys-red-tint: color-mix(in srgb, var(--sys-red) 8%, transparent);
121
+ --sys-red-tint-strong: color-mix(in srgb, var(--sys-red) 14%, transparent);
122
+ --sys-orange-tint: color-mix(in srgb, var(--sys-orange) 8%, transparent);
123
+ --sys-orange-tint-strong: color-mix(in srgb, var(--sys-orange) 14%, transparent);
124
+ --sys-blue-tint: color-mix(in srgb, var(--sys-blue) 8%, transparent);
125
+ --sys-blue-tint-strong: color-mix(in srgb, var(--sys-blue) 14%, transparent);
126
+ --sys-teal-tint: color-mix(in srgb, var(--sys-teal) 8%, transparent);
127
+ --sys-teal-tint-strong: color-mix(in srgb, var(--sys-teal) 14%, transparent);
128
+ --sys-green-tint: color-mix(in srgb, var(--sys-green) 8%, transparent);
129
+ --sys-green-tint-strong: color-mix(in srgb, var(--sys-green) 14%, transparent);
130
+ --sys-purple-tint: color-mix(in srgb, var(--sys-purple) 8%, transparent);
131
+ --sys-purple-tint-strong: color-mix(in srgb, var(--sys-purple) 14%, transparent);
132
+
98
133
  // Brushed-steel wash. Light-only in the design; the dark block declares it
99
134
  // `none` so a consumer never needs `var(--steel-sheen, …)` — a hex fallback
100
135
  // is banned outright (skill §9 rule 3).
@@ -255,6 +290,25 @@ html.dark-theme {
255
290
  --sys-green: #4dd6a8;
256
291
  --sys-purple: #a48ce0;
257
292
 
293
+ // ── System TINTS ───────────────────────────────────────────────────────────
294
+ // Same two-step law as the light block (see its comment for the full
295
+ // rationale). Dark strengths are HIGHER on purpose: these hues are bright
296
+ // pastels and the plate is near-black, so parity with the light wash needs
297
+ // more ink — the same asymmetry `--tint-hover` carries (10% light / 26%
298
+ // dark). Tune strength HERE, never at a call site.
299
+ --sys-red-tint: color-mix(in srgb, var(--sys-red) 12%, transparent);
300
+ --sys-red-tint-strong: color-mix(in srgb, var(--sys-red) 18%, transparent);
301
+ --sys-orange-tint: color-mix(in srgb, var(--sys-orange) 12%, transparent);
302
+ --sys-orange-tint-strong: color-mix(in srgb, var(--sys-orange) 18%, transparent);
303
+ --sys-blue-tint: color-mix(in srgb, var(--sys-blue) 12%, transparent);
304
+ --sys-blue-tint-strong: color-mix(in srgb, var(--sys-blue) 18%, transparent);
305
+ --sys-teal-tint: color-mix(in srgb, var(--sys-teal) 12%, transparent);
306
+ --sys-teal-tint-strong: color-mix(in srgb, var(--sys-teal) 18%, transparent);
307
+ --sys-green-tint: color-mix(in srgb, var(--sys-green) 12%, transparent);
308
+ --sys-green-tint-strong: color-mix(in srgb, var(--sys-green) 18%, transparent);
309
+ --sys-purple-tint: color-mix(in srgb, var(--sys-purple) 12%, transparent);
310
+ --sys-purple-tint-strong: color-mix(in srgb, var(--sys-purple) 18%, transparent);
311
+
258
312
  // Light-only in the design — declared as a no-op here so consumers can read
259
313
  // it unconditionally in either theme.
260
314
  --steel-sheen: none;
@@ -320,20 +374,21 @@ html.dark-theme {
320
374
  --mat-menu-b-alpha: 1;
321
375
  --mat-menu-b: rgb(26 25 30 / calc(var(--mat-menu-b-alpha) * 100%));
322
376
 
323
- // Re-valued by S6W (agent-panel sweep). The carried-over literal was
324
- // rgb(56 54 60) at 0.52→0.65 warm-hued AND translucent, so over a warm
325
- // wallpaper the aside composited into muddy brown while the account-menu
326
- // popover beside it stayed crisp on the alpha-1 `--mat-menu-*` pair. These
327
- // are now that same menu pair's stops at alpha 1: crisp, wallpaper-immune,
328
- // and cool-neutral like every other dark floating surface.
329
- // Alternatives weighed (final call is perceptual, at fan-in):
330
- // · alpha→1 on the old hue rgb(56 54 60) crisp but noticeably lighter
331
- // and warmer than the menu material next to it;
332
- // · ~0.85 alpha on either hue still lets a warm wallpaper tint the
333
- // plate, i.e. a smaller dose of the same defect.
334
- --mat-agent-a-alpha: 1;
377
+ // Translucent again (2026-08-16), on S6W's COOL hues half of that ruling reversed, half
378
+ // kept, and the split is deliberate. S6W found the aside compositing muddy brown over warm
379
+ // wallpapers and went alpha-1 on the menu pair's stops. Two facts have changed since:
380
+ // · the warm rgb(56 54 60) hue was half the mud, and it stays gone — these stops remain
381
+ // the cool menu-pair hues, which tint cool-neutral rather than brown;
382
+ // · the model now knows about the shell's 35% black wallpaper scrim (`shellBackdrop`),
383
+ // which darkens and mutes whatever shows through the "wallpaper tints the plate"
384
+ // dose S6W measured was computed against a backdrop the browser does not paint.
385
+ // At 0.6/0.68 every aside row clears AA through the scrim over the WORST shipped backdrop
386
+ // (primary 7.36/9.15, secondary 4.99/5.99theme-contrast gate), and the aside once again
387
+ // matches the design's translucent panel (the mock's aside was 0.52→0.65) and its light-theme
388
+ // sibling right above (0.6/0.65) instead of being the one opaque slab in the shell.
389
+ --mat-agent-a-alpha: 0.6;
335
390
  --mat-agent-a: rgb(32 31 37 / calc(var(--mat-agent-a-alpha) * 100%));
336
- --mat-agent-b-alpha: 1;
391
+ --mat-agent-b-alpha: 0.68;
337
392
  --mat-agent-b: rgb(26 25 30 / calc(var(--mat-agent-b-alpha) * 100%));
338
393
  --mat-tip-a-alpha: 0.82;
339
394
  --mat-tip-a: rgb(46 44 52 / calc(var(--mat-tip-a-alpha) * 100%));
@@ -108,7 +108,13 @@ html.dark-theme {
108
108
  --fly-shadow-md: 0 4px 16px rgb(0 0 0 / 42%);
109
109
 
110
110
  // ── Glass system ────────────────────────────────────────────────────────────
111
- --glass-bg: rgb(22 22 26 / 72%);
111
+ // 0.55, down from 0.72 (2026-08-16). The 72% was solved against the raw wallpaper, but no
112
+ // dark surface ever neighbours the wallpaper — the shell paints a 35% black scrim first
113
+ // (`shellBackdrop` in theme-contrast.ts), and through it the whole ink ladder clears its
114
+ // floors at 0.55: secondary 4.99:1 over the brightest shipped backdrop, tertiary 3.30 ≥ 3.
115
+ // Alpha parity with `--mat-panel` (Home) so windows, inner glass panels, and the content
116
+ // panel read as ONE material. The theme-contrast gate measures every row through the scrim.
117
+ --glass-bg: rgb(22 22 26 / 55%);
112
118
  --glass-bg-elevated: rgb(30 30 36 / 82%);
113
119
 
114
120
  // Tooltip surface — OPAQUE, and not a glass token. See the light theme for the full reasoning
@@ -144,10 +150,15 @@ html.dark-theme {
144
150
  --launcher-card-desc: rgb(255 255 255 / 58%);
145
151
 
146
152
  // ── Window chrome ───────────────────────────────────────────────────────────
147
- // 42% was too thin to be a dependable substrate: over the brightest shipped wallpapers
148
- // (`alpine-lake`, `cherry-blossom`) the plate stayed light enough that white body text fell
149
- // to ~2.9:1. Raised to match `--glass-bg`, which is the same surface one layer out.
150
- --window-bg: rgb(20 20 24 / 70%);
153
+ // 0.55, down from 0.70 (2026-08-16), and the history matters: 42% was genuinely too thin
154
+ // (white body text ~2.9:1 over `alpine-lake`), but the 70% that fixed it was solved against
155
+ // the RAW wallpaper a backdrop the browser never paints. Every dark surface sits on the
156
+ // shell's 35% black scrim (`.desktop-wallpaper.dark-theme::after`), and through it the full
157
+ // window ink ladder passes at 0.55: primary 7.35:1, secondary 4.99:1, tertiary 3.30:1 over
158
+ // the brightest shipped backdrop (theme-contrast gate, measured per row). 0.55 is alpha
159
+ // parity with `--mat-panel`, so a window and Home read as the same glass — the fork where a
160
+ // maximized window sat visibly thicker than the launcher beside it is what this closes.
161
+ --window-bg: rgb(20 20 24 / 55%);
151
162
  --window-radius: 24px;
152
163
  --window-blur: 30px;
153
164
  --window-backdrop-saturate: 160%;
@@ -118,12 +118,13 @@ html.light-theme {
118
118
  // Tooltip surface. OPAQUE and deliberately NOT a glass token.
119
119
 
120
120
  // A tooltip is body-parented and floats over whatever happens to be underneath — a light app
121
- // surface, a dark board canvas, the wallpaper. The glass family is TRANSLUCENT and, at runtime,
122
- // wallpaper-adaptive: the shell recomputes `--glass-bg-elevated` from the wallpaper and writes it
123
- // at `:root`, so under a dark wallpaper it becomes a 54 %-alpha DARK plate even while the shell
124
- // is in `light-theme`. Composited over a light page that resolves to roughly rgb(143,141,140),
125
- // and the matching white ink lands at about 2.8:1 the "tooltips are white on white" report.
126
- // An overlay that can appear anywhere cannot inherit a surface tuned for one backdrop.
121
+ // surface, a dark board canvas, the wallpaper. The glass family is TRANSLUCENT, and at the time
122
+ // of the "tooltips are white on white" report it was also runtime-adaptive: the shell then
123
+ // recomputed `--glass-bg-elevated` from the wallpaper and wrote it at `:root`, so under a dark
124
+ // wallpaper it became a 54%-alpha DARK plate even in `light-theme`, compositing white ink to
125
+ // ~2.8:1 over a light page. That recompute NO LONGER EXISTS (`--glass-bg-elevated` is static
126
+ // now verify with a grep before citing it), but the argument survives its mechanism: an
127
+ // overlay that can appear over ANY backdrop cannot inherit a surface tuned for one.
127
128
 
128
129
  // Dark plate + white ink in BOTH themes is the classic tooltip treatment (macOS, Material,
129
130
  // Bootstrap) and is exactly what this directive's own comment always claimed it fell back to —