@junoput01/junoui 0.2.0 → 0.4.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 (84) hide show
  1. package/CHANGELOG.md +251 -0
  2. package/README.md +23 -19
  3. package/dist/css/juno-custom-media.css +32 -0
  4. package/dist/css/juno.css +1355 -40
  5. package/dist/icons/inline.js +22 -0
  6. package/docs/accessibility.md +188 -0
  7. package/docs/boot-shell.md +295 -0
  8. package/docs/components/README.md +71 -0
  9. package/docs/components/accordion.md +49 -0
  10. package/docs/components/alert.md +46 -0
  11. package/docs/components/avatar.md +45 -0
  12. package/docs/components/badge.md +35 -0
  13. package/docs/components/breadcrumb.md +31 -0
  14. package/docs/components/button.md +32 -0
  15. package/docs/components/card.md +41 -0
  16. package/docs/components/checkbox.md +41 -0
  17. package/docs/components/chip.md +44 -0
  18. package/docs/components/divider.md +32 -0
  19. package/docs/components/dock.md +215 -0
  20. package/docs/components/drawer.md +100 -0
  21. package/docs/components/field.md +44 -0
  22. package/docs/components/fold-slot.md +31 -0
  23. package/docs/components/gauge.md +48 -0
  24. package/docs/components/icon-loader.md +122 -0
  25. package/docs/components/icon.md +70 -0
  26. package/docs/components/input.md +45 -0
  27. package/docs/components/list.md +76 -0
  28. package/docs/components/load-state.md +131 -0
  29. package/docs/components/loader.md +88 -0
  30. package/docs/components/menu.md +54 -0
  31. package/docs/components/modal.md +52 -0
  32. package/docs/components/navbar.md +53 -0
  33. package/docs/components/pagination.md +42 -0
  34. package/docs/components/pillbar.md +211 -0
  35. package/docs/components/popover.md +43 -0
  36. package/docs/components/rail.md +54 -0
  37. package/docs/components/readout.md +39 -0
  38. package/docs/components/reload.md +41 -0
  39. package/docs/components/segmented.md +46 -0
  40. package/docs/components/select.md +33 -0
  41. package/docs/components/skeleton.md +45 -0
  42. package/docs/components/slider.md +48 -0
  43. package/docs/components/spark.md +51 -0
  44. package/docs/components/status.md +30 -0
  45. package/docs/components/stepper.md +46 -0
  46. package/docs/components/switch.md +38 -0
  47. package/docs/components/table.md +126 -0
  48. package/docs/components/tabs.md +61 -0
  49. package/docs/components/thumb.md +81 -0
  50. package/docs/components/toast.md +48 -0
  51. package/docs/components/toggle-button.md +40 -0
  52. package/docs/components/tooltip.md +63 -0
  53. package/docs/design-guidelines.md +173 -0
  54. package/docs/flutter.md +42 -0
  55. package/docs/getting-started.md +93 -0
  56. package/docs/integration.md +95 -0
  57. package/docs/ios-conformance.md +224 -0
  58. package/docs/layout.md +271 -0
  59. package/docs/native.md +52 -0
  60. package/docs/roadmap.md +106 -0
  61. package/docs/tokens-reference.md +223 -0
  62. package/docs/web.md +95 -0
  63. package/package.json +7 -3
  64. package/src/css/base.css +171 -1
  65. package/src/css/components/dock.css +335 -0
  66. package/src/css/components/drawer.css +40 -3
  67. package/src/css/components/fold-slot.css +44 -0
  68. package/src/css/components/icon-loader.css +67 -0
  69. package/src/css/components/icon.css +6 -4
  70. package/src/css/components/load-state.css +136 -0
  71. package/src/css/components/loader.css +6 -0
  72. package/src/css/components/menu.css +4 -0
  73. package/src/css/components/modal.css +24 -3
  74. package/src/css/components/navbar.css +5 -1
  75. package/src/css/components/pillbar.css +222 -7
  76. package/src/css/components/rail.css +8 -0
  77. package/src/css/components/reload.css +48 -0
  78. package/src/css/components/skeleton.css +41 -13
  79. package/src/css/components/tabs.css +5 -0
  80. package/src/css/components/thumb.css +63 -1
  81. package/src/css/components/toast.css +5 -1
  82. package/src/css/density.css +22 -0
  83. package/src/css/layout.css +95 -5
  84. package/src/css/utilities.css +4 -1
