@axiapps/axi-design 1.45.0 → 1.47.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/README.md CHANGED
@@ -147,6 +147,7 @@ not "what does the system look like". Everything else is
147
147
  | `--axi-action-hit` | the hit target of an `.axi-action--glyph`, whose label is one character and gives the pointer nothing to land on | `24px` | `<button class="axi-action axi-action--glyph" style="--axi-action-hit: 32px">` |
148
148
  | `--axi-well-pad` | the padding inside an `.axi-well` | `10px` | `<div class="axi-well" style="--axi-well-pad: 18px">` |
149
149
  | `--axi-well-radius` | an `.axi-well`'s corner radius, for a well used at reading scale rather than page scale | `var(--axi-radius)` | `<div class="axi-well" style="--axi-well-radius: var(--axi-radius-sm)">` |
150
+ | `--axi-empty-pad` | the padding inside an `.axi-empty`, for an empty state standing in a tighter space than a table would | `24px 16px` | `<div class="axi-empty" style="--axi-empty-pad: 12px">` |
150
151
  | `--axi-rail-w` | an `.axi-rail`'s width, for labels longer than the default holds | `208px` | `<aside class="axi-rail" style="--axi-rail-w: 260px">` |
151
152
  | `--axi-rail-pad` | the padding inside an `.axi-rail` | `10px` | `<aside class="axi-rail" style="--axi-rail-pad: 6px">` |
152
153
  | `--axi-toolbar-pad` | the padding inside an `.axi-toolbar` | `14px` | `<div class="axi-toolbar" style="--axi-toolbar-pad: 4px 7px">` |
package/dist/axi.css CHANGED
@@ -590,6 +590,30 @@ button.axi-panel--tile:hover,
590
590
  the pad knob is still the right way to say anything else. */
591
591
  .axi-well--sm { --axi-well-radius: var(--axi-radius-sm); }
592
592
 
593
+ /* ---------- the empty state ---------- */
594
+ /* A well with nothing in it but the sentence saying so.
595
+
596
+ Every view that can have no data has to say so somewhere, and the first
597
+ consumer counted said it eighty times - a dashed-border box, centred, small,
598
+ dim - in eighty copies of the same eleven utilities, none of them a word the
599
+ language had. Dashed, because the box was "provisional"; the language says
600
+ provisional with the outlined/filled distinction (rule 5), so the edge is
601
+ the well's own rule. It is a well because an absence is a recess: the place
602
+ a table would stand, sunk into the surface, with nothing standing in it.
603
+
604
+ Only the sentence's type and placement are added to the well, and the
605
+ generous pad is the point - an empty state that is as tall as a single row
606
+ reads as a row that failed to render. */
607
+ .axi-empty {
608
+ background: var(--axi-well-fill);
609
+ border: var(--axi-border-control) solid var(--axi-well-line);
610
+ border-radius: var(--axi-radius-sm);
611
+ padding: var(--axi-empty-pad, 24px 16px);
612
+ text-align: center;
613
+ font: var(--axi-t-small);
614
+ color: var(--axi-text-dim);
615
+ }
616
+
593
617
  /* ---------- button ---------- */
