@oneli8/core 1.0.0-beta.10 → 1.0.0-beta.12

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/ai-context.json +13 -1
  2. package/package.json +2 -2
  3. package/skills/oneli8-ui/SKILL.md +6 -0
  4. package/src/atoms/icon/icon.css +1 -1
  5. package/src/atoms/icon/icon.js +1 -1
  6. package/src/atoms/icon/icons.generated.d.ts +5 -1
  7. package/src/atoms/icon/icons.generated.js +197 -1
  8. package/src/atoms/navigation-badge/navigation-badge.css +1 -1
  9. package/src/atoms/navigation-badge/navigation-badge.js +1 -1
  10. package/src/atoms/selection-indicator/selection-indicator.css +1 -1
  11. package/src/atoms/selection-indicator/selection-indicator.js +1 -1
  12. package/src/materials/gem/gem.css +190 -13
  13. package/src/molecules/button/button.css +1 -1
  14. package/src/molecules/button/button.js +1 -1
  15. package/src/molecules/choice-chip/choice-chip.css +1 -1
  16. package/src/molecules/choice-chip/choice-chip.js +1 -1
  17. package/src/molecules/choice-item/choice-item.css +1 -1
  18. package/src/molecules/choice-item/choice-item.js +1 -1
  19. package/src/molecules/form-message/form-message.css +1 -1
  20. package/src/molecules/form-message/form-message.js +2 -2
  21. package/src/molecules/icon-button/icon-button.css +1 -1
  22. package/src/molecules/icon-button/icon-button.js +1 -1
  23. package/src/molecules/link/link.css +1 -1
  24. package/src/molecules/link/link.js +1 -1
  25. package/src/molecules/navigation-item/navigation-item.css +1 -1
  26. package/src/molecules/navigation-item/navigation-item.js +1 -1
  27. package/src/molecules/select/select.css +1 -1
  28. package/src/molecules/select/select.js +2 -2
  29. package/src/molecules/selection-option/selection-option.css +1 -1
  30. package/src/molecules/selection-option/selection-option.js +1 -1
  31. package/src/molecules/text-field/text-field.css +1 -1
  32. package/src/molecules/text-field/text-field.js +1 -1
  33. package/src/molecules/token/token.css +1 -1
  34. package/src/molecules/token/token.js +1 -1
  35. package/src/organisms/choice-group/choice-group.css +1 -1
  36. package/src/organisms/choice-group/choice-group.js +1 -1
  37. package/src/organisms/choice-picker/choice-picker.css +1 -1
  38. package/src/organisms/choice-picker/choice-picker.js +1 -1
  39. package/src/organisms/combobox/combobox.css +1 -1
  40. package/src/organisms/combobox/combobox.js +1 -1
  41. package/src/organisms/multi-select-field/multi-select-field.css +1 -1
  42. package/src/organisms/multi-select-field/multi-select-field.js +1 -1
  43. package/src/organisms/segmented-control/segmented-control.css +1 -1
  44. package/src/organisms/segmented-control/segmented-control.js +1 -1
  45. package/src/organisms/selection-popup/selection-popup.css +1 -1
  46. package/src/organisms/selection-popup/selection-popup.js +1 -1
  47. package/src/organisms/tab-bar/tab-bar.css +1 -1
  48. package/src/organisms/tab-bar/tab-bar.js +1 -1
  49. package/src/organisms/tabs/tabs.css +1 -1
  50. package/src/organisms/tabs/tabs.js +1 -1
package/ai-context.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$comment": "GENERATED by packages/sync/src/build-package-context.mjs — do not edit.",
3
3
  "system": "OneLi8",
4
- "version": "1.0.0-beta.10",
4
+ "version": "1.0.0-beta.12",
5
5
  "meaning": "OneLi8 means One Light.",
6
6
  "foundations": {
7
7
  "package": "@oneli8/tokens",
@@ -329,6 +329,18 @@
329
329
  "ol8-icon-btn": [
330
330
  "primary",
331
331
  "secondary"
332
+ ],
333
+ "ol8-field": [
334
+ "outline",
335
+ "filled"
336
+ ],
337
+ "ol8-choice": [
338
+ "checkbox",
339
+ "radio",
340
+ "switch"
341
+ ],
342
+ "ol8-gem": [
343
+ "generic surface"
332
344
  ]
333
345
  }
334
346
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneli8/core",
3
- "version": "1.0.0-beta.10",
3
+ "version": "1.0.0-beta.12",
4
4
  "description": "OneLi8 Design System, framework agnostic. renderX returns an HTML string, hydrateX wires existing DOM. Ships the design language and the rules it follows.",
5
5
  "keywords": [
6
6
  "design-system",
@@ -89,7 +89,7 @@
89
89
  "NOTICE"
90
90
  ],
91
91
  "dependencies": {
92
- "@oneli8/tokens": "1.0.0-beta.10"
92
+ "@oneli8/tokens": "1.0.0-beta.12"
93
93
  },
