contain-css-svelte 1.4.2 → 1.5.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.
Files changed (50) hide show
  1. package/dist/Card.svelte +57 -3
  2. package/dist/controls/Button.svelte +32 -0
  3. package/dist/controls/ButtonLink.svelte +32 -0
  4. package/dist/controls/Checkbox.svelte +36 -0
  5. package/dist/controls/CircleButton.svelte +32 -0
  6. package/dist/controls/Input.svelte +32 -0
  7. package/dist/controls/RadioButton.svelte +36 -1
  8. package/dist/controls/Select.svelte +35 -0
  9. package/dist/controls/Slider.svelte +32 -0
  10. package/dist/controls/TabItem.svelte +36 -0
  11. package/dist/controls/Toggle.svelte +32 -0
  12. package/dist/dropdowns/DropdownMenu.svelte +53 -1
  13. package/dist/layout/Accordion.svelte +32 -0
  14. package/dist/layout/Bar.svelte +50 -0
  15. package/dist/layout/ColumnContainer.svelte +32 -0
  16. package/dist/layout/Columns.svelte +32 -0
  17. package/dist/layout/Container.svelte +48 -2
  18. package/dist/layout/DataList.svelte +33 -1
  19. package/dist/layout/DataList.svelte.d.ts +7 -0
  20. package/dist/layout/DataListItem.svelte +56 -2
  21. package/dist/layout/Fieldset.svelte +32 -0
  22. package/dist/layout/Form.svelte +32 -0
  23. package/dist/layout/FormItem.svelte +46 -0
  24. package/dist/layout/GridLayout.svelte +59 -0
  25. package/dist/layout/Hero.svelte +42 -0
  26. package/dist/layout/Inline.svelte +37 -1
  27. package/dist/layout/MenuList.svelte +32 -0
  28. package/dist/layout/Page.svelte +137 -10
  29. package/dist/layout/Page.svelte.d.ts +17 -0
  30. package/dist/layout/RowContainer.svelte +32 -0
  31. package/dist/layout/Sidebar.svelte +104 -56
  32. package/dist/layout/SidebarContainer.svelte +32 -0
  33. package/dist/layout/SplitPane.svelte +32 -0
  34. package/dist/layout/Stack.svelte +32 -0
  35. package/dist/layout/TabBar.svelte +127 -8
  36. package/dist/layout/TabBar.svelte.d.ts +16 -0
  37. package/dist/layout/Table.svelte +60 -9
  38. package/dist/layout/Tile.svelte +89 -6
  39. package/dist/misc/CodeInner.svelte +32 -0
  40. package/dist/misc/Progress.svelte +32 -0
  41. package/dist/misc/Tag.svelte +32 -0
  42. package/dist/overlays/Dialog.svelte +32 -0
  43. package/dist/overlays/Tooltip.svelte +32 -0
  44. package/dist/sass/_responsive.scss +43 -0
  45. package/dist/typography/TextLayout.svelte +47 -0
  46. package/dist/vars/colors.css +21 -5
  47. package/dist/vars/defaults.css +25 -6
  48. package/dist/vars/layout.css +4 -1
  49. package/dist/vars/responsive-typography.css +4 -1
  50. package/package.json +1 -1