package/docs/layout.md ADDED
@@ -0,0 +1,271 @@
1
+ # Layout & responsiveness
2
+
3
+ How blocks adapt — defined once, inherited by every UI. Two mechanisms:
4
+
5
+ 1. **Intrinsic layout primitives** — reflow by available space, no media queries.
6
+ 2. **Container queries** — a component restyles by _its own_ width, not the viewport
7
+ (right for a library dropped into unknown layouts).
8
+
9
+ Breakpoint tokens (`--juno-bp-sm…2xl`) follow Tailwind's scale and exist for the
10
+ rare viewport-level case.
11
+
12
+ ## Why container queries over viewport breakpoints
13
+
14
+ junoui components live inside arbitrary app skeletons. A card doesn't know if it's
15
+ in a 280px sidebar or full width — so it adapts to its container:
16
+
17
+ ```css
18
+ .juno-card {
19
+ container-type: inline-size;
20
+ } /* already set */
21
+ ```
22
+
23
+ `.juno-card__row` stacks automatically when the card is < 320px wide, anywhere.
24
+
25
+ ## Layout primitives
26
+
27
+ Wrap a region; it adapts on resize. Every knob is a custom property with a token
28
+ default — override per instance inline.
29
+
30
+ | Class | Does | Key knob (default) |
31
+ | ------------------------ | ---------------------------------------- | ---------------------------------------- |
32
+ | `.juno-center` | Max-measure wrapper, fluid gutters | `--juno-measure` (`bp-xl`) |
33
+ | `.juno-stack` | Vertical rhythm between children | `--juno-stack-space` (`space-16`) |
34
+ | `.juno-cluster` | Wrapping inline group (toolbars, tags) | `--juno-cluster-space` (`space-8`) |
35
+ | `.juno-grid-auto` | Cards that collapse columns themselves | `--juno-grid-min` (`240px`) |
36
+ | `.juno-grid-auto--tiles` | Media wall wired to the density layer | `--juno-tile-min` / `--juno-gap-content` |
37
+ | `.juno-sidebar` | Aside + fluid content, stacks when tight | `--juno-sidebar-width` (`280px`) |
38
+ | `.juno-switcher` | N-up or all-stacked at a threshold | `--juno-switcher-threshold` (`bp-sm`) |
39
+ | `.juno-scroller` | Bare scroll container (axis/snap/bar) | `--juno-scroller-snap` (`none`) |
40
+ | `.juno-reel` | Horizontal scroll-snap row | `--juno-reel-space` (`space-12`) |
41
+
42
+ ### Examples
43
+
44
+ ```html
45
+ <!-- responsive card grid — no breakpoints, columns just fit -->
46
+ <div class="juno-grid-auto" style="--juno-grid-min:280px;">
47
+ <article class="juno-card">…</article>
48
+ <article class="juno-card">…</article>
49
+ <article class="juno-card">…</article>
50
+ </div>
51
+
52
+ <!-- toolbar that wraps -->
53
+ <div class="juno-cluster">
54
+ <button class="juno-btn juno--nominal">CONFIRM</button>
55
+ <button class="juno-btn juno-btn--ghost">CANCEL</button>
56
+ </div>
57
+
58
+ <!-- sidebar + content; stacks when content would get too narrow -->
59
+ <div class="juno-sidebar">
60
+ <aside class="juno-sidebar__aside">…</aside>
61
+ <main class="juno-sidebar__main">…</main>
62
+ </div>
63
+
64
+ <!-- two-up that flips to stacked under ~640px of space -->
65
+ <div class="juno-switcher">
66
+ <div>A</div>
67
+ <div>B</div>
68
+ </div>
69
+
70
+ <!-- media wall: tile size + gap follow [data-juno-density] -->
71
+ <div class="juno-grid-auto juno-grid-auto--tiles"><img … /><img … /><img … /></div>
72
+ ```
73
+
74
+ `--tiles` reads `--juno-tile-min` / `--juno-gap-content` from the density layer
75
+ (`150px` / `space-10` comfortable, `108px` / `space-4` compact), so one
76
+ `data-juno-density` attribute re-densifies controls, surfaces **and** content
77
+ grids together.
78
+
79
+ ## Scroller
80
+
81
+ Every scrolling region in the library — `.juno-reel`, `.juno-app-shell__main`,
82
+ tab strips — is the same three knobs: overflow axis, overscroll containment,
83
+ snap type. `.juno-scroller` ships them as overridable custom props instead of
84
+ each consumer re-deriving (and usually forgetting `overscroll-behavior`, which
85
+ lets iOS pull-to-refresh/scroll-chain through an inner scroller into the
86
+ page). Defaults: `overflow: auto` (both axes), `overscroll-behavior: contain`,
87
+ no snap.
88
+
89
+ ```html
90
+ <!-- vertical list scroller with containment, no snap -->
91
+ <div class="juno-scroller juno-scroller--y">…</div>
92
+
93
+ <!-- horizontal, scrollbar hidden, softer "proximity" snap, opt-in stops -->
94
+ <div
95
+ class="juno-scroller juno-scroller--x juno-scroller--bare"
96
+ style="--juno-scroller-snap: x proximity;"
97
+ >
98
+ <div class="juno-snap">…</div>
99
+ <div class="juno-snap">…</div>
100
+ </div>
101
+ ```
102
+
103
+ - `.juno-scroller--x` — horizontal axis only (`overflow: auto hidden`)
104
+ - `.juno-scroller--y` — vertical axis only (`overflow: hidden auto`)
105
+ - `.juno-scroller--bare` — hides the scrollbar (Firefox + WebKit)
106
+ - `.juno-snap` — on a child: opts into `scroll-snap-align`
107
+
108
+ `.juno-reel` is `.juno-scroller`'s horizontal-snap preset baked into one
109
+ class: it now reads its `scroll-snap-type` from the same `--juno-scroller-snap`
110
+ prop (default unchanged: `inline mandatory`), so the mode is overridable
111
+ per instance instead of hardcoded — e.g. a "magnet" strip that wants
112
+ `proximity` instead of a stepped `mandatory` feel:
113
+
114
+ ```html
115
+ <div class="juno-reel" style="--juno-scroller-snap: inline proximity;">…</div>
116
+ ```
117
+
118
+ ## Gesture surfaces
119
+
120
+ For an element whose pointer events an app JS layer owns outright — drag-pan,
121
+ pinch-zoom, swipe classification, anything that is a state machine rather than
122
+ native scrolling — junoui ships the CSS side of that contract as one class.
123
+ The gesture handler itself is the app's job (or a sibling `junoui-<framework>`
124
+ package): junoui declares the surface, never the logic.
125
+
126
+ ```html
127
+ <div class="juno-gesture-surface" id="viewport"><!-- JS drag/pinch handlers attach here --></div>
128
+
129
+ <!-- only needs the touch-action axis lock, not the full reset -->
130
+ <li class="juno-list__item juno-pan-x"><!-- swipe-to-reveal row --></li>
131
+ ```
132
+
133
+ `.juno-gesture-surface` sets `touch-action: var(--juno-touch-action, none)`,
134
+ `-webkit-touch-callout: none`, `user-select: none` and
135
+ `-webkit-tap-highlight-color: transparent` — so the UA never fights the
136
+ handler with its own scroll/zoom recognition, long-press callout, text
137
+ selection or tap flash. Override `--juno-touch-action` per instance to hand
138
+ back one axis (`pan-x` / `pan-y`) instead of all of them. `.juno-pan-x` /
139
+ `.juno-pan-y` are standalone single-axis classes for elements that want the
140
+ axis lock alone.
141
+
142
+ These four properties are **community convention, not Apple-documented
143
+ behavior** — see [ios-conformance.md](./ios-conformance.md) before citing them
144
+ as a platform requirement.
145
+
146
+ ## App shell
147
+
148
+ Every product app assembles the same frame; `.juno-app-shell` ships it as
149
+ classes — a collapsible [rail](./components/rail.md), a topbar, a scrolling
150
+ content outlet, and a [dock](./components/dock.md) at the foot — so you stop
151
+ copy-pasting the same `<style>` block into every app.
152
+
153
+ ```html
154
+ <div class="juno-app-shell">
155
+ <nav class="juno-rail juno-rail--responsive" aria-label="Primary">
156
+ <div class="juno-rail__brand">JUNO</div>
157
+ <a class="juno-rail__item" href="/library" aria-current="page">
158
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
159
+ <span class="juno-rail__label">Library</span>
160
+ </a>
161
+ </nav>
162
+ <div class="juno-app-shell__body">
163
+ <header class="juno-app-shell__topbar">
164
+ <input class="juno-input" type="search" placeholder="SEARCH…" />
165
+ <span class="juno-badge juno-badge--soft juno--nominal">ONLINE</span>
166
+ </header>
167
+ <main class="juno-app-shell__main">…</main>
168
+ <nav class="juno-dock juno-hide-from-md" aria-label="Primary">
169
+ <a class="juno-dock__item" href="/library" aria-current="page">
170
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
171
+ <span class="juno-dock__label">Library</span>
172
+ </a>
173
+ </nav>
174
+ </div>
175
+ </div>
176
+ ```
177
+
178
+ What the primitive encodes so you don't have to:
179
+
180
+ - **`100dvh`, not `100vh`** — the shell fills the _dynamic_ viewport, so the
181
+ dock isn't clipped by the phone's shrinking address bar.
182
+ - **The `__main` region is the scroller**, not the page. The dock (or
183
+ [pillbar](./components/pillbar.md)) is a flex sibling at the body foot, so it
184
+ stays pinned with zero `sticky`/`fixed` and never overlaps content — the
185
+ short-page pitfall of sticky nav bars (below) can't happen here.
186
+ - **Safe-area insets** — the shell pads for landscape notches
187
+ (`inset-left`/`right`), the topbar for `inset-top`, the dock for
188
+ `inset-bottom`. **This requires `viewport-fit=cover` in your page's viewport
189
+ meta** ([getting-started](./getting-started.md#required-the-viewport-meta)) —
190
+ without it iOS reports every inset as `0` and none of this padding happens.
191
+
192
+ Collapse the rail by toggling `.juno-rail--collapsed` (one class; the width
193
+ transition and label hiding are built in). Trays/detail panels: the
194
+ [slide-over](./components/drawer.md#the-slide-over-pattern) pattern in the
195
+ drawer doc. Knobs: `--juno-app-shell-topbar-size` (topbar height).
196
+
197
+ ### Narrow viewports (phone)
198
+
199
+ The rail↔dock swap is two classes, no JS: `.juno-rail--responsive` self-hides
200
+ below `md`, and the dock carries `.juno-hide-from-md` so it shows only there.
201
+ (Equivalent to hanging `.juno-hide-below-md` on the rail yourself — the
202
+ modifier just saves you knowing to.) Keep 3–5 dock destinations; the rest go
203
+ behind a "More" item (drawer or menu). Prefer a floating bar? Swap the dock
204
+ for a [pillbar](./components/pillbar.md) — same contract, capsule look.
205
+
206
+ **Viewport helpers.** For the cases an intrinsic primitive can't express
207
+ (swap a nav for a menu button), hide/show by breakpoint at `sm` (640px),
208
+ `md` (768px), `lg` (1024px):
209
+
210
+ | Class | Visible |
211
+ | -------------------------------------------- | -------------- |
212
+ | `.juno-hide-below-md` / `.juno-show-from-md` | at `md` and up |
213
+ | `.juno-hide-from-md` / `.juno-show-below-md` | below `md` |
214
+
215
+ `show-*` are readable aliases for the inverse `hide-*` (`show-from-md` ≡
216
+ `hide-below-md`); pick whichever reads clearer at the call site. Same three
217
+ cut points for `sm` and `lg`.
218
+
219
+ ### Page-scroll shells (dock/pillbar `--fixed`)
220
+
221
+ `.juno-app-shell` is the recommended frame because its `__main` scroller keeps
222
+ the dock in flow. If instead the **whole page** scrolls, the dock/pillbar use
223
+ `position: sticky` — which only pins _while the column overflows_. On a short
224
+ page that doesn't scroll, a sticky bar lands mid-content, reading as "not
225
+ stuck." For that layout use `.juno-dock--fixed` (pins flush to the viewport
226
+ foot) or `.juno-pillbar--fixed` (fixes to the viewport, still floating its gap
227
+ above the foot) — then reserve the bar's footprint at the page foot (e.g.
228
+ `padding-block-end`) so it doesn't cover the last row.
229
+
230
+ ### Tab + stack (phone navigation recipe)
231
+
232
+ The full phone pattern is three parts: the dock or pillbar switches
233
+ _sections_; inside a section, a [list](./components/list.md) row (or any
234
+ link) pushes a detail view; every pushed view opens with a
235
+ [navbar](./components/navbar.md) whose back control unwinds one level.
236
+ junoui ships all three looks — the app owns the stack (routing/history):
237
+
238
+ ```html
239
+ <div class="juno-app-shell">
240
+ <div class="juno-app-shell__body">
241
+ <!-- one section, drilled one level in -->
242
+ <header class="juno-navbar">
243
+ <a class="juno-navbar__back" href="/settings">
244
+ <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-caret-left" /></svg>
245
+ <span class="juno-navbar__back-label">Settings</span>
246
+ </a>
247
+ <h1 class="juno-navbar__title">Playback</h1>
248
+ <div class="juno-navbar__actions"></div>
249
+ </header>
250
+ <main class="juno-app-shell__main"><!-- .juno-list groups… --></main>
251
+ <nav class="juno-pillbar" aria-label="Primary"><!-- section tabs --></nav>
252
+ </div>
253
+ </div>
254
+ ```
255
+
256
+ ## Adopting in an existing project
257
+
258
+ No restructuring required — additive and incremental:
259
+
260
+ 1. Set `data-juno-palette` / `data-juno-mode`, swap hardcoded values → `var(--juno-*)`.
261
+ 2. Add component classes where blocks match.
262
+ 3. Wrap layout regions in a primitive (`.juno-grid-auto`, `.juno-cluster`, …) to get
263
+ reflow. Add `container-type: inline-size` to a wrapper for component-level queries.
264
+
265
+ You opt in per region; nothing forces a markup shape.
266
+
267
+ ## The JS line
268
+
269
+ These are all CSS. Behavior that needs state (resize observers feeding app state,
270
+ virtualization, drag-resizable panels) belongs in your app or a sibling
271
+ `junoui-<framework>` package — not the design system.
package/docs/native.md ADDED
@@ -0,0 +1,52 @@
1
+ # Native mobile (Android / iOS)
2
+
3
+ Native platforms can't parse `oklch()`, so colors are pre-converted to sRGB hex
4
+ during the build. Values match the web rendering.
5
+
6
+ ## Android
7
+
8
+ Copy or sync the generated resources into your module:
9
+
10
+ ```
11
+ dist/android/colors.xml → res/values/colors.xml
12
+ dist/android/dimens.xml → res/values/dimens.xml
13
+ ```
14
+
15
+ Reference them:
16
+
17
+ ```xml
18
+ <TextView
19
+ android:textColor="@color/standard_dark_nominal"
20
+ android:padding="@dimen/space_16"
21
+ android:textSize="@dimen/font_size_14" />
22
+ ```
23
+
24
+ - Color names: `<palette>_<mode>_<role>` (e.g. `colorblind_dark_warning`).
25
+ - Dimensions are `dp`; font sizes are `sp`.
26
+ - Theme switching: pick the resource set for the active palette/mode, or split the
27
+ files into qualified `values-night/` for dark mode.
28
+
29
+ ## iOS (Swift)
30
+
31
+ Add the generated file to your target:
32
+
33
+ ```
34
+ dist/ios/JunoTokens.swift
35
+ ```
36
+
37
+ ```swift
38
+ label.textColor = JunoTokens.standardDarkNominal
39
+ let pad: CGFloat = JunoTokens.space16
40
+ let body: CGFloat = JunoTokens.fontSize14
41
+ ```
42
+
43
+ - Colors are `UIColor` constants named `<palette><Mode><Role>` (camelCase).
44
+ - Dimensions are `CGFloat` constants.
45
+
46
+ ## Keeping in sync
47
+
48
+ Re-run `npm run build` in junoui and re-copy the files (or script the copy in your
49
+ CI). Because all platforms derive from the same `tokens/` source, the values can
50
+ never drift between web and native.
51
+
52
+ Exact values for every token: [tokens-reference.md](./tokens-reference.md).
@@ -0,0 +1,106 @@
1
+ # Roadmap — missing capabilities
2
+
3
+ Gap analysis vs mature design systems (Material, Carbon, Radix, Polaris, Tailwind).
4
+ What junoui does **not** yet have, prioritised. The framework line holds throughout:
5
+ junoui ships the **look + the accessibility/structure contract**; stateful behavior
6
+ (focus traps, open/close, positioning, data) lives in apps or a sibling
7
+ `junoui-<framework>` package.
8
+
9
+ Priority key: 🔴 must · 🟡 high · 🟢 nice.
10
+
11
+ ## Have today
12
+
13
+ Tokens (color · spacing · type · radius · border · size · breakpoints · motion ·
14
+ z-index · elevation · opacity), density modes, themes (3 palettes × dark/light), CSS
15
+ components (badge, button, card, readout, status dot, loaders, **form controls** —
16
+ field · input · select · checkbox · radio · switch · slider; **overlays** — modal ·
17
+ drawer · tooltip · popover · menu), layout primitives + container queries,
18
+ multi-platform outputs, docs, lint + tests + CI.
19
+
20
+ ## Foundations (token gaps) — ✅ shipped 2026-06
21
+
22
+ All foundation token gaps are now built. Values: [tokens-reference.md](./tokens-reference.md);
23
+ usage: [design-guidelines.md](./design-guidelines.md).
24
+
25
+ | Done | What shipped |
26
+ | --------------------------------- | -------------------------------------------------------------------------------------------------------------- |
27
+ | **Motion** (duration + easing) | `--juno-motion-duration-{instant,quick,base,deliberate}` + `--juno-motion-ease-{decel,accel,standard,spring}`. |
28
+ | **Z-index scale** | `--juno-z-*` layer stack: surface · raised · anchored · overlay · alert. |
29
+ | **Elevation / shadow** | `--juno-shadow-{1,2,3}` (e1–e3) — border-first depth; shadow for lifted surfaces. |
30
+ | **Opacity scale** | `--juno-opacity-{disabled,muted,scrim}`. |
31
+ | **Density modes** (compact/comfy) | `data-juno-density` swaps semantic padding aliases (`--juno-pad-*`, `--juno-gap-control`). |
32
+
33
+ ## Components
34
+
35
+ | Missing | Priority |
36
+ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
37
+ | ~~**Form controls** — input, textarea, select, checkbox, radio, switch, slider~~ | ✅ shipped |
38
+ | ~~**Field** wrapper — label + control + help + error + required~~ | ✅ shipped |
39
+ | ~~**Overlays** — modal/dialog, drawer, tooltip, popover, menu/dropdown~~ | ✅ shipped |
40
+ | ~~**Table / data grid** styling~~ | ✅ shipped |
41
+ | ~~**Alert / toast / inline notification**~~ | ✅ shipped |
42
+ | ~~**Tabs**, accordion / disclosure~~ | ✅ shipped |
43
+ | ~~**Skeleton** loading placeholder (pairs with loaders)~~ | ✅ shipped |
44
+ | ~~Avatar, chip/tag, divider, breadcrumb, pagination, stepper~~ | ✅ shipped |
45
+ | **Chat layer** (`junoui-chat`) — message bubble, list, day separator, system pill, attachment cards, conversation header, chat-row, rail. Requested by the buzz integration; highest-leverage gap for chat apps. | 🟡 |
46
+ | Calendar **visuals** (event chip, day-cell) | 🟢 |
47
+
48
+ ## Field-driven — ✅ shipped 2026-07
49
+
50
+ Gaps surfaced by the first production consumer (a media-server web client, 2026-07):
51
+ everything a real app had to hand-roll on top of junoui, rebuilt here as generic,
52
+ reusable pieces. The rule stands — features land app-agnostic; only the origin is
53
+ logged.
54
+
55
+ | Done | What shipped |
56
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
57
+ | **Dense sizes** | `.juno-btn--sm` + `.juno-switch--sm` for 40–46px toolbar chrome / per-row toggles. |
58
+ | **Segmented control** | `.juno-seg` — radio-driven exclusive pill row, zero JS; `aria-pressed` button flavor. |
59
+ | **Gauge** | `.juno-gauge` — determinate metric ring (conic-gradient), value centered, threshold recipe doc. |
60
+ | **Spark** | `.juno-spark` — sparkline size/stroke/color contract (app supplies points; no charting shipped). |
61
+ | **Micro badge** | `.juno-badge--micro` — mono data-UI atom for provenance/kind tags + threshold values. |
62
+ | **Rail + app shell** | `.juno-rail` (collapsible, `aria-current`-styled) + `layout.md#app-shell` recipe. |
63
+ | **Content density** | `--juno-tile-min`/`--juno-gap-content` archetype + `.juno-grid-auto--tiles`. |
64
+ | **Slide-over recipe** | Drawer doc: scrim + header/body/pinned-footer composition from existing parts. |
65
+ | **Media/system icons** | 14 Phosphor glyphs: squares-four · images · hexagon · puzzle-piece · play · film-strip · cloud · cloud-arrow-down · arrows-clockwise · cpu · hard-drives · sliders · arrows-out · upload-simple. |
66
+
67
+ ## Mobile — ✅ shipped 2026-07
68
+
69
+ Mobile-first structures for narrow viewports and touch, automatic where safe,
70
+ opt-in where markup is needed:
71
+
72
+ | Done | What shipped |
73
+ | -------------------- | --------------------------------------------------------------------------------------------------------------------- |
74
+ | **Dock** | `.juno-dock` — bottom nav, phone counterpart of the rail; sticky, safe-area padded; shell swap recipe in `layout.md`. |
75
+ | **Bottom sheet** | Modal auto-converts below `bp.sm`: full-width, top-rounded, slides up, stretched footer actions. |
76
+ | **Drawer phone fit** | Side drawers cap at `85vw` (scrim stays tappable); bottom drawer pads for the home indicator. |
77
+ | **Toast snackbar** | Full-width bottom stack on phones; slides up instead of sideways. |
78
+ | **Scrollable tabs** | Tab strip scrolls sideways instead of overflowing. |
79
+ | **Stacked table** | `.juno-table--stack` + `data-label` — card rows below a 480px container; real `<table>` semantics kept. |
80
+ | **Touch ergonomics** | `pointer: coarse` raises `--juno-size-tap-min` → 44px; `hover: none` keeps table row actions visible. |
81
+ | **Pillbar** | `.juno-pillbar` — floating pill bar (iOS-style): 2–5 icon destinations/actions, translucent + blurred, safe-area. |
82
+ | **Navbar** | `.juno-navbar` — stack top bar: back control always on the start edge, centered truncating title, trailing actions. |
83
+ | **List** | `.juno-list` — grouped rows (settings pattern): icon + label/support + trailing value/control/chevron. |
84
+ | **Tab + stack** | Shell recipe in `layout.md`: dock/pillbar switches sections, navbar backs out of pushed views. |
85
+
86
+ ## Quality / infra
87
+
88
+ | Missing | Why | Priority |
89
+ | ------------------------------------------------ | ------------------------------------------------------------------------------------------------ | -------- |
90
+ | ~~**Visual regression** snapshots (Playwright)~~ | ✅ shipped — `npm run test:visual` diffs every showcase page (dark + light). | ✅ |
91
+ | ~~**Changesets**~~ | ✅ shipped — `npm run changeset`; manual Version PR (`npm run version`) → CI publishes on merge. | ✅ |
92
+ | ~~**Icon convention / set**~~ | ✅ shipped — `.juno-icon` + SVG sprite (Phosphor bold, MIT). | ✅ |
93
+ | **eslint** (flat config) | JS surface is small; prettier + tests cover most. | 🟢 |
94
+
95
+ Done already: stylelint + prettier, `node:test` integrity suite, a11y doc + ARIA
96
+ contract, forced-colors, RTL via logical properties, CI gate.
97
+
98
+ ## Recommended order
99
+
100
+ 1. ~~**Foundation tokens** — motion, z-index, elevation, opacity, density.~~ ✅ done.
101
+ 2. ~~**Form controls + field** — the single biggest capability gap.~~ ✅ done.
102
+ 3. ~~**Overlays** — modal, tooltip, menu.~~ ✅ done.
103
+ 4. ~~**Table / data grid** — sortable header, cell types, row states, overflow, skeleton/empty.~~ ✅ done.
104
+ 5. ~~**Quality** — visual-regression snapshots + changesets.~~ ✅ done.
105
+
106
+ Biggest leverage: **#1 + #2.**
@@ -0,0 +1,223 @@
1
+ <!-- GENERATED by scripts/gen-docs.mjs — do not edit by hand. Run `npm run gen-docs`. -->
2
+
3
+ # Token reference
4
+
5
+ Every junoui token with its value and the identifier to use on each platform.
6
+ Colors show the authored value and the resolved sRGB hex (use the hex in any
7
+ tool that does not understand `oklch()`).
8
+
9
+ ## How names map across platforms
10
+
11
+ | Platform | Pattern | Example (`color.standard.dark.nominal`) |
12
+ |---|---|---|
13
+ | CSS — semantic | `var(--juno-<role>)` (switches with theme attrs) | `var(--juno-nominal)` |
14
+ | SCSS | `$juno-color-<palette>-<mode>-<role>` | `$juno-color-standard-dark-nominal` |
15
+ | JS / TS | `TOKENS.<palette>.<mode>.<role>` | `TOKENS.standard.dark.nominal` |
16
+ | JSON (DTCG) | `color.<palette>.<mode>.<role>` | `color.standard.dark.nominal` |
17
+ | Android | `@color/<palette>_<mode>_<role>` | `@color/standard_dark_nominal` |
18
+ | iOS (Swift) | `JunoTokens.<camelCase>` | `JunoTokens.standardDarkNominal` |
19
+ | Flutter (Dart) | `JunoTokens.<camelCase>` | `JunoTokens.standardDarkNominal` |
20
+
21
+ Core tokens (spacing, radius, typography, …) use `--juno-<path-joined-by->`,
22
+ e.g. `space.16` → `var(--juno-space-16)`, `@dimen/space_16`, `JunoTokens.space16`.
23
+
24
+ ## Color roles
25
+
26
+ Color encodes status, never decoration. Each role has exactly one meaning.
27
+
28
+ ### Palette: colorblind
29
+
30
+ | Role | Dark value | Dark hex | Light value | Light hex |
31
+ |---|---|---|---|---|
32
+ | `nominal` | `#78A9FF` | `#78A9FF` | `#0043CE` | `#0043CE` |
33
+ | `active` | `#BE95FF` | `#BE95FF` | `#6929C4` | `#6929C4` |
34
+ | `target` | `#FF7EB6` | `#FF7EB6` | `#9F1853` | `#9F1853` |
35
+ | `caution` | `#F1C21B` | `#F1C21B` | `#7D4F00` | `#7D4F00` |
36
+ | `warning` | `#FF832B` | `#FF832B` | `#BA4300` | `#BA4300` |
37
+ | `data` | `oklch(93% 0.008 85)` | `#EAE7E2` | `oklch(14% 0.008 85)` | `#0B0906` |
38
+ | `data-dim` | `oklch(38% 0.010 85)` | `#45423C` | `oklch(70% 0.008 85)` | `#A19E99` |
39
+ | `label` | `oklch(63% 0.012 85)` | `#8C8981` | `oklch(42% 0.010 85)` | `#504D47` |
40
+ | `muted` | `oklch(48.5% 0.010 85)` | `#625F59` | `oklch(63% 0.008 85)` | `#8B8984` |
41
+ | `border` | `oklch(30% 0.012 85)` | `#312D27` | `oklch(82% 0.010 85)` | `#C7C4BD` |
42
+ | `border-strong` | `oklch(40% 0.012 85)` | `#4B4740` | `oklch(74% 0.010 85)` | `#AEAAA4` |
43
+ | `s0` | `oklch(11% 0.010 85)` | `#060402` | `oklch(97% 0.008 85)` | `#F8F5EF` |
44
+ | `s1` | `oklch(15% 0.012 85)` | `#0D0B06` | `oklch(93% 0.010 85)` | `#EBE7E0` |
45
+ | `s2` | `oklch(19% 0.012 85)` | `#16130E` | `oklch(89% 0.010 85)` | `#DEDAD3` |
46
+ | `s3` | `oklch(24% 0.012 85)` | `#221F19` | `oklch(85% 0.010 85)` | `#D1CDC7` |
47
+
48
+ ### Palette: soft
49
+
50
+ | Role | Dark value | Dark hex | Light value | Light hex |
51
+ |---|---|---|---|---|
52
+ | `nominal` | `oklch(63% 0.13 155)` | `#38A065` | `oklch(40% 0.11 155)` | `#00582C` |
53
+ | `active` | `oklch(67% 0.12 210)` | `#00A8BE` | `oklch(44% 0.11 210)` | `#006174` |
54
+ | `target` | `oklch(58% 0.14 318)` | `#9C5CAF` | `oklch(42% 0.12 318)` | `#673477` |
55
+ | `caution` | `oklch(72% 0.12 75)` | `#D09945` | `oklch(50% 0.12 75)` | `#8A5700` |
56
+ | `warning` | `oklch(62% 0.15 30)` | `#D15D4D` | `oklch(42% 0.13 30)` | `#86281D` |
57
+ | `data` | `oklch(90% 0.008 88)` | `#E0DED8` | `oklch(14% 0.008 88)` | `#0A0906` |
58
+ | `data-dim` | `oklch(39% 0.010 88)` | `#47453F` | `oklch(69% 0.008 88)` | `#9D9B96` |
59
+ | `label` | `oklch(63% 0.010 88)` | `#8C8982` | `oklch(44% 0.010 88)` | `#55524C` |
60
+ | `muted` | `oklch(48.5% 0.010 88)` | `#615F59` | `oklch(62.5% 0.008 88)` | `#8A8782` |
61
+ | `border` | `oklch(31% 0.010 88)` | `#32302B` | `oklch(84% 0.010 88)` | `#CDCAC3` |
62
+ | `border-strong` | `oklch(41% 0.010 88)` | `#4D4A44` | `oklch(76% 0.010 88)` | `#B4B1AA` |
63
+ | `s0` | `oklch(12% 0.012 88)` | `#070602` | `oklch(96% 0.010 88)` | `#F4F2EA` |
64
+ | `s1` | `oklch(16% 0.012 88)` | `#0F0D08` | `oklch(92% 0.010 88)` | `#E7E4DD` |
65
+ | `s2` | `oklch(20% 0.012 88)` | `#181610` | `oklch(88% 0.010 88)` | `#DAD7D0` |
66
+ | `s3` | `oklch(25% 0.012 88)` | `#24211B` | `oklch(84% 0.010 88)` | `#CDCAC3` |
67
+
68
+ ### Palette: standard
69
+
70
+ | Role | Dark value | Dark hex | Light value | Light hex |
71
+ |---|---|---|---|---|
72
+ | `nominal` | `oklch(73% 0.22 148)` | `#00CB4C` | `oklch(42% 0.18 148)` | `#006400` |
73
+ | `active` | `oklch(76% 0.16 204)` | `#00CDDF` | `oklch(47% 0.16 220)` | `#006B98` |
74
+ | `target` | `oklch(65% 0.26 324)` | `#D63DE6` | `oklch(45% 0.22 324)` | `#8B0097` |
75
+ | `caution` | `oklch(77% 0.17 73)` | `#F4A000` | `oklch(50% 0.17 73)` | `#9B4C00` |
76
+ | `warning` | `oklch(63% 0.22 28)` | `#F13A32` | `oklch(42% 0.21 26)` | `#A10000` |
77
+ | `data` | `oklch(93% 0.008 85)` | `#EAE7E2` | `oklch(14% 0.008 85)` | `#0B0906` |
78
+ | `data-dim` | `oklch(38% 0.010 85)` | `#45423C` | `oklch(70% 0.008 85)` | `#A19E99` |
79
+ | `label` | `oklch(63% 0.012 85)` | `#8C8981` | `oklch(42% 0.010 85)` | `#504D47` |
80
+ | `muted` | `oklch(48.5% 0.010 85)` | `#625F59` | `oklch(63% 0.008 85)` | `#8B8984` |
81
+ | `border` | `oklch(30% 0.012 85)` | `#312D27` | `oklch(82% 0.010 85)` | `#C7C4BD` |
82
+ | `border-strong` | `oklch(40% 0.012 85)` | `#4B4740` | `oklch(74% 0.010 85)` | `#AEAAA4` |
83
+ | `s0` | `oklch(11% 0.010 85)` | `#060402` | `oklch(97% 0.008 85)` | `#F8F5EF` |
84
+ | `s1` | `oklch(15% 0.012 85)` | `#0D0B06` | `oklch(93% 0.010 85)` | `#EBE7E0` |
85
+ | `s2` | `oklch(19% 0.012 85)` | `#16130E` | `oklch(89% 0.010 85)` | `#DEDAD3` |
86
+ | `s3` | `oklch(24% 0.012 85)` | `#221F19` | `oklch(85% 0.010 85)` | `#D1CDC7` |
87
+
88
+ ## Core tokens
89
+
90
+ ### Borders
91
+
92
+ | Token | Value | CSS variable | Flutter / iOS |
93
+ |---|---|---|---|
94
+ | `border.width.1` | `1px` | `var(--juno-border-width-1)` | `JunoTokens.borderWidth1` |
95
+ | `border.width.2` | `2px` | `var(--juno-border-width-2)` | `JunoTokens.borderWidth2` |
96
+ | `border.width.3` | `3px` | `var(--juno-border-width-3)` | `JunoTokens.borderWidth3` |
97
+
98
+ ### Breakpoints
99
+
100
+ | Token | Value | CSS variable | Flutter / iOS |
101
+ |---|---|---|---|
102
+ | `bp.sm` | `640px` | `var(--juno-bp-sm)` | `JunoTokens.bpSm` |
103
+ | `bp.md` | `768px` | `var(--juno-bp-md)` | `JunoTokens.bpMd` |
104
+ | `bp.lg` | `1024px` | `var(--juno-bp-lg)` | `JunoTokens.bpLg` |
105
+ | `bp.xl` | `1280px` | `var(--juno-bp-xl)` | `JunoTokens.bpXl` |
106
+ | `bp.2xl` | `1536px` | `var(--juno-bp-2xl)` | `JunoTokens.bp2xl` |
107
+
108
+ ### Elevation
109
+
110
+ | Token | Value | CSS variable | Flutter / iOS |
111
+ |---|---|---|---|
112
+ | `shadow.1` | `0 1px 2px rgb(0 0 0 / 0.30)` | `var(--juno-shadow-1)` | `JunoTokens.shadow1` |
113
+ | `shadow.2` | `0 4px 14px rgb(0 0 0 / 0.35)` | `var(--juno-shadow-2)` | `JunoTokens.shadow2` |
114
+ | `shadow.3` | `0 12px 32px rgb(0 0 0 / 0.50)` | `var(--juno-shadow-3)` | `JunoTokens.shadow3` |
115
+
116
+ ### Motion
117
+
118
+ | Token | Value | CSS variable | Flutter / iOS |
119
+ |---|---|---|---|
120
+ | `motion.duration.instant` | `80ms` | `var(--juno-motion-duration-instant)` | `JunoTokens.motionDurationInstant` |
121
+ | `motion.duration.quick` | `140ms` | `var(--juno-motion-duration-quick)` | `JunoTokens.motionDurationQuick` |
122
+ | `motion.duration.base` | `200ms` | `var(--juno-motion-duration-base)` | `JunoTokens.motionDurationBase` |
123
+ | `motion.duration.deliberate` | `300ms` | `var(--juno-motion-duration-deliberate)` | `JunoTokens.motionDurationDeliberate` |
124
+ | `motion.ease.decel` | `cubic-bezier(0.2, 0.8, 0.2, 1)` | `var(--juno-motion-ease-decel)` | `JunoTokens.motionEaseDecel` |
125
+ | `motion.ease.accel` | `cubic-bezier(0.4, 0, 1, 1)` | `var(--juno-motion-ease-accel)` | `JunoTokens.motionEaseAccel` |
126
+ | `motion.ease.standard` | `cubic-bezier(0.2, 0.7, 0.3, 1)` | `var(--juno-motion-ease-standard)` | `JunoTokens.motionEaseStandard` |
127
+ | `motion.ease.spring` | `cubic-bezier(0.2, 0.9, 0.3, 1.2)` | `var(--juno-motion-ease-spring)` | `JunoTokens.motionEaseSpring` |
128
+
129
+ ### Opacity
130
+
131
+ | Token | Value | CSS variable | Flutter / iOS |
132
+ |---|---|---|---|
133
+ | `opacity.disabled` | `0.45` | `var(--juno-opacity-disabled)` | `JunoTokens.opacityDisabled` |
134
+ | `opacity.muted` | `0.65` | `var(--juno-opacity-muted)` | `JunoTokens.opacityMuted` |
135
+ | `opacity.scrim` | `0.62` | `var(--juno-opacity-scrim)` | `JunoTokens.opacityScrim` |
136
+
137
+ ### Radius
138
+
139
+ | Token | Value | CSS variable | Flutter / iOS |
140
+ |---|---|---|---|
141
+ | `radius.2` | `2px` | `var(--juno-radius-2)` | `JunoTokens.radius2` |
142
+ | `radius.3` | `3px` | `var(--juno-radius-3)` | `JunoTokens.radius3` |
143
+ | `radius.4` | `4px` | `var(--juno-radius-4)` | `JunoTokens.radius4` |
144
+ | `radius.5` | `5px` | `var(--juno-radius-5)` | `JunoTokens.radius5` |
145
+ | `radius.8` | `8px` | `var(--juno-radius-8)` | `JunoTokens.radius8` |
146
+
147
+ ### Sizing
148
+
149
+ | Token | Value | CSS variable | Flutter / iOS |
150
+ |---|---|---|---|
151
+ | `size.tap.min` | `24px` | `var(--juno-size-tap-min)` | `JunoTokens.sizeTapMin` |
152
+ | `size.tap.comfortable` | `44px` | `var(--juno-size-tap-comfortable)` | `JunoTokens.sizeTapComfortable` |
153
+ | `size.dot.sm` | `8px` | `var(--juno-size-dot-sm)` | `JunoTokens.sizeDotSm` |
154
+ | `size.dot.md` | `10px` | `var(--juno-size-dot-md)` | `JunoTokens.sizeDotMd` |
155
+
156
+ ### Spacing
157
+
158
+ | Token | Value | CSS variable | Flutter / iOS |
159
+ |---|---|---|---|
160
+ | `space.2` | `2px` | `var(--juno-space-2)` | `JunoTokens.space2` |
161
+ | `space.4` | `4px` | `var(--juno-space-4)` | `JunoTokens.space4` |
162
+ | `space.8` | `8px` | `var(--juno-space-8)` | `JunoTokens.space8` |
163
+ | `space.10` | `10px` | `var(--juno-space-10)` | `JunoTokens.space10` |
164
+ | `space.12` | `12px` | `var(--juno-space-12)` | `JunoTokens.space12` |
165
+ | `space.16` | `16px` | `var(--juno-space-16)` | `JunoTokens.space16` |
166
+ | `space.20` | `20px` | `var(--juno-space-20)` | `JunoTokens.space20` |
167
+ | `space.24` | `24px` | `var(--juno-space-24)` | `JunoTokens.space24` |
168
+ | `space.28` | `28px` | `var(--juno-space-28)` | `JunoTokens.space28` |
169
+ | `space.32` | `32px` | `var(--juno-space-32)` | `JunoTokens.space32` |
170
+ | `space.40` | `40px` | `var(--juno-space-40)` | `JunoTokens.space40` |
171
+ | `space.56` | `56px` | `var(--juno-space-56)` | `JunoTokens.space56` |
172
+ | `space.72` | `72px` | `var(--juno-space-72)` | `JunoTokens.space72` |
173
+ | `space.96` | `96px` | `var(--juno-space-96)` | `JunoTokens.space96` |
174
+
175
+ ### Typography
176
+
177
+ | Token | Value | CSS variable | Flutter / iOS |
178
+ |---|---|---|---|
179
+ | `font.family.sans` | `'B612', sans-serif` | `var(--juno-font-family-sans)` | `JunoTokens.fontFamilySans` |
180
+ | `font.family.mono` | `'B612 Mono', monospace` | `var(--juno-font-family-mono)` | `JunoTokens.fontFamilyMono` |
181
+ | `font.weight.light` | `300` | `var(--juno-font-weight-light)` | `JunoTokens.fontWeightLight` |
182
+ | `font.weight.regular` | `400` | `var(--juno-font-weight-regular)` | `JunoTokens.fontWeightRegular` |
183
+ | `font.weight.medium` | `500` | `var(--juno-font-weight-medium)` | `JunoTokens.fontWeightMedium` |
184
+ | `font.weight.semibold` | `600` | `var(--juno-font-weight-semibold)` | `JunoTokens.fontWeightSemibold` |
185
+ | `font.weight.bold` | `700` | `var(--juno-font-weight-bold)` | `JunoTokens.fontWeightBold` |
186
+ | `font.size.10` | `10px` | `var(--juno-font-size-10)` | `JunoTokens.fontSize10` |
187
+ | `font.size.11` | `11px` | `var(--juno-font-size-11)` | `JunoTokens.fontSize11` |
188
+ | `font.size.12` | `12px` | `var(--juno-font-size-12)` | `JunoTokens.fontSize12` |
189
+ | `font.size.13` | `13px` | `var(--juno-font-size-13)` | `JunoTokens.fontSize13` |
190
+ | `font.size.14` | `14px` | `var(--juno-font-size-14)` | `JunoTokens.fontSize14` |
191
+ | `font.size.16` | `16px` | `var(--juno-font-size-16)` | `JunoTokens.fontSize16` |
192
+ | `font.size.18` | `18px` | `var(--juno-font-size-18)` | `JunoTokens.fontSize18` |
193
+ | `font.size.20` | `20px` | `var(--juno-font-size-20)` | `JunoTokens.fontSize20` |
194
+ | `font.size.28` | `28px` | `var(--juno-font-size-28)` | `JunoTokens.fontSize28` |
195
+ | `font.size.32` | `32px` | `var(--juno-font-size-32)` | `JunoTokens.fontSize32` |
196
+ | `font.size.36` | `36px` | `var(--juno-font-size-36)` | `JunoTokens.fontSize36` |
197
+ | `font.size.38` | `38px` | `var(--juno-font-size-38)` | `JunoTokens.fontSize38` |
198
+ | `font.size.48` | `48px` | `var(--juno-font-size-48)` | `JunoTokens.fontSize48` |
199
+ | `font.size.52` | `52px` | `var(--juno-font-size-52)` | `JunoTokens.fontSize52` |
200
+ | `font.lineHeight.none` | `1` | `var(--juno-font-lineHeight-none)` | `JunoTokens.fontLineHeightNone` |
201
+ | `font.lineHeight.tight` | `1.1` | `var(--juno-font-lineHeight-tight)` | `JunoTokens.fontLineHeightTight` |
202
+ | `font.lineHeight.snug` | `1.2` | `var(--juno-font-lineHeight-snug)` | `JunoTokens.fontLineHeightSnug` |
203
+ | `font.lineHeight.normal` | `1.4` | `var(--juno-font-lineHeight-normal)` | `JunoTokens.fontLineHeightNormal` |
204
+ | `font.lineHeight.relaxed` | `1.5` | `var(--juno-font-lineHeight-relaxed)` | `JunoTokens.fontLineHeightRelaxed` |
205
+ | `font.lineHeight.loose` | `1.7` | `var(--juno-font-lineHeight-loose)` | `JunoTokens.fontLineHeightLoose` |
206
+ | `font.tracking.tight` | `0.02em` | `var(--juno-font-tracking-tight)` | `JunoTokens.fontTrackingTight` |
207
+ | `font.tracking.normal` | `0.06em` | `var(--juno-font-tracking-normal)` | `JunoTokens.fontTrackingNormal` |
208
+ | `font.tracking.label` | `0.08em` | `var(--juno-font-tracking-label)` | `JunoTokens.fontTrackingLabel` |
209
+ | `font.tracking.wide` | `0.12em` | `var(--juno-font-tracking-wide)` | `JunoTokens.fontTrackingWide` |
210
+ | `font.tracking.caps` | `0.15em` | `var(--juno-font-tracking-caps)` | `JunoTokens.fontTrackingCaps` |
211
+ | `font.tracking.wider` | `0.2em` | `var(--juno-font-tracking-wider)` | `JunoTokens.fontTrackingWider` |
212
+ | `font.tracking.widest` | `0.3em` | `var(--juno-font-tracking-widest)` | `JunoTokens.fontTrackingWidest` |
213
+
214
+ ### Z-index
215
+
216
+ | Token | Value | CSS variable | Flutter / iOS |
217
+ |---|---|---|---|
218
+ | `z.surface` | `0` | `var(--juno-z-surface)` | `JunoTokens.zSurface` |
219
+ | `z.raised` | `100` | `var(--juno-z-raised)` | `JunoTokens.zRaised` |
220
+ | `z.anchored` | `2000` | `var(--juno-z-anchored)` | `JunoTokens.zAnchored` |
221
+ | `z.overlay` | `4000` | `var(--juno-z-overlay)` | `JunoTokens.zOverlay` |
222
+ | `z.alert` | `5000` | `var(--juno-z-alert)` | `JunoTokens.zAlert` |
223
+