94
94
  "engines": {
95
95
  "node": ">=20"
@@ -32,6 +32,12 @@ text. That means every glyph AND the unselected control boundary and any icon, n
32
32
  the label alone. Disabled takes material.gem.color.quiet.contentDisabled, one
33
33
  whitish grey shared by text and control geometry, and no halo.
34
34
 
35
+ On a button the label and the icon always take the same value: --_fg and --_ink are set
36
+ together, in every state. Disabled on Gem takes material.gem.color.quiet.contentDisabled for
37
+ both, never the regular action disabled-content colours, which are dark on a surface whose
38
+ enabled content is near-white. Loading is an ACTIVE state: it keeps the lit bezel and the gem
39
+ content ink, and it matches :disabled only because inert = disabled || loading.
40
+
35
41
  material.gem.color.quiet.stabilizedFace is the local content plane on app chrome,
36
42
  including the filled Gem text field, Select and Combobox. Its content is ordinary
37
43
  color.text.* and takes no halo. Selected and mixed indicators are never restyled
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Icon atom
2
+ * OneLi8 · Icon atom
3
3
  * Figma: page "Iconography" — masters "Icon Library / Masters" (426:55),
4
4
  * sizing from "Icon Frame" (418:51).
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Icon atom — headless behavior.
2
+ * OneLi8 · Icon atom — headless behavior.
3
3
  *
4
4
  * Two entry points, one output:
5
5
  * renderIcon(name, opts) -> markup string (build time / SSR)
@@ -1,5 +1,5 @@
1
1
  // GENERATED by packages/sync/src/build-icons.mjs — do not edit by hand.
2
- // Source: Figma "Oneli8 Design System — 1.0.0-beta.1", page Iconography,
2
+ // Source: Figma "OneLi8 Design System — 1.0.0-beta.1", page Iconography,
3
3
  // frame "Icon Library / Masters" (426:55). Re-run `npm run sync:icons`.
4
4
 
5
5
  export interface Ol8IconEntry {
@@ -29,6 +29,10 @@ export declare const OL8_ICONS: {
29
29
  readonly "close": Ol8IconEntry;
30
30
  readonly "copy": Ol8IconEntry;
31
31
  readonly "critical": Ol8IconEntry;
32
+ readonly "figure-running": Ol8IconEntry;
33
+ readonly "figure-sprinting": Ol8IconEntry;
34
+ readonly "figure-standing": Ol8IconEntry;
35
+ readonly "figure-walking": Ol8IconEntry;
32
36
  readonly "forward": Ol8IconEntry;
33
37
  readonly "heart": Ol8IconEntry;
34
38
  readonly "informative": Ol8IconEntry;
@@ -1,5 +1,5 @@
1
1
  // GENERATED by packages/sync/src/build-icons.mjs — do not edit by hand.
2
- // Source: Figma "Oneli8 Design System — 1.0.0-beta.1", page Iconography,
2
+ // Source: Figma "OneLi8 Design System — 1.0.0-beta.1", page Iconography,
3
3
  // frame "Icon Library / Masters" (426:55). Re-run `npm run sync:icons`.
4
4
 
5
5
  export const OL8_ICON_VIEWBOX = '0 0 24 24';
@@ -204,6 +204,202 @@ export const OL8_ICONS = {
204
204
  }
205
205
  ]
206
206
  },
207
+ "figure-running": {
208
+ "category": "locomotion",
209
+ "figmaNode": null,
210
+ "mirrorInRTL": true,
211
+ "candidate": true,
212
+ "sourceInk": "#151817",
213
+ "body": "<circle id=\"head\" cx=\"10.5\" cy=\"3.9\" r=\"2.1\" fill=\"currentColor\"/><path id=\"torso\" d=\"M10.5 6L12.3 12\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"arms\" d=\"M7.8 11.1L11.1 9M14.4 7.5L12 9.3\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"legs\" d=\"M7.5 18.6L12.3 12L16.2 17.4\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
214
+ "elements": [
215
+ {
216
+ "tag": "circle",
217
+ "attrs": {
218
+ "cx": "10.5",
219
+ "cy": "3.9",
220
+ "r": "2.1",
221
+ "fill": "currentColor"
222
+ }
223
+ },
224
+ {
225
+ "tag": "path",
226
+ "attrs": {
227
+ "d": "M10.5 6L12.3 12",
228
+ "stroke": "currentColor",
229
+ "strokeWidth": "1.8",
230
+ "strokeLinecap": "round",
231
+ "strokeLinejoin": "round"
232
+ }
233
+ },
234
+ {
235
+ "tag": "path",
236
+ "attrs": {
237
+ "d": "M7.8 11.1L11.1 9M14.4 7.5L12 9.3",
238
+ "stroke": "currentColor",
239
+ "strokeWidth": "1.8",
240
+ "strokeLinecap": "round",
241
+ "strokeLinejoin": "round"
242
+ }
243
+ },
244
+ {
245
+ "tag": "path",
246
+ "attrs": {
247
+ "d": "M7.5 18.6L12.3 12L16.2 17.4",
248
+ "stroke": "currentColor",
249
+ "strokeWidth": "1.8",
250
+ "strokeLinecap": "round",
251
+ "strokeLinejoin": "round"
252
+ }
253
+ }
254
+ ]
255
+ },
256
+ "figure-sprinting": {
257
+ "category": "locomotion",
258
+ "figmaNode": null,
259
+ "mirrorInRTL": true,
260
+ "candidate": true,
261
+ "sourceInk": "#151817",
262
+ "body": "<circle id=\"head\" cx=\"9.9\" cy=\"4.2\" r=\"2.1\" fill=\"currentColor\"/><path id=\"torso\" d=\"M9.9 6.3L12.6 11.7\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"arms\" d=\"M6.9 10.2L10.5 9M15.6 6.6L12 9.3\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"legs\" d=\"M6 17.7L12.6 11.7L17.1 16.2\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
263
+ "elements": [
264
+ {
265
+ "tag": "circle",
266
+ "attrs": {
267
+ "cx": "9.9",
268
+ "cy": "4.2",
269
+ "r": "2.1",
270
+ "fill": "currentColor"
271
+ }
272
+ },
273
+ {
274
+ "tag": "path",
275
+ "attrs": {
276
+ "d": "M9.9 6.3L12.6 11.7",
277
+ "stroke": "currentColor",
278
+ "strokeWidth": "1.8",
279
+ "strokeLinecap": "round",
280
+ "strokeLinejoin": "round"
281
+ }
282
+ },
283
+ {
284
+ "tag": "path",
285
+ "attrs": {
286
+ "d": "M6.9 10.2L10.5 9M15.6 6.6L12 9.3",
287
+ "stroke": "currentColor",
288
+ "strokeWidth": "1.8",
289
+ "strokeLinecap": "round",
290
+ "strokeLinejoin": "round"
291
+ }
292
+ },
293
+ {
294
+ "tag": "path",
295
+ "attrs": {
296
+ "d": "M6 17.7L12.6 11.7L17.1 16.2",
297
+ "stroke": "currentColor",
298
+ "strokeWidth": "1.8",
299
+ "strokeLinecap": "round",
300
+ "strokeLinejoin": "round"
301
+ }
302
+ }
303
+ ]
304
+ },
305
+ "figure-standing": {
306
+ "category": "locomotion",
307
+ "figmaNode": null,
308
+ "mirrorInRTL": false,
309
+ "candidate": true,
310
+ "sourceInk": "#151817",
311
+ "body": "<circle id=\"head\" cx=\"12\" cy=\"3.6\" r=\"2.1\" fill=\"currentColor\"/><path id=\"torso\" d=\"M12 5.7V12.6\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"arms\" d=\"M9.9 12.3L11.4 9M14.1 12.3L12.6 9\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"legs\" d=\"M11.1 19.5L12 12.6L12.9 19.5\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
312
+ "elements": [
313
+ {
314
+ "tag": "circle",
315
+ "attrs": {
316
+ "cx": "12",
317
+ "cy": "3.6",
318
+ "r": "2.1",
319
+ "fill": "currentColor"
320
+ }
321
+ },
322
+ {
323
+ "tag": "path",
324
+ "attrs": {
325
+ "d": "M12 5.7V12.6",
326
+ "stroke": "currentColor",
327
+ "strokeWidth": "1.8",
328
+ "strokeLinecap": "round",
329
+ "strokeLinejoin": "round"
330
+ }
331
+ },
332
+ {
333
+ "tag": "path",
334
+ "attrs": {
335
+ "d": "M9.9 12.3L11.4 9M14.1 12.3L12.6 9",
336
+ "stroke": "currentColor",
337
+ "strokeWidth": "1.8",
338
+ "strokeLinecap": "round",
339
+ "strokeLinejoin": "round"
340
+ }
341
+ },
342
+ {
343
+ "tag": "path",
344
+ "attrs": {
345
+ "d": "M11.1 19.5L12 12.6L12.9 19.5",
346
+ "stroke": "currentColor",
347
+ "strokeWidth": "1.8",
348
+ "strokeLinecap": "round",
349
+ "strokeLinejoin": "round"
350
+ }
351
+ }
352
+ ]
353
+ },
354
+ "figure-walking": {
355
+ "category": "locomotion",
356
+ "figmaNode": null,
357
+ "mirrorInRTL": true,
358
+ "candidate": true,
359
+ "sourceInk": "#151817",
360
+ "body": "<circle id=\"head\" cx=\"11.4\" cy=\"3.6\" r=\"2.1\" fill=\"currentColor\"/><path id=\"torso\" d=\"M11.4 5.7L12 12.3\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"arms\" d=\"M9.3 11.7L11.1 9M14.4 11.1L12.3 9\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path id=\"legs\" d=\"M9.3 19.5L12 12.3L14.7 18.9\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
361
+ "elements": [
362
+ {
363
+ "tag": "circle",
364
+ "attrs": {
365
+ "cx": "11.4",
366
+ "cy": "3.6",
367
+ "r": "2.1",
368
+ "fill": "currentColor"
369
+ }
370
+ },
371
+ {
372
+ "tag": "path",
373
+ "attrs": {
374
+ "d": "M11.4 5.7L12 12.3",
375
+ "stroke": "currentColor",
376
+ "strokeWidth": "1.8",
377
+ "strokeLinecap": "round",
378
+ "strokeLinejoin": "round"
379
+ }
380
+ },
381
+ {
382
+ "tag": "path",
383
+ "attrs": {
384
+ "d": "M9.3 11.7L11.1 9M14.4 11.1L12.3 9",
385
+ "stroke": "currentColor",
386
+ "strokeWidth": "1.8",
387
+ "strokeLinecap": "round",
388
+ "strokeLinejoin": "round"
389
+ }
390
+ },
391
+ {
392
+ "tag": "path",
393
+ "attrs": {
394
+ "d": "M9.3 19.5L12 12.3L14.7 18.9",
395
+ "stroke": "currentColor",
396
+ "strokeWidth": "1.8",
397
+ "strokeLinecap": "round",
398
+ "strokeLinejoin": "round"
399
+ }
400
+ }
401
+ ]
402
+ },
207
403
  "forward": {
208
404
  "category": "navigation",
209
405
  "figmaNode": "418:16",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Navigation Badge (ATOM)
2
+ * OneLi8 · Navigation Badge (ATOM)
3
3
  * Figma: Atom / Navigation Badge 989:484 — a full radius pill at the standard
4
4
  * indicator height, padded by the related inline step, whose surface and
5
5
  * content are the only things that change when the item is selected or gem.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Navigation Badge — headless behavior.
2
+ * OneLi8 · Navigation Badge — headless behavior.
3
3
  *
4
4
  * Figma (989:484): "Canonical optional navigation badge. Content comes from
5
5
  * item.badge; geometry and colors are semantic token controlled."
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Selection Indicator (ATOM)
2
+ * OneLi8 · Selection Indicator (ATOM)
3
3
  * Figma: Documentation / Choice Controls (246:3)
4
4
  * Icon / Selection / Checkbox 365:2417 (12 variants)
5
5
  * Icon / Selection / Radio 366:2371 (8)
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Selection Indicator (ATOM) — headless.
2
+ * OneLi8 · Selection Indicator (ATOM) — headless.
3
3
  *
4
4
  * Presentational only. It renders the mark a checkbox, radio or switch shows;
5
5
  * it never owns state, role or focus. The native <input> in Choice Item does.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Gem material adapter
2
+ * OneLi8 · Gem material adapter
3
3
  * Figma: section "Gem Button" (1034:9969) — 144 components across
4
4
  * Button/Primary/Gem 100:3, Button/Secondary/Gem 100:208,
5
5
  * Icon Button ±Circle Primary/Secondary Gem 102:78, 102:151, 119:202, 119:299.
@@ -226,27 +226,149 @@
226
226
  }
227
227
  /* Disabled resolves to the opaque equivalent, which is the same answer Reduced
228
228
  Transparency gives. */
229
+ /* DISABLED IS A STATE, NOT A MATERIAL CHANGE.
230
+ This used to swap the face for quiet.opaqueEquivalent and hide both painted
231
+ layers, so a disabled Gem field stopped being glass and became a solid slab.
232
+ That mirrored the Figma source faithfully and was wrong in both places:
233
+ opaqueEquivalent is the answer to prefers-reduced-transparency, a user
234
+ preference, not to a component state. Gem is worn, so an opaque disabled
235
+ field punches a solid hole in the wearer's view of the street — the same
236
+ objection that makes the reduced mode translucent rather than solid.
237
+ It also disagreed with Choice Item, which keeps its Gem surface when
238
+ disabled and only dims its content.
239
+
240
+ So the body and the backdrop blur stay. What goes is the lit bezel: the rim
241
+ inner shadows and the angular cut both drop, and the boundary falls to the
242
+ flat disabled border. The surface stays glass; it stops catching light. */
229
243
  .ol8-field[data-ol8-material="gem"][data-ol8-disabled] .ol8-field__control {
230
- --_surface: var(--ol8-material-gem-color-quiet-opaqueequivalent);
231
244
  --_border: var(--ol8-color-border-disabled);
232
245
  }
233
- .ol8-field[data-ol8-material="gem"][data-ol8-disabled] .ol8-field__control::before,
234
246
  .ol8-field[data-ol8-material="gem"][data-ol8-disabled] .ol8-field__control::after { display: none; }
235
247
 
248
+ /* THE ANGULAR CUT — the bezel stroke, at last implemented.
249
+ *
250
+ * Figma puts a 1px INSIDE stroke on the Control frame, and it is not a flat
251
+ * colour: it is a GRADIENT_ANGULAR with five stops, symmetric about 0.54, so
252
+ * the cut catches light at the top and fades at the bottom-left. The family
253
+ * depends on the appearance — Inner Thin Cut on Filled, Cut Edge on Outline —
254
+ * read off 214:132 and 210:112 respectively.
255
+ *
256
+ * CSS has no gradient border that follows border-radius, so the ring is a
257
+ * conic gradient clipped to a 1px inset band by two masks composited apart.
258
+ * It lives on .ol8-field__control-stack::before because that box is identical
259
+ * to the control's (both take --_height, the control is inline-size: 100%) and
260
+ * because the control's own two pseudo-elements are already spent: ::before is
261
+ * the body and backdrop blur, ::after is the pair of rim inner shadows. The
262
+ * stack's ::after is the focus edge. ::before was the one free layer, which is
263
+ * why this needs no markup change — an earlier read of this file concluded it
264
+ * did, and that was wrong.
265
+ *
266
+ * The flat --_border stays underneath. It is what shows when the ring cannot
267
+ * paint, and it is what Reduced Transparency falls back to. */
268
+ .ol8-field[data-ol8-material="gem"] {
269
+ --_bezel-high: var(--ol8-material-gem-color-cutedge-high);
270
+ --_bezel-mid: var(--ol8-material-gem-color-cutedge-mid);
271
+ --_bezel-low: var(--ol8-material-gem-color-cutedge-low);
272
+ }
273
+ .ol8-field[data-ol8-material="gem"][data-ol8-appearance="filled"] {
274
+ --_bezel-high: var(--ol8-material-gem-color-innerthincut-high);
275
+ --_bezel-mid: var(--ol8-material-gem-color-innerthincut-mid);
276
+ --_bezel-low: var(--ol8-material-gem-color-innerthincut-low);
277
+ }
278
+
279
+ .ol8-field[data-ol8-material="gem"] > .ol8-field__control-stack::before,
280
+ .ol8-gem::before {
281
+ content: "";
282
+ position: absolute;
283
+ inset: 0;
284
+ z-index: 1;
285
+ pointer-events: none;
286
+ padding: var(--ol8-border-width-hairline);
287
+ /* the five Figma stops, at their Figma positions */
288
+ background:
289
+ conic-gradient(from 0deg,
290
+ var(--_bezel-high) 0%,
291
+ var(--_bezel-mid) 30%,
292
+ var(--_bezel-low) 54%,
293
+ var(--_bezel-mid) 78%,
294
+ var(--_bezel-high) 100%);
295
+ -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
296
+ mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
297
+ -webkit-mask-composite: xor;
298
+ mask-composite: exclude;
299
+ }
300
+ .ol8-field[data-ol8-material="gem"] > .ol8-field__control-stack::before {
301
+ border-radius: var(--_radius);
302
+ }
303
+ .ol8-gem {
304
+ --_bezel-high: var(--ol8-material-gem-color-cutedge-high);
305
+ --_bezel-mid: var(--ol8-material-gem-color-cutedge-mid);
306
+ --_bezel-low: var(--ol8-material-gem-color-cutedge-low);
307
+ }
308
+ .ol8-gem::before { border-radius: inherit; }
309
+
310
+ /* Disabled and Reduced Transparency both drop to the flat boundary. */
311
+ .ol8-field[data-ol8-material="gem"][data-ol8-disabled] > .ol8-field__control-stack::before {
312
+ display: none;
313
+ }
314
+ @media (prefers-reduced-transparency: reduce) {
315
+ .ol8-field[data-ol8-material="gem"] > .ol8-field__control-stack::before,
316
+ .ol8-gem::before { display: none; }
317
+ }
318
+
236
319
  /* Content must sit above the ::before body. */
237
320
  .ol8-btn[data-ol8-material="gem"] > *,
238
321
  .ol8-icon-btn[data-ol8-material="gem"] .ol8-icon,
239
322
  .ol8-field[data-ol8-material="gem"] .ol8-field__control > * { position: relative; z-index: 0; }
240
323
 
241
- /* ---- Disabled inherits the regular opaque treatment ------------------ */
242
- .ol8-btn[data-ol8-material="gem"]:disabled::before,
243
- .ol8-btn[data-ol8-material="gem"]:disabled::after,
244
- .ol8-icon-btn[data-ol8-material="gem"]:disabled > .ol8-icon-btn__surface::before,
245
- .ol8-icon-btn[data-ol8-material="gem"]:disabled > .ol8-icon-btn__surface::after { display: none; }
246
-
247
324
  /* ---- Reduced Transparency -> the regular opaque equivalent -----------
248
325
  Explicitly required by the Figma description. Hiding the gem layers
249
326
  reveals the regular molecule's own background, which was never removed. */
327
+ /* DISABLED KEEPS THE GLASS ON BUTTONS TOO.
328
+ Same rule the Gem field follows, and buttons needed a different mechanism to
329
+ reach it. A Gem button's ::before body and backdrop blur survive Disabled
330
+ already — but ::before sits at z-index -1, behind the element's own --_bg,
331
+ and the disabled --_bg is an opaque action colour. So the glass was there and
332
+ occluded: the button looked like Figma's opaque slab even though the layer
333
+ was painting underneath it.
334
+
335
+ Making --_bg transparent for Gem reveals the body that was always there. The
336
+ lit bezel still goes, exactly as on the field. Loading resolves through the
337
+ same rule because loading is inert — renderButton sets inert = disabled ||
338
+ loading — which means a loading Gem button now shows its own loading
339
+ gradient stops rather than hiding them behind the disabled colour.
340
+
341
+ The negative z-index stays load-bearing: it is what lets the canonical
342
+ opaque background show through when Gem is suppressed for Reduced
343
+ Transparency, so that media query restores --_bg below. */
344
+ .ol8-btn[data-ol8-material="gem"]:disabled,
345
+ .ol8-icon-btn[data-ol8-material="gem"]:disabled > .ol8-icon-btn__surface {
346
+ --_bg: transparent;
347
+ }
348
+
349
+ /* Disabled ink on Gem is already solved: quiet.contentDisabled, the whitish
350
+ grey shared by Choice Item's label and its control geometry. Buttons were
351
+ falling through to the regular action disabled-content colours, which are
352
+ DARK — a dark glyph on a surface whose enabled content is near-white. Code
353
+ was worse than that: it kept the full near-white, so Disabled was
354
+ indistinguishable from Default.
355
+ --_fg is the label and --_ink is the icon, and they take the same value,
356
+ because on a button the two always match. */
357
+ .ol8-btn[data-ol8-material="gem"]:disabled:not([data-ol8-loading]),
358
+ .ol8-icon-btn[data-ol8-material="gem"]:disabled:not([data-ol8-loading]),
359
+ .ol8-icon-btn[data-ol8-material="gem"]:disabled:not([data-ol8-loading]) > .ol8-icon-btn__surface {
360
+ --_fg: var(--ol8-material-gem-color-quiet-contentdisabled);
361
+ --_ink: var(--ol8-material-gem-color-quiet-contentdisabled);
362
+ }
363
+ /* Loading is excluded. It matches :disabled because renderButton sets
364
+ inert = disabled || loading, but Loading is an ACTIVE state — Figma keeps
365
+ both rim inner shadows on it and gives it its own deep gradient stops, so it
366
+ keeps the lit bezel. Only Disabled loses it. */
367
+ .ol8-btn[data-ol8-material="gem"]:disabled:not([data-ol8-loading])::after,
368
+ .ol8-icon-btn[data-ol8-material="gem"]:disabled:not([data-ol8-loading]) > .ol8-icon-btn__surface::after {
369
+ display: none;
370
+ }
371
+
250
372
  @media (prefers-reduced-transparency: reduce) {
251
373
  .ol8-btn[data-ol8-material="gem"]::before,
252
374
  .ol8-btn[data-ol8-material="gem"]::after,
@@ -254,6 +376,12 @@
254
376
  .ol8-icon-btn[data-ol8-material="gem"] > .ol8-icon-btn__surface::after,
255
377
  .ol8-field[data-ol8-material="gem"] .ol8-field__control::before,
256
378
  .ol8-field[data-ol8-material="gem"] .ol8-field__control::after { display: none; }
379
+ /* With the Gem layers suppressed there is nothing behind a transparent
380
+ background, so the canonical disabled colour comes back. */
381
+ .ol8-btn[data-ol8-material="gem"]:disabled,
382
+ .ol8-icon-btn[data-ol8-material="gem"]:disabled > .ol8-icon-btn__surface {
383
+ --_bg: revert;
384
+ }
257
385
  .ol8-field[data-ol8-material="gem"] .ol8-field__control {
258
386
  --_surface: var(--ol8-material-gem-color-quiet-opaqueequivalent);
259
387
  }
@@ -317,11 +445,40 @@
317
445
  1 - (1 - a)^4. Measured in proof/gem-halo-contrast.html. */
318
446
  text-shadow: var(--_gem-glow), var(--_gem-glow),
319
447
  var(--_gem-glow), var(--_gem-glow);
320
- /* The cut edge. Invariant it is what keeps a gem recognisable as gem. */
448
+ /* The cut edge, exactly as the Gem slab carries it in Figma Light Gem Slab
449
+ 297:617, which is the container this class is the code equivalent of:
450
+
451
+ INNER_SHADOW offset 3, 3 blur 6 Cut Edge / High
452
+ INNER_SHADOW offset -3,-3 blur 12 spread -3 Cut Edge / Mid
453
+ DROP_SHADOW offset 0,12 blur 36 Cut Edge / Shadow
454
+ DROP_SHADOW offset 0, 3 blur 6 Cut Edge / Shadow
455
+
456
+ TWO inner shadows, from OPPOSITE corners: light falling top-left and shade
457
+ gathering bottom-right. That is why the bezel reads on all four sides in
458
+ Figma. This carried a top specular and a 1px rim instead — the CONTROL
459
+ recipe, which belongs to buttons and fields, not to a slab — so the cut
460
+ only ever showed along the top. Every offset and blur here is on the 3px
461
+ grid, which is how the slab was drawn. */
321
462
  box-shadow:
322
- inset 0 2px 1px 0 var(--ol8-material-gem-color-cutedge-high),
323
- inset 0 0 0 1px var(--ol8-material-gem-color-cutedge-mid),
324
- 0 9px 12px var(--ol8-material-gem-color-cutedge-shadow);
463
+ inset 3px 3px 6px 0 var(--ol8-material-gem-color-cutedge-high),
464
+ inset -3px -3px 12px -3px var(--ol8-material-gem-color-cutedge-mid),
465
+ 0 12px 36px var(--ol8-material-gem-color-cutedge-shadow),
466
+ 0 3px 6px var(--ol8-material-gem-color-cutedge-shadow);
467
+ }
468
+
469
+ /* A Token or Choice Chip sitting ON a Gem surface.
470
+ Both draw the Choice Chip silhouette, whose default --_surface is
471
+ color.surface.sunken — an opaque plate. On glass that reads as a solid
472
+ lozenge stuck to the surface, and in the Light appearance its ink is dark,
473
+ so the label goes invisible against near-white gem content beside it.
474
+ The pill turns transparent and the label takes the gem ink and halo, so the
475
+ chip reads as a boundary around content rather than a second material. */
476
+ .ol8-gem .ol8-chip {
477
+ --_surface: transparent;
478
+ --_edge: var(--ol8-material-gem-color-cutedge-high);
479
+ --_ink: var(--ol8-material-gem-color-quiet-content);
480
+ text-shadow: var(--_gem-glow), var(--_gem-glow),
481
+ var(--_gem-glow), var(--_gem-glow);
325
482
  }
326
483
 
327
484
  /* Disabled on a generic Gem surface, same single grey, same absent halo. */
@@ -351,6 +508,26 @@
351
508
  --_gem-blur: var(--ol8-material-gem-blur-environmental);
352
509
  }