594
618
  .axi-btn {
595
619
  display: inline-flex; align-items: center; gap: 8px;
@@ -2492,6 +2516,12 @@ textarea.axi-input {
2492
2516
  display: flex; align-items: center; gap: 12px;
2493
2517
  height: 38px; padding-left: 14px;
2494
2518
  background: var(--axi-ground-deep);
2519
+ /* The chrome takes the surface filter for the same reason a panel does: on a
2520
+ theme that makes its surfaces translucent, the one strip a reader never
2521
+ scrolls away is the one that has to agree. --axi-surface-filter is none on
2522
+ every opaque surface, so this is inert there - the same inert-by-default
2523
+ shape the panels already use. */
2524
+ backdrop-filter: var(--axi-surface-filter);
2495
2525
  border-bottom: var(--axi-border-control) solid var(--axi-ink-line);
2496
2526
  font: var(--axi-t-micro);
2497
2527
  letter-spacing: var(--axi-ls-micro);
@@ -2516,6 +2546,13 @@ textarea.axi-input {
2516
2546
  /* Close is the one destructive control in the chrome, and the one place a
2517
2547
  status ink belongs in a titlebar. */
2518
2548
  .axi-titlebar__btns :where(button:last-child:hover) { background: var(--axi-danger); color: var(--axi-ink-on-fill); }
2549
+ /* The page-wide ring sits 2px OUTSIDE its element, which a window button
2550
+ cannot afford: it is flush to the top of the frame and flush to its
2551
+ neighbours, so an outward ring spills past the window edge and reads as a
2552
+ loud accent box across the corner of the chrome. Pull it inward, the same
2553
+ way a picker option and a select option already do inside their own tight
2554
+ containers. */
2555
+ .axi-titlebar__btns :where(button:focus-visible) { outline-offset: -3px; }
2519
2556
  /* The scrolling region under the chrome. */
2520
2557
  .axi-window__body { flex: 1; overflow-y: auto; }
2521
2558
 
@@ -17,6 +17,10 @@
17
17
  --axi-text-dim: #8b929e;
18
18
  --axi-text-faint: #5d6577;
19
19
  --axi-scrim: rgba(4, 5, 8, .72);
20
+ --axi-offset-panel: 0;
21
+ --axi-offset-control: 0;
22
+ --axi-offset-panel-hover: 0;
23
+ --axi-offset-control-hover: 0;
20
24
  --axi-shadow-panel: 0 2px 8px rgba(0, 0, 0, .4), 0 1px 3px rgba(0, 0, 0, .3), inset 0 1px 0 rgba(255, 255, 255, .05);
21
25
  --axi-shadow-control: 0 1px 4px rgba(0, 0, 0, .3), inset 0 1px 0 rgba(255, 255, 255, .045);
22
26
  --axi-shadow-panel-hover: 0 6px 18px rgba(0, 0, 0, .5), 0 2px 5px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .07);
@@ -13,7 +13,7 @@
13
13
  --axi-surface-filter: blur(18px) saturate(140%);
14
14
  --axi-ink-line: rgba(180, 200, 255, .16);
15
15
  --axi-rule: rgba(180, 200, 255, .14);
16
- --axi-ground-deep: #0c0e12;
16
+ --axi-ground-deep: rgba(12, 14, 18, .72);
17
17
  --axi-well-fill: rgba(6, 8, 14, .32);
18
18
  --axi-accent-ink: #0c0e12;
19
19
  --axi-ink-on-fill: #0c0e12;
@@ -21,6 +21,10 @@
21
21
  --axi-text-dim: #b3bdd0;
22
22
  --axi-text-faint: #7f8aa0;
23
23
  --axi-scrim: rgba(4, 6, 12, .66);
24
+ --axi-offset-panel: 0;
25
+ --axi-offset-control: 0;
26
+ --axi-offset-panel-hover: 0;
27
+ --axi-offset-control-hover: 0;
24
28
  --axi-shadow-panel: 0 18px 44px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(255, 255, 255, .14);
25
29
  --axi-shadow-control: 0 6px 16px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .12);
26
30
  --axi-shadow-panel-hover: 0 26px 60px rgba(0, 0, 0, .6), inset 0 1px 0 rgba(255, 255, 255, .2);
package/docs/RULES.md CHANGED
@@ -830,10 +830,19 @@ What is **not** a theme's to restate, and each for its own reason:
830
830
  companions are not on this list: `--axi-accent-ink` and `--axi-ink-on-fill`
831
831
  are the colour a word is written in when it sits on a fill, and a theme that
832
832
  lightens the outline has to be able to hold them dark.
833
- - **The offset scale.** `--axi-offset-*` is what the main theme's block is
834
- composed *from*. A theme restates the composed `--axi-shadow-*` wholesale or
835
- leaves it; retuning the offsets underneath would leave the two spellings of
836
- "the block" disagreeing.
833
+ - **The offset scale, except to switch it off.** `--axi-offset-*` is what the
834
+ main theme's block is composed *from*, and retuning it underneath a restated
835
+ `--axi-shadow-*` would leave the two spellings of "the block" disagreeing.
836
+ A theme may set the offsets to `0` and may do nothing else to them. Zero is
837
+ not a retune — it is the same sentence the restated `--axi-shadow-*` is
838
+ already saying. This started out as a flat prohibition and shipped a bug:
839
+ the tokens are public, consumers compose blocks from them directly rather
840
+ than asking for `--axi-shadow-panel`, and a theme whose relief is a soft drop
841
+ was leaving a 6px near-black step standing behind every one of those cards.
842
+ On a square corner it read as a stray backdrop; on a rounded one it read as
843
+ broken rounding. A consumer still composing from the offsets now gets no
844
+ relief on a theme rather than the wrong one, which is a visible prompt to ask
845
+ for the composed block instead.
837
846
  - **The measure.** `--axi-page`, `--axi-gutter`. Where the text wraps is not a
838
847
  look, and moving it would reflow every page rather than repaint it.
839
848
  - **The type.** `--axi-sans`, `--axi-mono`, `--axi-t-*`, `--axi-ls-*`. The same
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiapps/axi-design",
3
- "version": "1.45.0",
3
+ "version": "1.47.0",
4
4
  "description": "The design language for the axi suite — flat and outlined, dark, drawn in saturated ink.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -186,6 +186,30 @@ button.axi-panel--tile:hover,
186
186
  the pad knob is still the right way to say anything else. */
187
187
  .axi-well--sm { --axi-well-radius: var(--axi-radius-sm); }
188
188
 
189
+ /* ---------- the empty state ---------- */
190
+ /* A well with nothing in it but the sentence saying so.
191
+
192
+ Every view that can have no data has to say so somewhere, and the first
193
+ consumer counted said it eighty times - a dashed-border box, centred, small,
194
+ dim - in eighty copies of the same eleven utilities, none of them a word the
195
+ language had. Dashed, because the box was "provisional"; the language says
196
+ provisional with the outlined/filled distinction (rule 5), so the edge is
197
+ the well's own rule. It is a well because an absence is a recess: the place
198
+ a table would stand, sunk into the surface, with nothing standing in it.
199
+
200
+ Only the sentence's type and placement are added to the well, and the
201
+ generous pad is the point - an empty state that is as tall as a single row
202
+ reads as a row that failed to render. */
203
+ .axi-empty {
204
+ background: var(--axi-well-fill);
205
+ border: var(--axi-border-control) solid var(--axi-well-line);
206
+ border-radius: var(--axi-radius-sm);
207
+ padding: var(--axi-empty-pad, 24px 16px);
208
+ text-align: center;
209
+ font: var(--axi-t-small);
210
+ color: var(--axi-text-dim);
211
+ }
212
+
189
213
  /* ---------- button ---------- */
190
214
  .axi-btn {
191
215
  display: inline-flex; align-items: center; gap: 8px;
package/src/shells.css CHANGED
@@ -947,6 +947,12 @@
947
947
  display: flex; align-items: center; gap: 12px;
948
948
  height: 38px; padding-left: 14px;
949
949
  background: var(--axi-ground-deep);
950
+ /* The chrome takes the surface filter for the same reason a panel does: on a
951
+ theme that makes its surfaces translucent, the one strip a reader never
952
+ scrolls away is the one that has to agree. --axi-surface-filter is none on
953
+ every opaque surface, so this is inert there - the same inert-by-default
954
+ shape the panels already use. */
955
+ backdrop-filter: var(--axi-surface-filter);
950
956
  border-bottom: var(--axi-border-control) solid var(--axi-ink-line);
951
957
  font: var(--axi-t-micro);
952
958
  letter-spacing: var(--axi-ls-micro);
@@ -971,6 +977,13 @@
971
977
  /* Close is the one destructive control in the chrome, and the one place a
972
978
  status ink belongs in a titlebar. */
973
979
  .axi-titlebar__btns :where(button:last-child:hover) { background: var(--axi-danger); color: var(--axi-ink-on-fill); }
980
+ /* The page-wide ring sits 2px OUTSIDE its element, which a window button
981
+ cannot afford: it is flush to the top of the frame and flush to its
982
+ neighbours, so an outward ring spills past the window edge and reads as a
983
+ loud accent box across the corner of the chrome. Pull it inward, the same
984
+ way a picker option and a select option already do inside their own tight
985
+ containers. */
986
+ .axi-titlebar__btns :where(button:focus-visible) { outline-offset: -3px; }
974
987
  /* The scrolling region under the chrome. */
975
988
  .axi-window__body { flex: 1; overflow-y: auto; }
976
989