@kolkrabbi/kol-theme 0.155.0 → 0.157.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.
@@ -31,7 +31,7 @@
31
31
  * range. Use when a step has to go past the theme's own ink:
32
32
  * "applying a percentage of primary on top of primary won't make
33
33
  * it darker, but applying a percentage of 000000 will."
34
- * absolute THE THEME'S OWN near-black / near-white, FROZEN. Same colour in
34
+ * absolute THE THEME'S OWN near-black / near-white, FROZEN. Same color in
35
35
  * light and dark — the original meaning of the word here, before
36
36
  * the 2026-08-28 rename collapsed it into an alias of `ab`.
37
37
  *
@@ -196,3 +196,31 @@
196
196
  --kol-surface-absolute-split: var(--kol-surface-ab-split);
197
197
  --kol-surface-absolute-split-inverse: var(--kol-surface-ab-split-inverse);
198
198
  }
199
+
200
+ /* ═══════════════════════════════════════════════════════════════
201
+ * THE CONTROL LADDER, AS TOKENS — and its TOUCH RUNG (ruling D5, apps review 2026-09-29)
202
+ *
203
+ * 22 · 26 · 32 · 40 (01-foundations/09-sizes.md). Every PINNED control height — an icon-only
204
+ * square, a dropdown trigger, a segmented strip, an IconFrame, a menu trigger — reads these, so the
205
+ * pinned boxes and the derived ones (padding + line-height + ring) move together.
206
+ *
207
+ * On a coarse pointer every text field must type at 16px or iOS zooms the page into it
208
+ * (OverlaySearchFieldZoomsIOS, 2026-09-01) — which put 16px text in a 26px `sm` box beside 12px
209
+ * buttons (the user: "bigger text than its relative height"). So on touch the WHOLE ladder takes
210
+ * 16 / 22 type and every box grows with it: xs 32 · sm 32 · md 36 · lg 40. One row, one height,
211
+ * on a phone as at a desk. The type rule lives with the controls (kol-components-atoms.css).
212
+ * ═══════════════════════════════════════════════════════════════ */
213
+ :root {
214
+ --kol-ctl-xs: 22px;
215
+ --kol-ctl-sm: 26px;
216
+ --kol-ctl-md: 32px;
217
+ --kol-ctl-lg: 40px;
218
+ }
219
+ @media (pointer: coarse) {
220
+ :root {
221
+ --kol-ctl-xs: 32px;
222
+ --kol-ctl-sm: 32px;
223
+ --kol-ctl-md: 36px;
224
+ --kol-ctl-lg: 40px;
225
+ }
226
+ }
package/kol-color.css CHANGED
@@ -108,7 +108,7 @@
108
108
  /* SURFACE-DERIVED chrome tokens live on the THEME selectors, not `:root` alone
109
109
  * (0.52.0, nested-theme-scope) — same reason as the fg ramp in kol-opacity.css:
110
110
  * a var() resolves where the property is declared, so a themed SUBTREE that
111
- * flips --kol-surface-on-primary kept the root's border colour (a white 8%
111
+ * flips --kol-surface-on-primary kept the root's border color (a white 8%
112
112
  * hairline on white paper). The accent family stays in the :root block above
113
113
  * on purpose: kol-brand-color.css rebinds it at :root only, and a themed
114
114
  * re-declaration here would hand a branded app's nested pane the neutral
@@ -179,7 +179,7 @@
179
179
  }
180
180
 
181
181
  /* POSITION ONLY. The control is a DS Button (quiet, icon-only) as of
182
- * 2026-08-01 — it brings its own box, border, colour set and states, so this
182
+ * 2026-08-01 — it brings its own box, border, color set and states, so this
183
183
  * class stopped painting one. It used to hand-draw a bordered square around a
184
184
  * literal `×` CHARACTER, which is why the button had no hover, no focus ring
185
185
  * and no glyph.
@@ -296,10 +296,10 @@
296
296
  * shorter, at `xs` 2px shorter. Three families (control shell, text button,
297
297
  * segmented) already agreed on 22/26/32/40, so the squares conform to them, not
298
298
  * the other way round. Glyphs are untouched — SOLO still resolves 16/20/24. */