@@ -308,15 +308,22 @@ function observeColumns() {
308
308
  </div>
309
309
  {/if}
310
310
  {:else}
311
- <table>
312
- {#if thead}
313
- {@render thead?.()}
314
- {/if}
315
- {#if tbody}
316
- {@render tbody?.()}
317
- {/if}
318
- {@render children?.()}
319
- </table>
311
+ <!-- A table can't shrink below its content, so on a narrow screen it is
312
+ wider than its container. It scrolls sideways in its own strip rather
313
+ than widening (or, under an overflow-clipping ancestor, being cut off
314
+ by) everything around it. Not done for the sticky variants: a scroll
315
+ box would become the sticky header's scroll container. -->
316
+ <div class="table-scroll">
317
+ <table>
318
+ {#if thead}
319
+ {@render thead?.()}
320
+ {/if}
321
+ {#if tbody}
322
+ {@render tbody?.()}
323
+ {/if}
324
+ {@render children?.()}
325
+ </table>
326
+ </div>
320
327
  {/if}
321
328
 
322
329
  <style>/* Per-level heading (h1-h6) box/typography properties, resolved to PRIVATE,
@@ -390,6 +397,38 @@ function observeColumns() {
390
397
  we deliberately avoid everywhere else.
391
398
 
392
399
  One definition, used by both, so they cannot drift again. */
400
+ /* The "small" size tier: a component whose container is this wide or less
401
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
402
+
403
+ The convention, shared by every component that has a size worth changing
404
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
405
+
406
+ --{component}-{property}-small
407
+
408
+ applies inside a small container. What wins there, in order:
409
+ 1. the `-small` variable, if you set it;
410
+ 2. otherwise the regular variable, if you set it -- a size you chose on
411
+ purpose is not overridden behind your back;
412
+ 3. otherwise the component's own small default, which for most
413
+ properties is simply its regular default.
414
+
415
+ Container queries can't read a custom property, so the breakpoint itself
416
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
417
+ which already switched there. (The Sidebar's rail-to-sheet switch,
418
+ above, is a separate, layout-chrome decision and keeps its own value.) */
419
+ /* Styles for the small tier: the nearest container is narrow, OR the
420
+ viewport is.
421
+
422
+ The container query is the real answer -- a Tile in a 400px pane on a
423
+ desktop is small. But a container query only matches inside an ancestor
424
+ that *is* a container, and a component dropped straight into a page (no
425
+ Page, no Container around it) has none, so on a phone it would never
426
+ find out. The viewport query covers that: a narrow viewport means every
427
+ container in it is narrow too, so the two never disagree in the
428
+ direction that matters.
429
+
430
+ An element never queries itself, so on a component that is its own
431
+ container (Tile, Bar) this asks about the space it was given. */
393
432
  /* Warning: because we define a fallback
394
433
  media query, the media query can override the container
395
434
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -836,6 +875,18 @@ table :global(tr > th:first-child:has(~ td)) {
836
875
  border-right: var(--table-first-row-bottom-border, var(--table-thick-border, 3px) solid var(--table-first-row-border-color, var(--secondary-bg))) !important;
837
876
  }
838
877
 
878
+ .table-scroll {
879
+ max-width: 100%;
880
+ overflow-x: auto;
881
+ /* Room for the table's own box-shadow, which the scroll box would
882
+ otherwise clip. */
883
+ padding: var(--table-scroll-padding, 0 0 4px);
884
+ /* A visible scrollbar, not the hover-revealed one the other scroll areas
885
+ use: a phone has no hover, and the bar is the only sign that the table
886
+ goes on past the edge. */
887
+ scrollbar-width: thin;
888
+ }
889
+
839
890
  .table-container {
840
891
  position: sticky;
841
892
  top: 0;
@@ -142,6 +142,38 @@ const className = $derived(props.class);
142
142
  we deliberately avoid everywhere else.
143
143
 
144
144
  One definition, used by both, so they cannot drift again. */
145
+ /* The "small" size tier: a component whose container is this wide or less
146
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
147
+
148
+ The convention, shared by every component that has a size worth changing
149
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
150
+
151
+ --{component}-{property}-small
152
+
153
+ applies inside a small container. What wins there, in order:
154
+ 1. the `-small` variable, if you set it;
155
+ 2. otherwise the regular variable, if you set it -- a size you chose on
156
+ purpose is not overridden behind your back;
157
+ 3. otherwise the component's own small default, which for most
158
+ properties is simply its regular default.
159
+
160
+ Container queries can't read a custom property, so the breakpoint itself
161
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
162
+ which already switched there. (The Sidebar's rail-to-sheet switch,
163
+ above, is a separate, layout-chrome decision and keeps its own value.) */
164
+ /* Styles for the small tier: the nearest container is narrow, OR the
165
+ viewport is.
166
+
167
+ The container query is the real answer -- a Tile in a 400px pane on a
168
+ desktop is small. But a container query only matches inside an ancestor
169
+ that *is* a container, and a component dropped straight into a page (no
170
+ Page, no Container around it) has none, so on a phone it would never
171
+ find out. The viewport query covers that: a narrow viewport means every
172
+ container in it is narrow too, so the two never disagree in the
173
+ direction that matters.
174
+
175
+ An element never queries itself, so on a component that is its own
176
+ container (Tile, Bar) this asks about the space it was given. */
145
177
  /* Warning: because we define a fallback
146
178
  media query, the media query can override the container
147
179
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -451,15 +483,22 @@ const className = $derived(props.class);
451
483
  --_box-shadow:
452
484
  var(--tile-shadow-distance, var(--surface-shadow-distance, var(--shadow-distance, var(--space)))) var(--tile-shadow-distance, var(--surface-shadow-distance, var(--shadow-distance, var(--space)))) var(--tile-shadow-blur, var(--surface-shadow-blur, var(--shadow-blur, var(--space)))) var(--tile-shadow-color, var(--surface-shadow-color, var(--shadow-color, rgba(127, 127, 127, 0.4))));
453
485
  box-shadow: var(--_box-shadow);
454
- width: var(--tile-width, calc(var(--space-lg) * 24));
455
- /* Override typography max-width */
456
- max-width: var(--tile-width, calc(var(--space-lg) * 24));
486
+ /* --_tile-width is resolved in the sizing block below. max-width also
487
+ overrides the typography mixin's prose measure. */
488
+ width: var(--_tile-width);
489
+ max-width: var(--_tile-width);
457
490
  display: inline-flex;
458
491
  vertical-align: top;
459
492
  flex-direction: column;
460
493
  justify-content: var(--tile-justify, var(--justify, flex-start));
461
494
  align-items: var(--tile-align, var(--align, center));
462
495
  container-type: inline-size;
496
+ /* A Tile is a fixed-size object. Inline-size containment makes its
497
+ min-content width zero, so as a flex item in any row that runs out of
498
+ room (a RowContainer lane, a nowrap Inline) it would be squeezed to a
499
+ sliver with its text spilling out. Hold the size; let the row wrap or
500
+ scroll instead. */
501
+ flex-shrink: 0;
463
502
  }
464
503
 
465
504
  button.tile,
@@ -610,12 +649,56 @@ label.tile:has(:global(input:focus-visible)) {
610
649
  box-shadow: var(--focus-ring-box-shadow, 0 0 0 3px var(--focus-shadow-color, rgba(100, 150, 250, 0.5)));
611
650
  }
612
651
 
613
- /* Sizing code */
652
+ /* Sizing.
653
+
654
+ One width, declared once. There used to be two -- `--space-lg * 24`
655
+ (192px) above and `200px` here -- and the narrower max-width quietly won,
656
+ so tiles rendered 192px wide but 267px tall (200 * 4/3).
657
+
658
+ The 3:4 shape is a *minimum* height rather than a fixed one, so a tile
659
+ with more content than its shape holds grows to fit instead of spilling
660
+ out. Set --tile-height to pin it (it sets the minimum too, or the shape
661
+ would win over a shorter pinned height); --tile-aspect-ratio to change
662
+ the shape.
663
+
664
+ Not the `aspect-ratio` property: a percentage --tile-width (a tile
665
+ filling a ColumnContainer rail) would then be 4/3 of the rail tall. As a
666
+ calc, a percentage height against an auto-height parent resolves to
667
+ nothing and the tile is as tall as its content, which is what those
668
+ layouts have always relied on. */
614
669
  .tile {
615
- width: var(--tile-width, 200px);
616
- height: var(--tile-height, calc(var(--tile-width, 200px) * 1.333));
670
+ --_tile-width: var(--tile-width, calc(var(--space-lg, 8px) * 24));
671
+ --_tile-min-height: var(
672
+ --tile-height,
673
+ calc(var(--_tile-width) / (var(--tile-aspect-ratio, 3 / 4)))
674
+ );
675
+ height: var(--tile-height, auto);
676
+ min-height: var(--_tile-min-height);
617
677
  }
618
678
 
679
+ /* Small tier (see $small-max): two tiles side by side on a phone instead of
680
+ one 192px tile alone in a 360px row. 160px * 2 + a gap fits a 328px
681
+ content box, i.e. a 360px phone with 16px gutters. */
682
+ @media (max-width: 600px) {
683
+ .tile {
684
+ --_tile-width: var(
685
+ --tile-width-small,
686
+ var(--tile-width, calc(var(--space-lg, 8px) * 20))
687
+ );
688
+ height: var(--tile-height-small, var(--tile-height, auto));
689
+ min-height: var(--tile-height-small, var(--_tile-min-height));
690
+ }
691
+ }
692
+ @container (max-width: 600px) {
693
+ .tile {
694
+ --_tile-width: var(
695
+ --tile-width-small,
696
+ var(--tile-width, calc(var(--space-lg, 8px) * 20))
697
+ );
698
+ height: var(--tile-height-small, var(--tile-height, auto));
699
+ min-height: var(--tile-height-small, var(--_tile-min-height));
700
+ }
701
+ }
619
702
  /* Checkbox code */
620
703
  .tile {
621
704
  position: relative;
@@ -87,6 +87,38 @@ let highlightedCode = $derived.by(() => {
87
87
  we deliberately avoid everywhere else.
88
88
 
89
89
  One definition, used by both, so they cannot drift again. */
90
+ /* The "small" size tier: a component whose container is this wide or less
91
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
92
+
93
+ The convention, shared by every component that has a size worth changing
94
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
95
+
96
+ --{component}-{property}-small
97
+
98
+ applies inside a small container. What wins there, in order:
99
+ 1. the `-small` variable, if you set it;
100
+ 2. otherwise the regular variable, if you set it -- a size you chose on
101
+ purpose is not overridden behind your back;
102
+ 3. otherwise the component's own small default, which for most
103
+ properties is simply its regular default.
104
+
105
+ Container queries can't read a custom property, so the breakpoint itself
106
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
107
+ which already switched there. (The Sidebar's rail-to-sheet switch,
108
+ above, is a separate, layout-chrome decision and keeps its own value.) */
109
+ /* Styles for the small tier: the nearest container is narrow, OR the
110
+ viewport is.
111
+
112
+ The container query is the real answer -- a Tile in a 400px pane on a
113
+ desktop is small. But a container query only matches inside an ancestor
114
+ that *is* a container, and a component dropped straight into a page (no
115
+ Page, no Container around it) has none, so on a phone it would never
116
+ find out. The viewport query covers that: a narrow viewport means every
117
+ container in it is narrow too, so the two never disagree in the
118
+ direction that matters.
119
+
120
+ An element never queries itself, so on a component that is its own
121
+ container (Tile, Bar) this asks about the space it was given. */
90
122
  /* Warning: because we define a fallback
91
123
  media query, the media query can override the container
92
124
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -134,6 +134,38 @@ let halfFull = $derived(fillFraction > 0.5);
134
134
  we deliberately avoid everywhere else.
135
135
 
136
136
  One definition, used by both, so they cannot drift again. */
137
+ /* The "small" size tier: a component whose container is this wide or less
138
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
139
+
140
+ The convention, shared by every component that has a size worth changing
141
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
142
+
143
+ --{component}-{property}-small
144
+
145
+ applies inside a small container. What wins there, in order:
146
+ 1. the `-small` variable, if you set it;
147
+ 2. otherwise the regular variable, if you set it -- a size you chose on
148
+ purpose is not overridden behind your back;
149
+ 3. otherwise the component's own small default, which for most
150
+ properties is simply its regular default.
151
+
152
+ Container queries can't read a custom property, so the breakpoint itself
153
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
154
+ which already switched there. (The Sidebar's rail-to-sheet switch,
155
+ above, is a separate, layout-chrome decision and keeps its own value.) */
156
+ /* Styles for the small tier: the nearest container is narrow, OR the
157
+ viewport is.
158
+
159
+ The container query is the real answer -- a Tile in a 400px pane on a
160
+ desktop is small. But a container query only matches inside an ancestor
161
+ that *is* a container, and a component dropped straight into a page (no
162
+ Page, no Container around it) has none, so on a phone it would never
163
+ find out. The viewport query covers that: a narrow viewport means every
164
+ container in it is narrow too, so the two never disagree in the
165
+ direction that matters.
166
+
167
+ An element never queries itself, so on a component that is its own
168
+ container (Tile, Bar) this asks about the space it was given. */
137
169
  /* Warning: because we define a fallback
138
170
  media query, the media query can override the container
139
171
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -101,6 +101,38 @@ const el = $derived(elementProps(restProps, "tag", TAG_VARS));
101
101
  we deliberately avoid everywhere else.
102
102
 
103
103
  One definition, used by both, so they cannot drift again. */
104
+ /* The "small" size tier: a component whose container is this wide or less
105
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
106
+
107
+ The convention, shared by every component that has a size worth changing
108
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
109
+
110
+ --{component}-{property}-small
111
+
112
+ applies inside a small container. What wins there, in order:
113
+ 1. the `-small` variable, if you set it;
114
+ 2. otherwise the regular variable, if you set it -- a size you chose on
115
+ purpose is not overridden behind your back;
116
+ 3. otherwise the component's own small default, which for most
117
+ properties is simply its regular default.
118
+
119
+ Container queries can't read a custom property, so the breakpoint itself
120
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
121
+ which already switched there. (The Sidebar's rail-to-sheet switch,
122
+ above, is a separate, layout-chrome decision and keeps its own value.) */
123
+ /* Styles for the small tier: the nearest container is narrow, OR the
124
+ viewport is.
125
+
126
+ The container query is the real answer -- a Tile in a 400px pane on a
127
+ desktop is small. But a container query only matches inside an ancestor
128
+ that *is* a container, and a component dropped straight into a page (no
129
+ Page, no Container around it) has none, so on a phone it would never
130
+ find out. The viewport query covers that: a narrow viewport means every
131
+ container in it is narrow too, so the two never disagree in the
132
+ direction that matters.
133
+
134
+ An element never queries itself, so on a component that is its own
135
+ container (Tile, Bar) this asks about the space it was given. */
104
136
  /* Warning: because we define a fallback
105
137
  media query, the media query can override the container
106
138
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -148,6 +148,38 @@ let ref;
148
148
  we deliberately avoid everywhere else.
149
149
 
150
150
  One definition, used by both, so they cannot drift again. */
151
+ /* The "small" size tier: a component whose container is this wide or less
152
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
153
+
154
+ The convention, shared by every component that has a size worth changing
155
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
156
+
157
+ --{component}-{property}-small
158
+
159
+ applies inside a small container. What wins there, in order:
160
+ 1. the `-small` variable, if you set it;
161
+ 2. otherwise the regular variable, if you set it -- a size you chose on
162
+ purpose is not overridden behind your back;
163
+ 3. otherwise the component's own small default, which for most
164
+ properties is simply its regular default.
165
+
166
+ Container queries can't read a custom property, so the breakpoint itself
167
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
168
+ which already switched there. (The Sidebar's rail-to-sheet switch,
169
+ above, is a separate, layout-chrome decision and keeps its own value.) */
170
+ /* Styles for the small tier: the nearest container is narrow, OR the
171
+ viewport is.
172
+
173
+ The container query is the real answer -- a Tile in a 400px pane on a
174
+ desktop is small. But a container query only matches inside an ancestor
175
+ that *is* a container, and a component dropped straight into a page (no
176
+ Page, no Container around it) has none, so on a phone it would never
177
+ find out. The viewport query covers that: a narrow viewport means every
178
+ container in it is narrow too, so the two never disagree in the
179
+ direction that matters.
180
+
181
+ An element never queries itself, so on a component that is its own
182
+ container (Tile, Bar) this asks about the space it was given. */
151
183
  /* Warning: because we define a fallback
152
184
  media query, the media query can override the container
153
185
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -368,6 +368,38 @@ async function showPopover() {
368
368
  we deliberately avoid everywhere else.
369
369
 
370
370
  One definition, used by both, so they cannot drift again. */
371
+ /* The "small" size tier: a component whose container is this wide or less
372
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
373
+
374
+ The convention, shared by every component that has a size worth changing
375
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
376
+
377
+ --{component}-{property}-small
378
+
379
+ applies inside a small container. What wins there, in order:
380
+ 1. the `-small` variable, if you set it;
381
+ 2. otherwise the regular variable, if you set it -- a size you chose on
382
+ purpose is not overridden behind your back;
383
+ 3. otherwise the component's own small default, which for most
384
+ properties is simply its regular default.
385
+
386
+ Container queries can't read a custom property, so the breakpoint itself
387
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
388
+ which already switched there. (The Sidebar's rail-to-sheet switch,
389
+ above, is a separate, layout-chrome decision and keeps its own value.) */
390
+ /* Styles for the small tier: the nearest container is narrow, OR the
391
+ viewport is.
392
+
393
+ The container query is the real answer -- a Tile in a 400px pane on a
394
+ desktop is small. But a container query only matches inside an ancestor
395
+ that *is* a container, and a component dropped straight into a page (no
396
+ Page, no Container around it) has none, so on a phone it would never
397
+ find out. The viewport query covers that: a narrow viewport means every
398
+ container in it is narrow too, so the two never disagree in the
399
+ direction that matters.
400
+
401
+ An element never queries itself, so on a component that is its own
402
+ container (Tile, Bar) this asks about the space it was given. */
371
403
  /* Warning: because we define a fallback
372
404
  media query, the media query can override the container
373
405
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -13,6 +13,49 @@
13
13
  $sidebar-compact-max: 512px;
14
14
  $sidebar-wide-min: 513px;
15
15
 
16
+ /* The "small" size tier: a component whose container is this wide or less
17
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
18
+
19
+ The convention, shared by every component that has a size worth changing
20
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
21
+
22
+ --{component}-{property}-small
23
+
24
+ applies inside a small container. What wins there, in order:
25
+ 1. the `-small` variable, if you set it;
26
+ 2. otherwise the regular variable, if you set it -- a size you chose on
27
+ purpose is not overridden behind your back;
28
+ 3. otherwise the component's own small default, which for most
29
+ properties is simply its regular default.
30
+
31
+ Container queries can't read a custom property, so the breakpoint itself
32
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
33
+ which already switched there. (The Sidebar's rail-to-sheet switch,
34
+ above, is a separate, layout-chrome decision and keeps its own value.) */
35
+ $small-max: 600px;
36
+
37
+ /* Styles for the small tier: the nearest container is narrow, OR the
38
+ viewport is.
39
+
40
+ The container query is the real answer -- a Tile in a 400px pane on a
41
+ desktop is small. But a container query only matches inside an ancestor
42
+ that *is* a container, and a component dropped straight into a page (no
43
+ Page, no Container around it) has none, so on a phone it would never
44
+ find out. The viewport query covers that: a narrow viewport means every
45
+ container in it is narrow too, so the two never disagree in the
46
+ direction that matters.
47
+
48
+ An element never queries itself, so on a component that is its own
49
+ container (Tile, Bar) this asks about the space it was given. */
50
+ @mixin when-small {
51
+ @media (max-width: #{$small-max}) {
52
+ @content;
53
+ }
54
+ @container (max-width: #{$small-max}) {
55
+ @content;
56
+ }
57
+ }
58
+
16
59
 
17
60
  /* Warning: because we define a fallback
18
61
  media query, the media query can override the container
@@ -78,6 +78,38 @@ const el = $derived(elementProps(restProps, "text-layout", ["marginBlock", "marg
78
78
  we deliberately avoid everywhere else.
79
79
 
80
80
  One definition, used by both, so they cannot drift again. */
81
+ /* The "small" size tier: a component whose container is this wide or less
82
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
83
+
84
+ The convention, shared by every component that has a size worth changing
85
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
86
+
87
+ --{component}-{property}-small
88
+
89
+ applies inside a small container. What wins there, in order:
90
+ 1. the `-small` variable, if you set it;
91
+ 2. otherwise the regular variable, if you set it -- a size you chose on
92
+ purpose is not overridden behind your back;
93
+ 3. otherwise the component's own small default, which for most
94
+ properties is simply its regular default.
95
+
96
+ Container queries can't read a custom property, so the breakpoint itself
97
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
98
+ which already switched there. (The Sidebar's rail-to-sheet switch,
99
+ above, is a separate, layout-chrome decision and keeps its own value.) */
100
+ /* Styles for the small tier: the nearest container is narrow, OR the
101
+ viewport is.
102
+
103
+ The container query is the real answer -- a Tile in a 400px pane on a
104
+ desktop is small. But a container query only matches inside an ancestor
105
+ that *is* a container, and a component dropped straight into a page (no
106
+ Page, no Container around it) has none, so on a phone it would never
107
+ find out. The viewport query covers that: a narrow viewport means every
108
+ container in it is narrow too, so the two never disagree in the
109
+ direction that matters.
110
+
111
+ An element never queries itself, so on a component that is its own
112
+ container (Tile, Bar) this asks about the space it was given. */
81
113
  /* Warning: because we define a fallback
82
114
  media query, the media query can override the container
83
115
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -305,6 +337,10 @@ div {
305
337
  --_prose-margin-inline: var(--body-prose-margin-inline, var(--text-prose-margin-inline, var(--prose-margin-inline, auto)));
306
338
  --_heading-margin-inline: var(--body-heading-margin-inline, var(--text-heading-margin-inline, var(--heading-margin-inline, auto)));
307
339
  width: var(--text-width, var(--body-width, 100%));
340
+ /* width is 100% by default and padding-inline is added on top -- without
341
+ border-box a TextLayout is always 2 * padding wider than its parent,
342
+ which on a phone means a sideways scroll before anything else loads. */
343
+ box-sizing: border-box;
308
344
  /* Not margin-props() (_box.scss): that defaults both axes to 0, but a
309
345
  TextLayout has always centred itself horizontally by default. Same
310
346
  var-with-fallbacks() shape as everywhere else, just inline defaults to
@@ -357,6 +393,17 @@ div :global(code) {
357
393
  text-wrap: nowrap;
358
394
  }
359
395
 
396
+ /* Inline code (a CSS variable name, a prop signature) reads best unbroken,
397
+ so it stays on one line -- until the column it sits in is too narrow for
398
+ that to be a choice. There a long token like --grid-layout-justify-content
399
+ is wider than the whole line, and refusing to break it pushes the layout
400
+ sideways; let it wrap, and mid-token if it has to. */
401
+ @container (max-width: 30rem) {
402
+ div :global(:not(pre) > code) {
403
+ text-wrap: wrap;
404
+ overflow-wrap: anywhere;
405
+ }
406
+ }
360
407
  /* Everywhere else, heading styling is consumed once, globally, by the
361
408
  :where()-scoped rule in vars/typography-context.css -- zero specificity, so
362
409
  any real selector easily overrides it. TextLayout is the one exception:
@@ -12,9 +12,17 @@
12
12
  --inactive-bg: var(--material-color-grey-400);
13
13
  --inactive-fg: var(--material-color-grey-900);
14
14
 
15
- /* Fallback colors - themes can override these */
16
- --bg: #fcfcff;
17
- --fg: #1b1d2e;
15
+ /* Fallback colors - themes can override these.
16
+
17
+ Neutral on purpose: this file is the base every theme (and every app
18
+ with no theme at all) inherits before anything else runs, so a tint
19
+ here reaches apps that never asked for it. A theme that wants a
20
+ particular cast -- indigo, warm, whatever -- sets --bg/--fg itself
21
+ (see themes/light.css); --border-color below already derives from
22
+ whatever --bg/--fg a theme (or an app) actually provides, so a themed
23
+ app gets a themed border for free without this file picking a hue. */
24
+ --bg: var(--material-color-grey-50);
25
+ --fg: var(--material-color-grey-900);
18
26
 
19
27
  --stripe-fg: var(--menu-fg, var(--fg));
20
28
  --stripe-bg: color-mix(
@@ -53,7 +61,12 @@
53
61
  affordances.css. The color-props(menu-item, menu, button, control) chain
54
62
  resolves it to --menu-bg / --bg at the element, keeping per-instance
55
63
  --menu-bg overrides working. */
56
- --focus-color: var(--material-color-indigo-a200);
64
+ /* --focus-color intentionally not defaulted here either: both consumers
65
+ (_affordances.scss's outline rule, Tag's close-button outline) already
66
+ fall back to the browser's own focus ring / currentColor when it's
67
+ unset, which is exactly the neutral behavior an un-themed app should
68
+ get. A theme that wants a specific ring sets --focus-color itself
69
+ (see themes/light.css, themes/material.css, themes/purple.css). */
57
70
  --tooltip-border: none;
58
71
  }
59
72
 
@@ -64,7 +77,10 @@ body {
64
77
 
65
78
  a {
66
79
  background-color: var(--link-bg, transparent);
67
- color: var(--link-fg, var(--material-color-indigo-700));
80
+ /* Same reasoning as --surface-link-fg above: derive from the theme's own
81
+ --primary-bg (always defined, even for an app with no theme at all)
82
+ rather than hard-coding a hue here too. */
83
+ color: var(--link-fg, var(--primary-bg));
68
84
  }
69
85
 
70
86
  /* Color definitions */
@@ -306,9 +306,17 @@
306
306
  --inactive-bg: var(--material-color-grey-400);
307
307
  --inactive-fg: var(--material-color-grey-900);
308
308
 
309
- /* Fallback colors - themes can override these */
310
- --bg: #fcfcff;
311
- --fg: #1b1d2e;
309
+ /* Fallback colors - themes can override these.
310
+
311
+ Neutral on purpose: this file is the base every theme (and every app
312
+ with no theme at all) inherits before anything else runs, so a tint
313
+ here reaches apps that never asked for it. A theme that wants a
314
+ particular cast -- indigo, warm, whatever -- sets --bg/--fg itself
315
+ (see themes/light.css); --border-color below already derives from
316
+ whatever --bg/--fg a theme (or an app) actually provides, so a themed
317
+ app gets a themed border for free without this file picking a hue. */
318
+ --bg: var(--material-color-grey-50);
319
+ --fg: var(--material-color-grey-900);
312
320
 
313
321
  --stripe-fg: var(--menu-fg, var(--fg));
314
322
  --stripe-bg: color-mix(
@@ -347,7 +355,12 @@
347
355
  affordances.css. The color-props(menu-item, menu, button, control) chain
348
356
  resolves it to --menu-bg / --bg at the element, keeping per-instance
349
357
  --menu-bg overrides working. */
350
- --focus-color: var(--material-color-indigo-a200);
358
+ /* --focus-color intentionally not defaulted here either: both consumers
359
+ (_affordances.scss's outline rule, Tag's close-button outline) already
360
+ fall back to the browser's own focus ring / currentColor when it's
361
+ unset, which is exactly the neutral behavior an un-themed app should
362
+ get. A theme that wants a specific ring sets --focus-color itself
363
+ (see themes/light.css, themes/material.css, themes/purple.css). */
351
364
  --tooltip-border: none;
352
365
  }
353
366
  body {
@@ -356,7 +369,10 @@ body {
356
369
  }
357
370
  a {
358
371
  background-color: var(--link-bg, transparent);
359
- color: var(--link-fg, var(--material-color-indigo-700));
372
+ /* Same reasoning as --surface-link-fg above: derive from the theme's own
373
+ --primary-bg (always defined, even for an app with no theme at all)
374
+ rather than hard-coding a hue here too. */
375
+ color: var(--link-fg, var(--primary-bg));
360
376
  }
361
377
  /* Color definitions */
362
378
  :root {
@@ -873,7 +889,10 @@ body {
873
889
  --icon-size: 32px;
874
890
  /* Cards */
875
891
  --card-width: 420px;
876
- --card-width-small: 250px;
892
+ /* In the small tier a Card fills the space it's given (Card's max-width
893
+ still keeps it inside its margins). Was 250px: a narrow card adrift in a
894
+ 390px phone, small enough to trip Card's own narrow-card styles. */
895
+ --card-width-small: 100%;
877
896
  --card-width-large: 600px;
878
897
  --card-height: 300px;
879
898
  --card-height-small: 150px;
@@ -47,7 +47,10 @@ body {
47
47
  --icon-size: 32px;
48
48
  /* Cards */
49
49
  --card-width: 420px;
50
- --card-width-small: 250px;
50
+ /* In the small tier a Card fills the space it's given (Card's max-width
51
+ still keeps it inside its margins). Was 250px: a narrow card adrift in a
52
+ 390px phone, small enough to trip Card's own narrow-card styles. */
53
+ --card-width-small: 100%;
51
54
  --card-width-large: 600px;
52
55
  --card-height: 300px;
53
56
  --card-height-small: 150px;
@@ -1,6 +1,9 @@
1
+ /* 16px is the floor, not 14: phones are where small text hurts most, and
2
+ iOS Safari zooms the page whenever an input under 16px takes focus. The
3
+ scale grows from there on bigger screens. */
1
4
  @media screen and (max-width: 800px) {
2
5
  :root {
3
- --font-size: 14px;
6
+ --font-size: 16px;
4
7
  --text-size: var(--font-size);
5
8
  --ui-size: var(--font-size);
6
9
  font-size: var(--font-size);