353
510
 
511
+ /* The third rung, and the SAME face as reduced transparency below reached for
512
+ a different reason. That one is the PREFERENCE route — the person asked for
513
+ less transparency, system-wide. This is the CONTEXT route: this surface is
514
+ legibility-critical right now, and the environment losing presence is the
515
+ correct trade rather than a regression. An athlete reading a split while
516
+ running laps is the case: speed is exactly when the ambient face recedes,
517
+ and exactly when this reader can least afford it.
518
+
519
+ Both land on legibilityFace because there is one dense-but-see-through face,
520
+ not two. 0.72 leaves 28% of the scene visible and measures 7.70:1 against
521
+ near-white ink in the worst region of a daylight plate, with no credit taken
522
+ for the halo — AAA while still worn-display honest.
523
+
524
+ Blur holds at the stabilized 12px. Environmental's 18px exists to let the
525
+ scene dominate, which is the opposite of what this face is for. */
526
+ .ol8-gem[data-ol8-face="legibility"] {
527
+ --_gem-face: var(--ol8-material-gem-color-quiet-legibilityface);
528
+ --_gem-blur: var(--ol8-material-gem-blur-stabilized);
529
+ }
530
+
354
531
  /* REDUCED TRANSPARENCY, THE WORN-DISPLAY READING OF IT
355
532
  Gem is worn, so the background is the real world and an opaque panel would
356
533
  occlude the street for the person who needs help reading the interface most.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Button
2
+ * OneLi8 · Button
3
3
  * Figma: section "Button" (1034:9968) — Primary 15:823, Secondary 15:824,
4
4
  * Quiet 15:825, Destructive 15:826. 4 families × 4 sizes × 6 states.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Button — headless behavior.
2
+ * OneLi8 · Button — headless behavior.
3
3
  *
4
4
  * The Figma component description is explicit that native semantics, disabled,
5
5
  * loading, pressed and fullWidth "remain implemented and tested in code; they
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Chip (MOLECULE) — the Soft Hexagon
2
+ * OneLi8 · Choice Chip (MOLECULE) — the Soft Hexagon
3
3
  * Figma: Select and Combobox / Choice Chip / Soft Hexagon 636:847 (8 variants)
4
4
  *
5
5
  * GEOMETRY, read from all four sizes in Figma:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Chip (MOLECULE) — the Soft Hexagon.
2
+ * OneLi8 · Choice Chip (MOLECULE) — the Soft Hexagon.
3
3
  *
4
4
  * Figma: Select and Combobox / Choice Chip / Soft Hexagon 636:847 (8 variants,
5
5
  * Size x Selection, plus a Label text property and a Show Mark boolean).
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Item (MOLECULE)
2
+ * OneLi8 · Choice Item (MOLECULE)
3
3
  * Figma: Documentation / Molecule / Choice Item
4
4
  * Checkbox 252:301 (24 variants) · Radio 331:1309 (16) · Switch 825:1591 (16)
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Item (MOLECULE) — headless behavior.
2
+ * OneLi8 · Choice Item (MOLECULE) — headless behavior.
3
3
  *
4
4
  * Figma (252:301): "Native input, name/value, required, reset, form
5
5
  * submission, and onCheckedChange live in code." This module is that code —
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Form Message (MOLECULE)
2
+ * OneLi8 · Form Message (MOLECULE)
3
3
  * Figma: Form Message 177:13, five tones.
4
4
  *
5
5
  * Anatomy read from Figma: a horizontal row, gap Component / Text Field / Gap /
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Oneli8 · Form Message — headless behavior.
2
+ * OneLi8 · Form Message — headless behavior.
3
3
  *
4
- * Figma (177:13): "Canonical Oneli8 Form Message molecule. Tone maps to
4
+ * Figma (177:13): "Canonical OneLi8 Form Message molecule. Tone maps to
5
5
  * semantic message tone; Pending is resolved through validationStatus rather
6
6
  * than treated as a fifth error tone. Icon and Message remain modular content
7
7
  * atoms. Runtime role, status announcement and relationships live in code."
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Icon Button
2
+ * OneLi8 · Icon Button
3
3
  * Figma: section "Icon Button" (1034:10546) — Primary 86:2, Secondary 87:26,
4
4
  * Quiet 88:50, Destructive 89:74, plus the four Circle sets.
5
5
  * 4 families × 2 shapes × 4 sizes × 6 states = 192 components.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Icon Button — headless behavior.
2
+ * OneLi8 · Icon Button — headless behavior.
3
3
  *
4
4
  * Figma (86:2): "Icon is an INSTANCE_SWAP sourced from the governed 24px Icon
5
5
  * Library atom and resized only through Icon Frame; Accessible Name is
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Link (MOLECULE)
2
+ * OneLi8 · Link (MOLECULE)
3
3
  *
4
4
  * Figma (138:260, 139:260, 139:453): "Runtime href, native anchor behavior,
5
5
  * visited resolution, aria-current, motion preference and navigation list
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Link — headless behavior.
2
+ * OneLi8 · Link — headless behavior.
3
3
  *
4
4
  * The Figma component description is explicit that "runtime href, native anchor
5
5
  * behavior, visited resolution, aria-current, motion preference and navigation
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Navigation Item (MOLECULE, internal)
2
+ * OneLi8 · Navigation Item (MOLECULE, internal)
3
3
  * Figma: Tab Item 688:51, Segment Item 695:167, Destination Item 700:292.
4
4
  *
5
5
  * All three are one molecule. Read from Figma: a box at the size's control
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Navigation Item — the shared internal molecule.
2
+ * OneLi8 · Navigation Item — the shared internal molecule.
3
3
  *
4
4
  * Figma draws three of these: Tab Item (688:51), Segment Item (695:167) and
5
5
  * Destination Item (700:292). They are the same molecule with three selection
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Select (MOLECULE)
2
+ * OneLi8 · Select (MOLECULE)
3
3
  * Figma: Select / Trigger 583:338, Molecule / Select 875:1778.
4
4
  *
5
5
  * "Geometry and appearance reuse approved Text Field tokens", and Figma proves
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Select — headless behavior.
2
+ * OneLi8 · Select — headless behavior.
3
3
  *
4
4
  * Figma (583:338 Trigger, 875:1778 Select): "Geometry and appearance reuse
5
5
  * approved Text Field tokens; focus remains inward."
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * So this renders a real <select>. The user agent owns the keyboard, the type
13
13
  * ahead, the picker and the announcements, which is exactly what the contract
14
- * asks for: "Oneli8 does not intercept native keys to imitate a different
14
+ * asks for: "OneLi8 does not intercept native keys to imitate a different
15
15
  * platform." A custom listbox is available, but only when the caller says
16
16
  * native="custom-allowed" and therefore accepts the whole contract that comes
17
17
  * with it.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Selection Option (MOLECULE)
2
+ * OneLi8 · Selection Option (MOLECULE)
3
3
  * Figma: Select and Combobox -> 01 · Atomic Selection Building Blocks
4
4
  * Building Blocks / Selection Option 570:122 (8 variants)
5
5
  * Size Standard|Large x Selection x Availability
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Selection Option (MOLECULE) — headless.
2
+ * OneLi8 · Selection Option (MOLECULE) — headless.
3
3
  *
4
4
  * Figma (570:122): "Description is associated through aria-describedby and
5
5
  * remains outside the option accessible name. Selection Popup composes this
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Text Field (MOLECULE)
2
+ * OneLi8 · Text Field (MOLECULE)
3
3
  * Figma: Text Field / Outline 182:33, Text Field / Filled 186:53,
4
4
  * Text Field / Outline / Gem 211:36, Text Field / Filled / Gem 215:226,
5
5
  * Text Field / Content 175:2, Form Message 177:13.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Text Field — headless behavior.
2
+ * OneLi8 · Text Field — headless behavior.
3
3
  *
4
4
  * Two sources govern this file and they govern different things.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Token (MOLECULE)
2
+ * OneLi8 · Token (MOLECULE)
3
3
  * Figma: Select and Combobox / Molecule / Token 897:2106 (24 variants)
4
4
  *
5
5
  * The silhouette, sizes and colours all come from the Choice Chip stylesheet,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Token (MOLECULE) — a committed value.
2
+ * OneLi8 · Token (MOLECULE) — a committed value.
3
3
  *
4
4
  * Figma: Select and Combobox / Molecule / Token 897:2106 (24 variants,
5
5
  * Size x Selection x Mark).
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Group (ORGANISM)
2
+ * OneLi8 · Choice Group (ORGANISM)
3
3
  * Figma: Documentation / Organism / Choice Group
4
4
  * Checkbox Hierarchy 273:603 Aggregate = None | Some | All
5
5
  * Radio Group 859:5180 Behavior = Safe Default | No Default |
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Group (ORGANISM) — headless behavior.
2
+ * OneLi8 · Choice Group (ORGANISM) — headless behavior.
3
3
  *
4
4
  * Figma (273:603): "Aggregate None/Some/All is computed from nested Checkbox
5
5
  * molecules; Mixed is never a third preference. Runtime recursion,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Picker (ORGANISM)
2
+ * OneLi8 · Choice Picker (ORGANISM)
3
3
  * Figma: Organism / Choice Picker / Soft Hexagon 906:2898 (16 variants)
4
4
  *
5
5
  * Three parts stacked twelve apart: a search field, a wrapping matrix of chips,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Choice Picker (ORGANISM)
2
+ * OneLi8 · Choice Picker (ORGANISM)
3
3
  *
4
4
  * Figma: Organism / Choice Picker / Soft Hexagon 906:2898 (16 variants,
5
5
  * Material x Commitment x Size).
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Combobox (ORGANISM)
2
+ * OneLi8 · Combobox (ORGANISM)
3
3
  * Figma: Organism / Combobox 883:2159 — "Reuses approved Text Field, Selection
4
4
  * Popup and governed icon atoms."
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Combobox — headless behavior.
2
+ * OneLi8 · Combobox — headless behavior.
3
3
  *
4
4
  * Figma (883:2159): "Reuses approved Text Field, Selection Popup and governed
5
5
  * icon atoms", and "Expanded remains Boolean" so the design does not explode
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Multi-select Field (ORGANISM)
2
+ * OneLi8 · Multi-select Field (ORGANISM)
3
3
  * Figma: Organism / Multi-select Field / Outline 904:2507 (16 variants)
4
4
  * Organism / Multi-select Field / Filled 978:4472 (16 variants)
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Multi-select Field (ORGANISM)
2
+ * OneLi8 · Multi-select Field (ORGANISM)
3
3
  *
4
4
  * Figma: Select and Combobox
5
5
  * Organism / Multi-select Field / Outline · Soft Hexagon 904:2507 (16)
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Segmented Control (ORGANISM)
2
+ * OneLi8 · Segmented Control (ORGANISM)
3
3
  * Figma: Navigation / Segmented Control 698:4792 — six presentations.
4
4
  *
5
5
  * "Presentation never changes behavior." Every presentation below is a
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Segmented Control — headless behavior.
2
+ * OneLi8 · Segmented Control — headless behavior.
3
3
  *
4
4
  * Figma (698:4792): "Behavior is a consuming contract: single = Radio Group,
5
5
  * multi = independent Toggle Buttons, momentary = grouped actions."
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Selection Popup (ORGANISM)
2
+ * OneLi8 · Selection Popup (ORGANISM)
3
3
  * Figma: Building Blocks / Selection Popup 574:534 — Width, Size.
4
4
  *
5
5
  * The rail is a div with role="listbox" rather than a list element, because a
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Selection Popup — headless behavior.
2
+ * OneLi8 · Selection Popup — headless behavior.
3
3
  *
4
4
  * Figma (574:534): "Width and Size govern layout only; content must be
5
5
  * canonical Selection Option instances. Runtime listbox naming, ownership,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Tab Bar (ORGANISM)
2
+ * OneLi8 · Tab Bar (ORGANISM)
3
3
  * Figma: Navigation / Tab Bar 701:460 — Bottom, Inline, Sidebar, Spatial Rail.
4
4
  *
5
5
  * "Tab Bar contains destinations, never a central action disguised as a
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Tab Bar — headless behavior.
2
+ * OneLi8 · Tab Bar — headless behavior.
3
3
  *
4
4
  * Figma (701:460): "Production uses native destination links, requires a non
5
5
  * empty navigation name, resolves exactly one current destination, and rejects
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Tabs (ORGANISM)
2
+ * OneLi8 · Tabs (ORGANISM)
3
3
  * Figma: Navigation / Tabs 693:171 — Hierarchy, Material, Size.
4
4
  *
5
5
  * The organism owns sibling separation and the rail; the item owns its own
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Oneli8 · Tabs — headless behavior.
2
+ * OneLi8 · Tabs — headless behavior.
3
3
  *
4
4
  * Figma (693:171): "Production emits tablist, tab and tabpanel, requires a non
5
5
  * empty accessible region name, retains one enabled Tab stop, mirrors