299
- .kol-btn-icon.kol-btn-xs { width: 22px; height: 22px; padding: 0; }
300
- .kol-btn-icon.kol-btn-sm { width: 26px; height: 26px; padding: 0; }
301
- .kol-btn-icon.kol-btn-md { width: 32px; height: 32px; padding: 0; }
302
- .kol-btn-icon.kol-btn-lg { width: 40px; height: 40px; padding: 0; }
299
+ .kol-btn-icon.kol-btn-xs { width: var(--kol-ctl-xs); height: var(--kol-ctl-xs); padding: 0; }
300
+ .kol-btn-icon.kol-btn-sm { width: var(--kol-ctl-sm); height: var(--kol-ctl-sm); padding: 0; }
301
+ .kol-btn-icon.kol-btn-md { width: var(--kol-ctl-md); height: var(--kol-ctl-md); padding: 0; }
302
+ .kol-btn-icon.kol-btn-lg { width: var(--kol-ctl-lg); height: var(--kol-ctl-lg); padding: 0; }
303
303
 
304
304
  /* ─── Variants — the ground ones are TONES now (2026-09-03) ───
305
305
  * `.kol-btn-primary` · `-secondary` · `-outline` · `-ghost` · `-grey` are
@@ -332,7 +332,7 @@
332
332
  * Outside the hover guard: :active fires on touch too. */
333
333
  /* NO HOVER, NO PRESS ON A DROPDOWN TRIGGER (user ruling 2026-08-28). Every
334
334
  * variant excludes `.kol-dd-trigger` at the SOURCE. It used to be cancelled
335
- * downstream — kol-components-molecules re-stated each variant's rest colours
335
+ * downstream — kol-components-molecules re-stated each variant's rest colors
336
336
  * on :hover — and that restatement was specificity (0,4,0) against the sunken
337
337
  * tone's (0,2,0), so hovering a SUNKEN trigger repainted it in the untoned
338
338
  * fill: a light box beside two icon controls that stayed dark. */
@@ -639,7 +639,7 @@
639
639
  * element, and an element's own declaration beats anything it would inherit —
640
640
  * so the override the component's docstring promised was unreachable from any
641
641
  * ancestor. Consumers were reaching into `.slider-black` by specificity from
642
- * their own stylesheets to get a track colour. `.kol-slider-dual-playhead`
642
+ * their own stylesheets to get a track color. `.kol-slider-dual-playhead`
643
643
  * below had it right from the start; this now matches it. */
644
644
  -webkit-appearance: none;
645
645
  appearance: none;
@@ -702,7 +702,7 @@
702
702
  * grabbed. In-mark is hollow (surface fill, ink ring), out-mark is solid, which
703
703
  * is the treatment mirror's local copy proved over months.
704
704
  *
705
- * The playhead colour is a TOKEN. Mirror hardcoded `#2dd4bf`, which is the
705
+ * The playhead color is a TOKEN. Mirror hardcoded `#2dd4bf`, which is the
706
706
  * defect this move exists to end: a literal cannot follow a theme or a
707
707
  * consumer's brand. `--kol-slider-playhead` defaults to the accent and is
708
708
  * overridable per instance. */
@@ -1132,6 +1132,17 @@ a:hover .icon-hover,
1132
1132
  border: 1px solid var(--kol-tone-border, transparent);
1133
1133
  }
1134
1134
 
1135
+ /* THE KOL RING ON AN ACTIONABLE FRAME (2026-09-30 — the header's icon buttons drew the browser's
1136
+ * blue ring: IconFrame renders a bare <button>/<a>, not `.kol-btn`, so it had no focus rule). The
1137
+ * same ring as every Button: `--kol-focus-ring`, keyboard focus only. */
1138
+ a.kol-icon-frame:focus-visible,
1139
+ button.kol-icon-frame:focus-visible {
1140
+ outline: 2px solid var(--kol-focus-ring);
1141
+ outline-offset: 2px;
1142
+ }
1143
+ a.kol-icon-frame:focus:not(:focus-visible),
1144
+ button.kol-icon-frame:focus:not(:focus-visible) { outline: none; }
1145
+
1135
1146
  /* An ACTIONABLE frame — `onClick`/`href` (user ruling 2026-08-01: *"you dont
1136
1147
  * use a button… you use the ICON COMPONENT… it has no interactive states"*).
1137
1148
  *
@@ -1170,10 +1181,10 @@ a.kol-icon-frame {
1170
1181
  /* pinned squares — the box never moves with glyph size (user law 2026-07-28),
1171
1182
  * on the size's HEIGHT so a frame lines up with the Button, Input and Dropdown
1172
1183
  * beside it (user ruling 2026-09-02 — see .kol-btn-icon above). 22/26/32/40. */
