layered-ui-rails 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8e4d9560a90e896fb66753e342a555c9ce281764e2c3c7ac9d326a4a52d5ff4
4
- data.tar.gz: 3c1f55587df50d2f0def13536b0adb3c8869682246932fd73ddcd146a63a4e38
3
+ metadata.gz: '0596cb85b0ecaf7e9efe534a5d7b7ff9e9c3f0848d1faf8972ce7f1e4617fb1b'
4
+ data.tar.gz: f03e28644cd462bcf5988d851d4f85ad177761fd37eea52ed404a4046b230404
5
5
  SHA512:
6
- metadata.gz: 99a8dff88d32df2645427d4802d64294744cfc51d185e3b7df7b1fbf25db5887472b654293c6ce3af78440be2730a809c73f37bf282e6166d47b39ec80e85530
7
- data.tar.gz: 13f9cc999716982874cfc3a6eaff48e63a5c7a06b608e321692de90d573c74e2879229dec97bd6250f3afb5b4bdfd222fef6150643b92e7f38d77b2b28fb85f3
6
+ metadata.gz: 72a5b12ad90bd8997f03e7f9624af1ef3cfeeffc25db54a147c435bde91bb6ed49c353bf049210ec122eae10297db94b96d1918c88131acb13fac1786171feca
7
+ data.tar.gz: 150ccf137e7e41cb2181444b11c73cb3bb583ae3e1160b3f87cc70ee019acf34c688af70e6a09ad04b5ff756a5e8f7f72fd4e9afedbb408a052ad6b81cde41ca
@@ -0,0 +1,189 @@
1
+ ---
2
+ name: layered-ui-rails
3
+ description: Installs, configures, and builds with the layered-ui-rails gem - a Rails 8+ engine providing WCAG 2.2 AA compliant layout, components, and Stimulus controllers with dark/light theming. Use when adding layered-ui-rails to a Rails app, building views with its layout and helpers, styling with its CSS classes, or troubleshooting setup.
4
+ license: Apache-2.0
5
+ compatibility: Requires Ruby on Rails >= 8.0, tailwindcss-rails >= 4.0, importmap-rails >= 2.0, stimulus-rails >= 1.0
6
+ metadata:
7
+ author: layered.ai
8
+ version: "1.0"
9
+ source: https://github.com/layered-ai-public/layered-ui-rails
10
+ ---
11
+
12
+ # layered-ui-rails
13
+
14
+ A Rails 8+ engine providing WCAG 2.2 AA compliant design tokens, Tailwind CSS components, and Stimulus controllers for theme switching, mobile navigation, slide-out panels, modals, and tabs.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ bundle add layered-ui-rails
20
+ bin/rails generate layered:ui:install
21
+ ```
22
+
23
+ The generator copies `layered_ui.css` into `app/assets/tailwind/`, adds the CSS import to `application.css`, and adds the JS import to `application.js`.
24
+
25
+ Then render the engine layout from your application layout:
26
+
27
+ ```erb
28
+ <%= render template: "layouts/layered_ui/application" %>
29
+ ```
30
+
31
+ ## Layout structure
32
+
33
+ The engine layout provides a fixed header (63px), optional sidebar navigation (240px wide), optional resizable panel (320px default), and a main content area. Dark mode is built in with a toggle and localStorage persistence.
34
+
35
+ ### Content blocks
36
+
37
+ Populate layout regions with `content_for`:
38
+
39
+ ```erb
40
+ <%# Navigation sidebar items %>
41
+ <% content_for :l_ui_navigation_items do %>
42
+ <%= l_ui_navigation_item("Dashboard", dashboard_path) %>
43
+ <%= l_ui_navigation_item("Users", users_path) %>
44
+ <% end %>
45
+
46
+ <%# Side panel %>
47
+ <% content_for :l_ui_panel_heading do %>
48
+ Help
49
+ <% end %>
50
+ <% content_for :l_ui_panel_body do %>
51
+ <p>Panel content here.</p>
52
+ <% end %>
53
+
54
+ <%# Inject into <head> (e.g. per-tenant theming) %>
55
+ <% content_for :l_ui_head do %>
56
+ <style nonce="<%= content_security_policy_nonce %>">
57
+ :root { --accent: 220 80% 55%; }
58
+ </style>
59
+ <% end %>
60
+
61
+ <%# Add CSS classes to <body> %>
62
+ <% content_for :l_ui_body_class do %>
63
+ l-ui-body--always-show-navigation
64
+ <% end %>
65
+
66
+ <%# Override logos %>
67
+ <% content_for :l_ui_logo_light do %>
68
+ <%= image_tag "my_logo.svg", alt: "", class: "l-ui-header__logo l-ui-header__logo--light" %>
69
+ <% end %>
70
+ <% content_for :l_ui_logo_dark do %>
71
+ <%= image_tag "my_logo_dark.svg", alt: "", class: "l-ui-header__logo l-ui-header__logo--dark" %>
72
+ <% end %>
73
+ ```
74
+
75
+ Body class modifiers:
76
+ - `l-ui-body--always-show-navigation` - pins navigation as a sidebar on desktop
77
+ - `l-ui-body--hide-header` - hides the header and collapses its space
78
+
79
+ ### Controller instance variables
80
+
81
+ ```ruby
82
+ @page_title = "Users" # Sets <title>
83
+ @page_description = "Manage users" # Sets <meta name="description">
84
+ @l_ui_icon_light_url = url # Override favicon (light)
85
+ @l_ui_icon_dark_url = url # Override favicon (dark)
86
+ @l_ui_apple_touch_icon_url = url # Override apple touch icon
87
+ @l_ui_panel_icon_light_url = url # Override panel button icon (light)
88
+ @l_ui_panel_icon_dark_url = url # Override panel button icon (dark)
89
+ ```
90
+
91
+ ## View helpers
92
+
93
+ All helpers use the `l_ui_` prefix and are available in all views automatically. See `references/HELPERS.md` for full signatures and examples.
94
+
95
+ Quick reference:
96
+
97
+ | Helper | Purpose |
98
+ |---|---|
99
+ | `l_ui_navigation_item(label, path, active: nil, &block)` | Sidebar nav link with optional nesting |
100
+ | `l_ui_breadcrumbs(&block)` | Breadcrumb nav wrapper |
101
+ | `l_ui_breadcrumb_item(label, path = nil)` | Individual breadcrumb |
102
+ | `l_ui_pagy(pagy)` | Styled pagination (requires pagy gem) |
103
+ | `l_ui_search_form(query, url:, fields:, ...)` | Search form (requires ransack gem) |
104
+ | `l_ui_sort_link(query, attribute, label = nil, ...)` | Sortable table header (requires ransack gem) |
105
+ | `l_ui_user_signed_in?` | Check if user is authenticated |
106
+ | `l_ui_current_user` | Current user object |
107
+
108
+ ## CSS classes
109
+
110
+ All classes use the `l-ui-` prefix with BEM naming. Use these in host app views rather than raw Tailwind utilities. See `references/CSS.md` for the full catalogue.
111
+
112
+ Key components:
113
+
114
+ | Component | Key classes |
115
+ |---|---|
116
+ | Page layout | `.l-ui-page`, `--with-navigation`, `--vertically-centered`, `--width-constrained` |
117
+ | Buttons | `.l-ui-button`, `--primary`, `--outline`, `--outline-danger`, `--full`, `--icon` |
118
+ | Surfaces | `.l-ui-surface`, `--active`, `--sm`, `--collapsible` |
119
+ | Forms | `.l-ui-form`, `.l-ui-form__group`, `.l-ui-form__field`, `.l-ui-label`, `.l-ui-select` |
120
+ | Tables | `.l-ui-table`, `.l-ui-table__header`, `.l-ui-table__cell`, `--primary`, `--action` |
121
+ | Badges | `.l-ui-badge`, `--rounded`, `--default`, `--success`, `--warning`, `--danger` |
122
+ | Notices | `.l-ui-notice--success`, `--warning`, `--error` |
123
+ | Tabs | `.l-ui-tabs__list`, `.l-ui-tabs__tab`, `--active` |
124
+ | Modal | `.l-ui-modal`, `.l-ui-modal__header`, `.l-ui-modal__body` |
125
+
126
+ ## Stimulus controllers
127
+
128
+ All controllers use the `l-ui--` namespace and are auto-registered via importmap.
129
+
130
+ | Controller | Identifier | Purpose |
131
+ |---|---|---|
132
+ | Theme | `l-ui--theme` | Dark/light mode toggle with localStorage |
133
+ | Navigation | `l-ui--navigation` | Responsive sidebar with backdrop |
134
+ | Panel | `l-ui--panel` | Resizable side panel (Cmd/Ctrl+I toggle) |
135
+ | Panel button | `l-ui--panel-button` | Draggable floating action button |
136
+ | Panel resize | `l-ui--panel-resize` | Panel width drag handle |
137
+ | Modal | `l-ui--modal` | Native `<dialog>` with focus trap |
138
+ | Tabs | `l-ui--tabs` | Accessible tabbed interface |
139
+ | Search form | `l-ui--search-form` | Multi-scope search with Turbo support |
140
+
141
+ ## Theming
142
+
143
+ Override CSS custom properties after the engine import. Values are space-separated HSL channels (no `hsl()` wrapper).
144
+
145
+ ```css
146
+ @import "./layered_ui";
147
+
148
+ :root {
149
+ --accent: 220 80% 55%;
150
+ --accent-foreground: 0 0% 100%;
151
+ }
152
+ .dark {
153
+ --accent: 220 80% 65%;
154
+ }
155
+ ```
156
+
157
+ Key tokens: `--accent`, `--accent-foreground`, `--background`, `--foreground`, `--foreground-muted`, `--border`, `--border-control`, `--surface`, `--surface-active`, `--danger`, `--header-height`.
158
+
159
+ ## Asset overrides
160
+
161
+ Place files in `app/assets/images/layered_ui/` to replace engine defaults:
162
+
163
+ `logo_light.svg`, `logo_dark.svg`, `icon_light.svg`, `icon_dark.svg`, `apple_touch_icon.png`, `panel_icon_light.svg`, `panel_icon_dark.svg`.
164
+
165
+ ## Optional integrations
166
+
167
+ - **Devise** - auto-detected. Provides styled auth views, header login/register buttons, sidebar user info and logout.
168
+ - **Pagy** - auto-detected. Use `l_ui_pagy(@pagy)` for styled pagination.
169
+ - **Ransack** - auto-detected. Use `l_ui_search_form` and `l_ui_sort_link` for styled search and sortable tables.
170
+
171
+ ## Configuration
172
+
173
+ ```ruby
174
+ # config/initializers/layered_ui.rb
175
+ Layered::Ui.current_user_method = :current_member # default: :current_user
176
+ ```
177
+
178
+ ## Common issues
179
+
180
+ - **Tailwind classes not generated** - The host app's Tailwind build only sees classes in the host app's templates. Use `l-ui-` classes (which are in the copied CSS) rather than raw Tailwind utilities when styling engine-provided patterns.
181
+ - **Missing styles** - Ensure `@import "./layered_ui";` is in `app/assets/tailwind/application.css`.
182
+ - **Missing JS controllers** - Ensure `import "layered_ui"` is in `app/javascript/application.js`.
183
+
184
+ ## Further reference
185
+
186
+ - `references/HELPERS.md` - full helper signatures and examples
187
+ - `references/CSS.md` - complete CSS class catalogue
188
+ - `references/CONTROLLERS.md` - Stimulus controller targets, actions, and usage patterns
189
+ - Live demo: https://layered-ui-rails.layered.ai
@@ -0,0 +1,156 @@
1
+ # Stimulus controllers
2
+
3
+ All controllers use the `l-ui--` namespace and are auto-registered via importmap. No manual registration is needed in the host app.
4
+
5
+ ## Theme (`l-ui--theme`)
6
+
7
+ Toggles dark/light mode with localStorage persistence and system preference detection.
8
+
9
+ **Targets:** `button`
10
+ **Actions:** `toggle`
11
+ **Storage key:** `theme` (stores `"dark"` or `"light"`)
12
+
13
+ The layout already wires this up. To add your own toggle button:
14
+
15
+ ```html
16
+ <button data-controller="l-ui--theme"
17
+ data-action="click->l-ui--theme#toggle"
18
+ data-l-ui--theme-target="button"
19
+ aria-pressed="false">
20
+ Toggle theme
21
+ </button>
22
+ ```
23
+
24
+ ## Navigation (`l-ui--navigation`)
25
+
26
+ Responsive sidebar navigation with backdrop overlay on mobile.
27
+
28
+ **Targets:** `navigation`, `backdrop`, `toggleButton`, `openIcon`, `closeIcon`
29
+ **Actions:** `toggle`, `close`
30
+ **Keyboard:** Escape to close
31
+
32
+ The layout wires this up automatically. Navigation items are populated via `content_for :l_ui_navigation_items`.
33
+
34
+ ## Modal (`l-ui--modal`)
35
+
36
+ Native `<dialog>` wrapper with focus trap, scroll lock, and focus restoration.
37
+
38
+ **Targets:** `dialog`
39
+ **Actions:** `open`, `close`, `closeOnBackdrop`
40
+
41
+ ```html
42
+ <div data-controller="l-ui--modal">
43
+ <button data-action="click->l-ui--modal#open" class="l-ui-button">
44
+ Open modal
45
+ </button>
46
+ <dialog data-l-ui--modal-target="dialog" class="l-ui-modal">
47
+ <div class="l-ui-modal__header">
48
+ <h2>Title</h2>
49
+ <button data-action="click->l-ui--modal#close" class="l-ui-button--icon">
50
+ Close
51
+ </button>
52
+ </div>
53
+ <div class="l-ui-modal__body">
54
+ Content here.
55
+ </div>
56
+ </dialog>
57
+ </div>
58
+ ```
59
+
60
+ Features:
61
+ - Focus moves to first focusable element on open
62
+ - Focus returns to trigger element on close
63
+ - Body scroll is locked while open
64
+ - Supports nested modals
65
+
66
+ ## Tabs (`l-ui--tabs`)
67
+
68
+ Accessible tabbed interface with keyboard navigation.
69
+
70
+ **Targets:** `tab`, `panel`
71
+ **Actions:** `select`, `keydown`
72
+ **Keyboard:** Arrow Left/Right, Home, End
73
+
74
+ ```html
75
+ <div data-controller="l-ui--tabs">
76
+ <div role="tablist" class="l-ui-tabs__list">
77
+ <button role="tab" data-l-ui--tabs-target="tab"
78
+ data-action="click->l-ui--tabs#select keydown->l-ui--tabs#keydown"
79
+ class="l-ui-tabs__tab l-ui-tabs__tab--active"
80
+ aria-selected="true" tabindex="0">
81
+ Tab 1
82
+ </button>
83
+ <button role="tab" data-l-ui--tabs-target="tab"
84
+ data-action="click->l-ui--tabs#select keydown->l-ui--tabs#keydown"
85
+ class="l-ui-tabs__tab"
86
+ aria-selected="false" tabindex="-1">
87
+ Tab 2
88
+ </button>
89
+ </div>
90
+ <div role="tabpanel" data-l-ui--tabs-target="panel">
91
+ Content 1
92
+ </div>
93
+ <div role="tabpanel" data-l-ui--tabs-target="panel" hidden>
94
+ Content 2
95
+ </div>
96
+ </div>
97
+ ```
98
+
99
+ ## Panel (`l-ui--panel`)
100
+
101
+ Resizable side panel. Full-width overlay on mobile, docked sidebar on desktop.
102
+
103
+ **Targets:** `container`, `hideButton`, `actionButton`
104
+ **Actions:** `toggle`
105
+ **Keyboard:** Cmd/Ctrl+I to toggle
106
+ **Storage key:** `panelOpen` (stores `"true"` or `"false"`)
107
+
108
+ The layout wires this up automatically. Panel content is populated via `content_for :l_ui_panel_heading` and `content_for :l_ui_panel_body`.
109
+
110
+ ## Panel button (`l-ui--panel-button`)
111
+
112
+ Draggable floating action button that toggles the panel.
113
+
114
+ **Actions:** `queueToggle`, `cycleCorner`, `startDrag`, `drag`, `stopDrag`
115
+ **Keyboard:** Cmd/Ctrl+Alt+1/2/3/4 to move to corners
116
+ **Storage key:** `panelButtonPosition` (JSON with `{edge, top}`)
117
+
118
+ Features:
119
+ - Drag with mouse or touch
120
+ - Auto-snaps to nearest screen edge
121
+ - Double-click cycles through four corners
122
+ - 5px drag threshold prevents accidental clicks
123
+
124
+ ## Panel resize (`l-ui--panel-resize`)
125
+
126
+ Drag handle for resizing the panel width on desktop.
127
+
128
+ **Targets:** `container`, `handle`
129
+ **Actions:** `startResize`, `resize`, `stopResize`, `handleKeydown`, `resetWidth`
130
+ **Keyboard:** Arrow Left/Right (10px), Shift+Arrow (50px), Home/End
131
+ **Storage key:** `panelWidth` (pixel value)
132
+
133
+ - Min width: 240px
134
+ - Default width: 480px
135
+ - Double-click handle to reset to default
136
+
137
+ ## Search form (`l-ui--search-form`)
138
+
139
+ Manages multi-scope search forms with parameter preservation and Turbo frame support.
140
+
141
+ **Values:** `scope` (String, default `"q"`)
142
+ **Actions:** `preserve`, `clear`
143
+
144
+ ```html
145
+ <form data-controller="l-ui--search-form"
146
+ data-l-ui--search-form-scope-value="q"
147
+ data-action="submit->l-ui--search-form#preserve"
148
+ data-turbo-frame="results">
149
+ <!-- search fields -->
150
+ <button type="button" data-action="click->l-ui--search-form#clear">
151
+ Clear
152
+ </button>
153
+ </form>
154
+ ```
155
+
156
+ When multiple search forms exist on one page (each with a different `scope` value), submitting one form automatically preserves the other forms' query parameters.
@@ -0,0 +1,298 @@
1
+ # CSS classes
2
+
3
+ All classes use the `l-ui-` prefix with BEM naming. Use these in host app views. Do not use raw Tailwind utilities for engine-provided patterns as they will not be generated by the host app's Tailwind build.
4
+
5
+ ## Page layout
6
+
7
+ ```
8
+ .l-ui-page Main content wrapper with responsive padding
9
+ .l-ui-page--with-navigation Left margin for sidebar on desktop
10
+ .l-ui-page--vertically-centered Centred layout (e.g. login pages)
11
+ .l-ui-page--width-constrained Max-width container
12
+ ```
13
+
14
+ ## Buttons
15
+
16
+ ```
17
+ .l-ui-button Base button with padding and focus ring
18
+ .l-ui-button--primary Accent-coloured button
19
+ .l-ui-button--outline Bordered button
20
+ .l-ui-button--outline-danger Red bordered button
21
+ .l-ui-button--full Full-width button
22
+ .l-ui-button--icon Icon-only button (fixed size, no text)
23
+ .l-ui-button--disabled Disabled appearance
24
+ .l-ui-button--navigation-toggle Mobile navigation toggle
25
+ .l-ui-button--panel-close Panel close button
26
+ ```
27
+
28
+ ## Surfaces
29
+
30
+ ```
31
+ .l-ui-surface Rounded, padded container
32
+ .l-ui-surface--active Darker background variant
33
+ .l-ui-surface--sm Smaller padding
34
+ .l-ui-surface--collapsible Wraps a <details> element
35
+ .l-ui-surface--collapsible-active Open state
36
+ .l-ui-surface__summary Collapsible toggle (on <summary>)
37
+ .l-ui-surface__chevron Chevron indicator (rotates on open)
38
+ .l-ui-surface__content Collapsible content area
39
+ ```
40
+
41
+ ## Forms
42
+
43
+ ```
44
+ .l-ui-form Form container
45
+ .l-ui-form__group Vertical field group with spacing
46
+ .l-ui-form__group--large-gap Larger spacing variant
47
+ .l-ui-form__field Input/textarea styling
48
+ .l-ui-form__errors Error summary box
49
+ .l-ui-form__errors-list Bulleted error list
50
+ .l-ui-form__field-error Individual field error message
51
+ .l-ui-form__hint Field hint text
52
+ .l-ui-form__required Required indicator (*)
53
+
54
+ .l-ui-label Form label
55
+ .l-ui-label--checkbox Checkbox label variant
56
+
57
+ .l-ui-select Select dropdown
58
+ .l-ui-select-wrapper Select wrapper (custom arrow)
59
+
60
+ .l-ui-search__inline Inline search form layout
61
+
62
+ .l-ui-container--checkbox Checkbox container
63
+ .l-ui-radio__group Radio button group
64
+ .l-ui-radio__item Radio item wrapper
65
+ .l-ui-radio__input Radio input element
66
+ .l-ui-radio__label Radio label
67
+
68
+ .l-ui-switch Toggle switch container
69
+ .l-ui-switch__input Hidden checkbox input
70
+ .l-ui-switch__track Visual track element
71
+ ```
72
+
73
+ ## Tables
74
+
75
+ ```
76
+ .l-ui-table Table element
77
+ .l-ui-table__header <thead> row
78
+ .l-ui-table__header-cell <th> cell
79
+ .l-ui-table__header-cell--action Right-aligned action header
80
+ .l-ui-table__sort-link Sortable header link
81
+ .l-ui-table__sort-indicator Sort direction indicator (arrow)
82
+ .l-ui-table__body <tbody>
83
+ .l-ui-table__cell Regular <td> cell
84
+ .l-ui-table__cell--primary Bold cell (typically first column, use <th scope="row">)
85
+ .l-ui-table__cell--action Right-aligned action cell
86
+ .l-ui-table__action--danger Danger action link
87
+ .l-ui-container--table Overflow wrapper for responsive tables
88
+ ```
89
+
90
+ WCAG 2.2 AA table pattern:
91
+
92
+ ```html
93
+ <div class="l-ui-container--table">
94
+ <table class="l-ui-table">
95
+ <caption>Users</caption>
96
+ <thead class="l-ui-table__header">
97
+ <tr>
98
+ <th scope="col" class="l-ui-table__header-cell">Name</th>
99
+ <th scope="col" class="l-ui-table__header-cell">Email</th>
100
+ <th scope="col" class="l-ui-table__header-cell--action">Actions</th>
101
+ </tr>
102
+ </thead>
103
+ <tbody class="l-ui-table__body">
104
+ <tr>
105
+ <th scope="row" class="l-ui-table__cell--primary">Alice</th>
106
+ <td class="l-ui-table__cell">alice@example.com</td>
107
+ <td class="l-ui-table__cell--action">
108
+ <a href="/users/1/edit">Edit</a>
109
+ </td>
110
+ </tr>
111
+ </tbody>
112
+ </table>
113
+ </div>
114
+ ```
115
+
116
+ ## Notices
117
+
118
+ ```
119
+ .l-ui-notice--success Green success message
120
+ .l-ui-notice--warning Yellow warning message
121
+ .l-ui-notice--error Red error message
122
+ ```
123
+
124
+ ## Badges
125
+
126
+ ```
127
+ .l-ui-badge Base badge
128
+ .l-ui-badge--rounded Pill shape
129
+ .l-ui-badge--default Grey
130
+ .l-ui-badge--success Green
131
+ .l-ui-badge--warning Yellow
132
+ .l-ui-badge--danger Red
133
+ ```
134
+
135
+ ## Tabs
136
+
137
+ ```
138
+ .l-ui-tabs__list Tab list container (role="tablist")
139
+ .l-ui-tabs__tab Tab button
140
+ .l-ui-tabs__tab--active Active tab with accent border
141
+ .l-ui-tabs__panel Tab panel content
142
+ ```
143
+
144
+ ## Modal
145
+
146
+ ```
147
+ .l-ui-modal <dialog> element
148
+ .l-ui-modal__header Modal header
149
+ .l-ui-modal__body Scrollable modal content
150
+ ```
151
+
152
+ ## Breadcrumbs
153
+
154
+ ```
155
+ .l-ui-breadcrumbs <nav> container
156
+ .l-ui-breadcrumbs__list <ol> list
157
+ .l-ui-breadcrumbs__item <li> item
158
+ .l-ui-breadcrumbs__link Breadcrumb link
159
+ ```
160
+
161
+ ## Pagination
162
+
163
+ ```
164
+ .l-ui-pagination Pagination container
165
+ .l-ui-pagination__item Page link or span
166
+ .l-ui-pagination__item--active Current page
167
+ .l-ui-pagination__item--disabled Disabled navigation
168
+ .l-ui-pagination__gap Gap indicator (...)
169
+ ```
170
+
171
+ ## Navigation
172
+
173
+ ```
174
+ .l-ui-container--navigation Sidebar container
175
+ .l-ui-container--navigation.open Visible sidebar
176
+ .l-ui-backdrop--navigation Overlay backdrop
177
+ .l-ui-backdrop--navigation.open Visible backdrop
178
+ .l-ui-navigation Nav flexbox
179
+ .l-ui-navigation__links Nav links list
180
+ .l-ui-navigation__item Nav item
181
+ .l-ui-navigation__item--active Active nav item (with arrow)
182
+ .l-ui-navigation__secondary Nested nav list
183
+ .l-ui-navigation__user User info section
184
+ .l-ui-navigation__user-name User name text
185
+ .l-ui-navigation__user-email User email text
186
+ ```
187
+
188
+ ## Header
189
+
190
+ ```
191
+ .l-ui-container--header Fixed header container
192
+ .l-ui-header Header flexbox
193
+ .l-ui-header__icon Header icon (responsive)
194
+ .l-ui-header__icon--light Light theme icon
195
+ .l-ui-header__icon--dark Dark theme icon
196
+ .l-ui-header__logo Header logo (responsive)
197
+ .l-ui-header__logo--light Light theme logo
198
+ .l-ui-header__logo--dark Dark theme logo
199
+ .l-ui-theme-toggle Theme toggle button
200
+ .l-ui-theme-toggle__icon--light Sun icon (shown in dark mode)
201
+ .l-ui-theme-toggle__icon--dark Moon icon (shown in light mode)
202
+ ```
203
+
204
+ ## Panel
205
+
206
+ ```
207
+ .l-ui-container--panel Side panel container
208
+ .l-ui-container--panel.open Visible panel
209
+ .l-ui-panel Panel flexbox
210
+ .l-ui-panel__button Floating action button
211
+ .l-ui-panel__button--dragging During drag
212
+ .l-ui-panel__button--snapping Snapping to edge
213
+ .l-ui-panel__icon--light Panel button icon (light)
214
+ .l-ui-panel__icon--dark Panel button icon (dark)
215
+ .l-ui-panel__resize-handle Desktop resize handle
216
+ .l-ui-panel__header Panel header
217
+ .l-ui-panel__header-heading Panel title
218
+ .l-ui-panel__body Scrollable panel content
219
+ .l-ui-panel__input Panel input area (footer)
220
+ ```
221
+
222
+ ## Conversation
223
+
224
+ ```
225
+ .l-ui-conversation Conversation wrapper
226
+ .l-ui-conversation__messages Scrollable messages area
227
+ .l-ui-conversation__composer Message input area
228
+ .l-ui-conversation__composer-input Textarea
229
+ .l-ui-conversation__separator Date separator
230
+
231
+ .l-ui-message Message wrapper
232
+ .l-ui-message--sent Sent message (right-aligned)
233
+ .l-ui-message__avatar User avatar
234
+ .l-ui-message__bubble Message bubble
235
+ .l-ui-message__author Author name
236
+ .l-ui-message__body Message content
237
+ .l-ui-message__footer Metadata footer
238
+ .l-ui-message__timestamp Timestamp
239
+ ```
240
+
241
+ ## Markdown
242
+
243
+ ```
244
+ .l-ui-markdown Markdown content wrapper (styles h1-h6, p, code, pre, lists, tables, blockquotes, hr)
245
+ ```
246
+
247
+ ## Icon sizes
248
+
249
+ ```
250
+ .l-ui-icon--sm 20px (5x5)
251
+ .l-ui-icon--md 24px (6x6)
252
+ .l-ui-icon--lg 28px (7x7)
253
+ .l-ui-icon--xl 32px (8x8)
254
+ ```
255
+
256
+ ## Utility classes
257
+
258
+ ```
259
+ .l-ui-utility--mt-0 through --mt-8 Margin top (fixed scale)
260
+ .l-ui-utility--mt-sm/md/lg/xl/2xl Responsive margin top
261
+ .l-ui-utility--mb-0 Margin bottom zero
262
+ .l-ui-sr-only Visually hidden, screen reader only
263
+ .l-ui-skip-link Accessibility skip link
264
+ .l-ui-list Styled list
265
+ .l-ui-container--grid 1-col mobile, 2-col desktop grid
266
+ .l-ui-container--spread Flex row with space-between
267
+ .l-ui-container--pagy Pagination wrapper
268
+ .l-ui-scroll-lock Prevent body scroll (mobile panels/modals)
269
+ ```
270
+
271
+ ## Theming tokens
272
+
273
+ All colour values are space-separated HSL channels (e.g. `220 80% 55%`). Override after importing the engine CSS.
274
+
275
+ ```
276
+ --accent Primary action colour
277
+ --accent-foreground Text on accent backgrounds
278
+ --background Page background
279
+ --foreground Primary text colour
280
+ --foreground-muted Secondary/muted text
281
+ --border Default border colour
282
+ --border-control Form control border
283
+ --ring Focus ring colour
284
+ --surface Card/surface background
285
+ --surface-active Active/selected surface
286
+ --danger Danger/error colour
287
+ --danger-light Light danger background
288
+ --danger-text Danger text colour
289
+ --success-bg Success background
290
+ --success-text Success text
291
+ --switch-track-checked Checked switch track
292
+ --warning-bg Warning background
293
+ --warning-text Warning text
294
+ --error-bg Error background
295
+ --error-text Error text
296
+ --backdrop Backdrop overlay colour
297
+ --header-height Header height (default 63px)
298
+ ```