1173
- .kol-icon-frame-xs { width: 22px; height: 22px; }
1174
- .kol-icon-frame-sm { width: 26px; height: 26px; }
1175
- .kol-icon-frame-md { width: 32px; height: 32px; }
1176
- .kol-icon-frame-lg { width: 40px; height: 40px; }
1184
+ .kol-icon-frame-xs { width: var(--kol-ctl-xs); height: var(--kol-ctl-xs); }
1185
+ .kol-icon-frame-sm { width: var(--kol-ctl-sm); height: var(--kol-ctl-sm); }
1186
+ .kol-icon-frame-md { width: var(--kol-ctl-md); height: var(--kol-ctl-md); }
1187
+ .kol-icon-frame-lg { width: var(--kol-ctl-lg); height: var(--kol-ctl-lg); }
1177
1188
 
1178
1189
  /* `.kol-icon-frame-{primary,secondary,accent,outline,ghost,nav,grey,danger}` — tone aliases, see TONE */
1179
1190
  .kol-icon-frame-plate {
@@ -1199,7 +1210,7 @@ a.kol-icon-frame {
1199
1210
  * at rest, shown on hover of the tile (`.kol-media-tile`) or on focus, over
1200
1211
  * full-bleed artwork. Declared AFTER the variants so it wins in-layer — the
1201
1212
  * consumer no longer restates bg-fg-inverse-64 / border-fg-96 beside the
1202
- * variant. Absolute colours: it sits on artwork, not on the theme. NO
1213
+ * variant. Absolute colors: it sits on artwork, not on the theme. NO
1203
1214
  * backdrop-filter — it flips the tile onto a composited layer on hover and the
1204
1215
  * artwork's saturation jumps (Chrome). */
1205
1216
  .kol-play-disc {
@@ -1310,6 +1321,15 @@ a.kol-icon-frame {
1310
1321
  * own; it exists so the floor below keys on every body plan the DS ships,
1311
1322
  * including the chrome-less one. */
1312
1323
  @media (pointer: coarse) {
1324
+ /* THE TOUCH RUNG (D5, 2026-09-29 — see kol-base-tokens.css): every text control types 16 / 22 on
1325
+ * touch, so a derived box grows exactly as the pinned tokens do — xs/sm 4+4+22+2 = 32, md
1326
+ * 6+6+22+2 = 36, lg 40. Two classes, so it outranks the size's own kol-mono-* class. */
1327
+ .kol-btn.kol-btn-xs, .kol-btn.kol-btn-sm, .kol-btn.kol-btn-md, .kol-btn.kol-btn-lg,
1328
+ .kol-control.kol-control-xs, .kol-control.kol-control-sm, .kol-control.kol-control-md, .kol-control.kol-control-lg,
1329
+ .kol-seg .kol-seg-cell, .kol-menu-btn.kol-menu-btn {
1330
+ font-size: 16px;
1331
+ line-height: 22px;
1332
+ }
1313
1333
  .kol-control input,
1314
1334
  .kol-control--bare input,
1315
1335
  .kol-expand input {
@@ -11,7 +11,7 @@
11
11
  * LEDs are the set's own emitters, deliberately NOT `--kol-palette-*` (user
12
12
  * ruling: "leds and the colors should stay, they are unique to this set").
13
13
  *
14
- * `JackSocket` appends a hex alpha to its role colour for the glow, so the two
14
+ * `JackSocket` appends a hex alpha to its role color for the glow, so the two
15
15
  * jack roles must resolve to HEX on :root — a consumer overriding them binds a
16
16
  * hex, never a var().
17
17
  * --------------------------------------------------------------------------- */
@@ -3,7 +3,7 @@
3
3
  * =============================================================================
4
4
  * Component CSS for the type-specimen apparatus. Recreated 2026-07-09 when the
5
5
  * type-specimen kit + live-font effects (TypeSample, TypeSpecCard, TextPressure,
6
- * ColorLoader) moved from @kolkrabbi/kol-component into @kolkrabbi/kol-foundry;
6
+ * IntroLoader, then ColorLoader) moved from @kolkrabbi/kol-component into @kolkrabbi/kol-foundry;
7
7
  * their rules moved here from kol-components-atoms.css with them. CSS always
8
8
  * lives in kol-theme — the foundry package ships JS only.
9
9
  *
@@ -32,7 +32,7 @@
32
32
  Everything else (layout, sizing, weight) is Tailwind utilities / inline vars
33
33
  on the JSX. Stroke color comes in through the inline `--kol-text-pressure-
34
34
  stroke` custom property (defaulted here so the rule is standalone-safe).
35
- ColorLoader composes TextPressure and needs no rules of its own. */
35
+ IntroLoader composes TextPressure and needs no rules of its own. */
36
36
  .kol-text-pressure--stroke .kol-text-pressure-char {
37
37
  position: relative;
38
38
  }
@@ -59,15 +59,15 @@
59
59
  gap: 0;
60
60
  position: relative;
61
61
  }
62
- .kol-dd-trigger.kol-btn-xs { height: 22px; padding-block: 0; }
63
- .kol-dd-trigger.kol-btn-sm { height: 26px; padding-block: 0; }
64
- .kol-dd-trigger.kol-btn-md { height: 32px; padding-block: 0; }
65
- .kol-dd-trigger.kol-btn-lg { height: 40px; padding-block: 0; }
62
+ .kol-dd-trigger.kol-btn-xs { height: var(--kol-ctl-xs); padding-block: 0; }
63
+ .kol-dd-trigger.kol-btn-sm { height: var(--kol-ctl-sm); padding-block: 0; }
64
+ .kol-dd-trigger.kol-btn-md { height: var(--kol-ctl-md); padding-block: 0; }
65
+ .kol-dd-trigger.kol-btn-lg { height: var(--kol-ctl-lg); padding-block: 0; }
66
66
  /* REST AND OPEN ARE THE ONLY STATES (2026-07-15, re-called 2026-08-09 and
67
67
  * 2026-08-28). No :hover or :active rules for the trigger live here any more —
68
68
  * kol-components-atoms.css excludes `.kol-dd-trigger` from every variant's
69
69
  * hover and press instead. The pin-backs that stood here restated each
70
- * variant's REST colours to cancel the button's, and that failed twice: one
70
+ * variant's REST colors to cancel the button's, and that failed twice: one
71
71
  * went stale when `.kol-btn-outline`'s rest border moved (2026-08-26), and a
72
72
  * pin-back out-specifies the tone, so a sunken trigger hovered into the
73
73
  * untoned fill. "No state" is an absence now, not a mirror. */
@@ -440,9 +440,9 @@
440
440
  }
441
441
  .kol-tag-dismiss:hover { opacity: 1; }
442
442
 
443
- /* The per-colour tag palette was DELETED 2026-08-01 with the `color` prop.
443
+ /* The per-color tag palette was DELETED 2026-08-01 with the `color` prop.
444
444
  * A chip's look is its variant now (kol-tag--primary|secondary|inverse), the
445
- * same vocabulary Pill and Button use. Tag colour BY TAXONOMY returns later
445
+ * same vocabulary Pill and Button use. Tag color BY TAXONOMY returns later
446
446
  * as its own decision, layered ON the variants rather than replacing them. */
447
447
 
448
448
  .control-unified-inverse {
@@ -581,14 +581,14 @@
581
581
  * forced the pin). Same principle as .kol-btn-icon's pinned square:
582
582
  * the box never moves. */
583
583
  box-sizing: border-box;
584
- height: 32px; /* md — .kol-btn-md */
584
+ height: var(--kol-ctl-md); /* md — .kol-btn-md */
585
585
  }
586
586
 
587
587
  /* Sizes mirror .kol-btn-{sm,md,lg} exactly: pinned height above + cell
588
588
  * padding per size (below) + mono type (12/14/16) applied in JSX. */
589
- .kol-seg--xs { height: 22px; }
590
- .kol-seg--sm { height: 26px; }
591
- .kol-seg--lg { height: 40px; }
589
+ .kol-seg--xs { height: var(--kol-ctl-xs); }
590
+ .kol-seg--sm { height: var(--kol-ctl-sm); }
591
+ .kol-seg--lg { height: var(--kol-ctl-lg); }
592
592
  .kol-seg--xs .kol-seg-cell { padding: 4px 8px; }
593
593
  .kol-seg--sm .kol-seg-cell { padding: 4px 12px; }
594
594
  .kol-seg--lg .kol-seg-cell { padding: 8px 20px; }
@@ -632,7 +632,7 @@
632
632
 
633
633
  /* Reads the quiet ring token so the segmented strip is part of the system-wide
634
634
  * focus off switch (FocusRingsInConsumers, 2026-08-15). This is the LAST
635
- * hardcoded focus colour in the theme — with it, `--kol-focus-ring` +
635
+ * hardcoded focus color in the theme — with it, `--kol-focus-ring` +
636
636
  * `--kol-focus-ring-quiet` set to transparent turns every ring off, which is
637
637
  * the whole point of the pair. Offset stays -2px: the cell's own inset, not
638
638
  * the rails' -1px. */
@@ -1043,7 +1043,7 @@
1043
1043
  /* the FALLBACK is not optional. A variant with no frame publishes no
1044
1044
  * `--kol-row-border`, and `border-color: var(--undefined)` is invalid at
1045
1045
  * computed-value time — it resolves to `unset`, which INHERITS, which is
1046
- * currentColor, which is the text colour. That is how `default`'s hairline
1046
+ * currentColor, which is the text color. That is how `default`'s hairline
1047
1047
  * divider rendered as a solid white rule. */
1048
1048
  border-color: var(--kol-row-border, transparent);
1049
1049
  transition: background-color 300ms var(--kol-ease-house),
@@ -1238,7 +1238,7 @@
1238
1238
  }
1239
1239
  }
1240
1240
 
1241
- /* The card's rest colours, for the same reason as .kol-row — an inline
1241
+ /* The card's rest colors, for the same reason as .kol-row — an inline
1242
1242
  * background/borderColor outranks .kol-content-hover:hover, so the step
1243
1243
  * silently never rendered.
1244
1244
  * `background-clip: padding-box` (CardCornerLeak, kol-monitor 2026-08-28,
@@ -1612,7 +1612,7 @@
1612
1612
 
1613
1613
  /* THE QUICKTIME BAR (PlaybackBarAndAudioSheet, kol-r2b2 2026-08-27 — ruled
1614
1614
  * against the reference). White glyphs on the frosted strip whatever the theme:
1615
- * the ghost IconFrame paints --kol-oq-48, a theme colour, and the bar sits on
1615
+ * the ghost IconFrame paints --kol-oq-48, a theme color, and the bar sits on
1616
1616
  * media, not on the theme. The scrubber is a native range — a 2px track at 40 %
1617
1617
  * white, a tall 4 × 28 white pill for the knob — pseudo-elements, so CSS. */
1618
1618
  .kol-playback-bar .kol-icon-frame { color: var(--kol-color-ab-white); opacity: 0.8; }
@@ -1850,7 +1850,7 @@
1850
1850
  * layer (user: *"we are talking about components, wash affects background"*):
1851
1851
  * a control has no business reproducing a page-level film, and portalling
1852
1852
  * proved it — `.kol-dd-panel` renders at document.body, could not inherit the
1853
- * property, and drew a different colour from its own trigger. Reverted.
1853
+ * property, and drew a different color from its own trigger. Reverted.
1854
1854
  * The collision is a PAGE/token question and belongs there.
1855
1855
  *
1856
1856
  * THE SUNKEN TONE IS `surface-tertiary`, NOT `oq-inverse-96` (measured on
@@ -1882,7 +1882,7 @@
1882
1882
  * `.kol-control` and `.kol-dd-panel` each re-invented it with paints that
1883
1883
  * drifted (`primary` painting `surface-secondary`; the panel's outline
1884
1884
  * hardcoding `surface-primary`, so a dropdown opened over any other ground
1885
- * changed the colour under it).
1885
+ * changed the color under it).
1886
1886
  *
1887
1887
  * SIX TONES, ONE MECHANISM. A tone is a bundle of `--kol-tone-*` custom
1888
1888
  * properties — rest, hover, press, pressed, and what a FLOATING surface of
@@ -1975,9 +1975,9 @@
1975
1975
  * 2026-09-03; user: "I told you I wanted primary surface as a tone … that tone
1976
1976
  * should be called secondary. What is currently secondary should be called
1977
1977
  * inverted."). 0.134.0 lifted the name from Button's `secondary` VARIANT, which
1978
- * was already an inverse, and the page's own colour had no tone at all. The
1978
+ * was already an inverse, and the page's own color had no tone at all. The
1979
1979
  * variant keeps its pixels — it aliases `inverted` below — only the tone word
1980
- * moved. Hover / press are primary's rungs over the page colour. */
1980
+ * moved. Hover / press are primary's rungs over the page color. */
1981
1981
  .kol-tone-secondary {
1982
1982
  --kol-tone-bg: var(--kol-surface-primary);
1983
1983
  --kol-tone-image: none;
@@ -1996,7 +1996,7 @@
1996
1996
  --kol-tone-panel-border-w: 0;
1997
1997
  --kol-tone-panel-border: transparent;
1998
1998
  }
1999
- /* `inverted` — the text colour as fill: Button's / IconFrame's `secondary`
1999
+ /* `inverted` — the text color as fill: Button's / IconFrame's `secondary`
2000
2000
  * variant and the panel's `--secondary`, under the name the user gave it.
2001
2001
  * (`inverse` is NOT this: it is sunken's alias from 0.117.0, still on one
2002
2002
  * kol-website call, and stays that until it is dropped — the two words were
@@ -2201,7 +2201,7 @@
2201
2201
  * vanishes on secondary's near-black well. It takes SUNKEN'S RUNG, `fg-08` (the 2026-08-28 ruling, down
2202
2202
  * from fg-16): the tones' own `--kol-tone-active-bg` was tried first and secondary's `oq-16` read
2203
2203
  * "too bright" (user, same day) — that rung is a button's press, not a chip in a well. `inverted` is
2204
- * the exception: its well is the ink colour, where an ink wash disappears, so it keeps its own active
2204
+ * the exception: its well is the ink color, where an ink wash disappears, so it keeps its own active
2205
2205
  * paint. No tone = the fixed chip, as before. */
2206
2206
  :is(.kol-tone-primary, .kol-tone-secondary, .kol-tone-outline, .kol-tone-ghost, .kol-tone-grey) .kol-view-toggle button[aria-pressed="true"],
2207
2207
  .kol-view-toggle:is(.kol-tone-primary, .kol-tone-secondary, .kol-tone-outline, .kol-tone-ghost, .kol-tone-grey) button[aria-pressed="true"] {
@@ -166,7 +166,7 @@
166
166
  .kol-table-token {
167
167
  /* THE LOOK LIVES IN ONE PLACE (2026-08-09) — the shared chip recipe in
168
168
  * kol-type-roles.css (`.kol-prose code, .kol-doc-code-inline,
169
- * .kol-table-token`): font, size, weight, colour, fill, padding, radius.
169
+ * .kol-table-token`): font, size, weight, color, fill, padding, radius.
170
170
  * This rule keeps only the CELL mechanics the prose chip must not have. */
171
171
  display: inline-flex;
172
172
  align-items: center;
@@ -41,7 +41,9 @@
41
41
  .kol-shell-page {
42
42
  display: flex;
43
43
  flex-direction: column;
44
- min-height: 100vh;
44
+ /* less the phone bar (`--kol-shell-bar-h`, set by AppShell `touch="bar"`): the content column
45
+ * already pads for it, so a full-height page ends above the bar, not under it (2026-09-29) */
46
+ min-height: calc(100vh - var(--kol-shell-bar-h, 0px));
45
47
  padding: var(--kol-shell-page-pad);
46
48
  /* PageShellScrollbarGutter (kol-monitor 2026-08-28): in `fixed` mode this
47
49
  * element IS the scroll container and reserves the gutter; in `scroll` mode
@@ -58,7 +60,7 @@
58
60
  }
59
61
  /* `mode="fixed"` — the element is the scroll container; pair with a
60
62
  * `flex:1 overflow:auto` body (the settings idiom) */
61
- .kol-shell-page--fixed { min-height: 0; height: 100vh; overflow: hidden; }
63
+ .kol-shell-page--fixed { min-height: 0; height: calc(100vh - var(--kol-shell-bar-h, 0px)); overflow: hidden; }
62
64
  /* `width="capped"` — the SITE tier: the framework container ladder, centred.
63
65
  * `bleed` (the default, unclassed) fills the window — the app tier. The one
64
66
  * real difference between a shell page and a `.kol-page`, and it is a prop
@@ -202,6 +204,34 @@
202
204
  background: color-mix(in srgb, var(--kol-color-ab-black) 48%, transparent);
203
205
  }
204
206
 
207
+ /* ── THE PHONE BAR (AppShell `touch="bar"`, apps review 2026-09-29) — the rail as kol-component's
208
+ * MobileTabBar below 768; past five destinations the fifth tab is More, and More is this sheet,
209
+ * floated just above the bar. The scrim sits under the bar, so More stays tappable to close. */
210
+ .kol-phone-nav-scrim {
211
+ position: fixed;
212
+ inset: 0;
213
+ z-index: calc(var(--kol-z-sticky) - 1);
214
+ border: 0;
215
+ padding: 0;
216
+ cursor: default;
217
+ }
218
+ .kol-phone-nav-more {
219
+ position: fixed;
220
+ left: 12px;
221
+ right: 12px;
222
+ bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 8px);
223
+ z-index: var(--kol-z-sticky);
224
+ display: flex;
225
+ flex-direction: column;
226
+ gap: 2px;
227
+ max-height: 60dvh;
228
+ overflow-y: auto;
229
+ padding: 8px;
230
+ border-radius: var(--kol-radius-sm);
231
+ background: var(--kol-surface-primary);
232
+ border: 1px solid var(--kol-oq-08);
233
+ }
234
+
205
235
  /* ── THE TAP OPENER IS THE LINE (ShellRailCollapsedWithTapOpen, kol-mirror
206
236
  * 2026-09-01; corrected by RailGrabTapIsALine, kol-monitor 2026-09-02 — user:
207
237
  * "it was a thicker line" · "who decided it should be a chevron?"). `touch=
@@ -2,14 +2,14 @@
2
2
  * KOL components — style-guide / brand-guide set
3
3
  * =============================================================================
4
4
  * Chrome for the @kolkrabbi/kol-styleguide component set: the combination lab,
5
- * colour anatomy, mood tiles, logo construction/scaling, type blocks, asset
5
+ * color anatomy, mood tiles, logo construction/scaling, type blocks, asset
6
6
  * tables. Raided from the monorepo apps/brand styleguide (2026-07).
7
7
  *
8
8
  * Layer: ships unlayered; kol-theme.css assigns the layer at import —
9
9
  * @import "./kol-components-styleguide.css" layer(components);
10
10
  *
11
- * KOL conformance: resting type + colour live INLINE on the JSX (kol-* type
12
- * classes + kol colour utilities); only structural props Tailwind can't express
11
+ * KOL conformance: resting type + color live INLINE on the JSX (kol-* type
12
+ * classes + kol color utilities); only structural props Tailwind can't express
13
13
  * (grid templates, absolute positioning, transitions, pseudo-elements) live here.
14
14
  *
15
15
  * Rules are consolidated here as each component lands. Some were relocated from
@@ -269,7 +269,7 @@
269
269
  * SECTION the right rail's rows (same PAGE row idiom)
270
270
  *
271
271
  * CHAPTER and PAGE were indistinguishable: both `kol-mono-14`, and the only
272
- * difference was `.text-default` — which is a COLOUR utility, not type. A parent
272
+ * difference was `.text-default` — which is a COLOR utility, not type. A parent
273
273
  * and its children reading identically is not a hierarchy.
274
274
  *
275
275
  * The weight is the difference, and it stays INSIDE the one ramp: 700 here
@@ -285,7 +285,7 @@
285
285
  /* MEDIUM + SHOUT (user ruling 2026-08-01, the settled pair). 700 was tried
286
286
  * for one turn and reverted: with the page rows at Thin 100 the weight gap
287
287
  * already carries, so the CHAPTER buys its prominence from INK instead —
288
- * `shout` (88) against the rows' `fg-64`. Weight and colour each doing half
288
+ * `shout` (88) against the rows' `fg-64`. Weight and color each doing half
289
289
  * the work beats either doing all of it, and 500 keeps the chapter inside
290
290
  * the ramp's normal range. */
291
291
  font-weight: 500;
@@ -371,7 +371,7 @@
371
371
  * locked the TYPE class and nothing locked the stack: the eyebrow-box failure,
372
372
  * one rung down.
373
373
  *
374
- * Layout, colour, hover, transition and focus live HERE now. Markup comes from
374
+ * Layout, color, hover, transition and focus live HERE now. Markup comes from
375
375
  * `RailRow`; `validate:rails` R4 fails a hand-written `shell-nav-item`.
376
376
  *
377
377
  * WEIGHT IS THIN (user ruling 2026-08-01, asked five times).
@@ -443,8 +443,8 @@
443
443
  * 2026-08-01, twice). The first attempt put `text-emphasis` on the row from the
444
444
  * JSX and nothing happened: `.text-emphasis` and `.shell-nav-item` are both
445
445
  * single-class selectors in the same cascade layer, and this file loads AFTER
446
- * kol-opacity.css, so the rail's resting `--kol-fg-64` won every time. A colour
447
- * utility cannot brighten a row whose own rule sets colour — the modifier has
446
+ * kol-opacity.css, so the rail's resting `--kol-fg-64` won every time. A color
447
+ * utility cannot brighten a row whose own rule sets color — the modifier has
448
448
  * to live beside that rule. Same file, same specificity, declared later. */
449
449
  .shell-nav-item--own {
450
450
  color: var(--kol-fg-emphasis);
@@ -107,7 +107,7 @@
107
107
  /* Border radius (4px increments) */
108
108
  --kol-radius-none: 0;
109
109
  /* xs (2026-08-01) — the hairline rung. Claimed out loud: 2px had SIX
110
- hand-written `rounded-[2px]` call sites (swatches, colour rows, the
110
+ hand-written `rounded-[2px]` call sites (swatches, color rows, the
111
111
  glass panel) and no token, so the scale's 4px floor was simply being
112
112
  ignored rather than followed. A value used six times is a rung. */
113
113
  --kol-radius-xs: 2px;
package/kol-opacity.css CHANGED
@@ -491,7 +491,7 @@
491
491
  * `mute` (32%) was retired 2026-04-30 with zero consumers and does not return.
492
492
  *
493
493
  * Tokens chain through the fg ramp — single source of truth is preserved;
494
- * descriptors are aliases, never their own colour values.
494
+ * descriptors are aliases, never their own color values.
495
495
  * ============================================================================== */
496
496
 
497
497
  /* Theme selectors, same reason as the ramp above — the roles chain through
@@ -509,7 +509,7 @@
509
509
  --kol-fg-emphasis: var(--kol-surface-on-primary);
510
510
 
511
511
  /* DEPRECATED ALIAS — `default` is the old name for `body`, kept pointing at
512
- * the same stop so a consumer mid-sweep cannot render colourless. Remove once
512
+ * the same stop so a consumer mid-sweep cannot render colorless. Remove once
513
513
  * no source references it. */
514
514
  --kol-fg-default: var(--kol-fg-body);
515
515
  }
@@ -115,7 +115,7 @@
115
115
  * only shares the word "token".
116
116
  *
117
117
  * The two chips had drifted on every value that makes them look alike: fg-04
118
- * against fg-08, radius-sm against a bare literal, no colour against fg-80.
118
+ * against fg-08, radius-sm against a bare literal, no color against fg-80.
119
119
  * Same concept, two spellings — the `.text-fg-*` vs `--kol-fg-*` lesson again.
120
120
  * ONE RECIPE NOW, size and padding included (user ruling 2026-08-09: "it's
121
121
  * basically the same style, so why are they so different"). The earlier
@@ -276,7 +276,7 @@
276
276
  * uppercase · fg-64; the slot is `eyebrow` on ContentText and SectionText.
277
277
  * `kol-card-kicker` is the alias below, on the retirement ledger. */
278
278
  /* NO ink on the role (ShellHomeSystem, 2026-08-27): type roles set type, not
279
- * colour — a baked fg-64 outranked every ink utility beside it. Consumers that
279
+ * color — a baked fg-64 outranked every ink utility beside it. Consumers that
280
280
  * relied on the 64 pass `text-body`; the `kol-card-kicker` alias keeps it. */
281
281
  .kol-eyebrow {
282
282
  font-family: var(--kol-font-family-mono);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-theme",
3
- "version": "0.155.0",
3
+ "version": "0.157.0",
4
4
  "description": "KOL (Kolkrabbi) design-system tokens + base CSS — brand-neutral. The canonical token/cascade layer every other KOL package and consumer builds on.",
5
5
  "license": "MIT",
6
6
  "type": "module",