@keenmate/pure-admin-core 2.3.6 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +23 -29
  2. package/dist/css/main.css +68 -148
  3. package/package.json +1 -5
  4. package/snippets/AUDIT.md +94 -0
  5. package/snippets/alerts.html +264 -89
  6. package/snippets/badges.html +193 -61
  7. package/snippets/buttons.html +178 -0
  8. package/snippets/callouts.html +210 -129
  9. package/snippets/cards.html +383 -200
  10. package/snippets/checkbox-lists.html +199 -65
  11. package/snippets/code.html +55 -11
  12. package/snippets/command-palette.html +401 -111
  13. package/snippets/comparison.html +144 -93
  14. package/snippets/customization.html +311 -104
  15. package/snippets/data-display.html +584 -0
  16. package/snippets/detail-panel.html +470 -138
  17. package/snippets/filter-card.html +246 -0
  18. package/snippets/forms.html +408 -308
  19. package/snippets/grid.html +253 -141
  20. package/snippets/layout.html +379 -480
  21. package/snippets/lists.html +144 -47
  22. package/snippets/loaders.html +64 -39
  23. package/snippets/manifest.json +330 -280
  24. package/snippets/modal-dialogs.html +137 -64
  25. package/snippets/modals.html +221 -151
  26. package/snippets/notifications.html +285 -0
  27. package/snippets/popconfirm.html +213 -19
  28. package/snippets/profile.html +290 -330
  29. package/snippets/statistics.html +247 -0
  30. package/snippets/tables.html +359 -150
  31. package/snippets/tabs.html +129 -45
  32. package/snippets/timeline.html +123 -56
  33. package/snippets/toasts.html +179 -31
  34. package/snippets/tooltips.html +199 -81
  35. package/snippets/typography.html +183 -58
  36. package/snippets/utilities.html +511 -415
  37. package/snippets/virtual-scroll.html +201 -75
  38. package/snippets/web-daterangepicker.html +369 -189
  39. package/snippets/web-multiselect.html +360 -124
  40. package/src/scss/core-components/_alerts.scss +51 -12
  41. package/src/scss/core-components/_pagers.scss +1 -1
  42. package/src/scss/core-components/_popconfirm.scss +35 -13
  43. package/src/scss/core-components/_profile.scss +18 -8
  44. package/src/scss/core-components/_statistics.scss +12 -12
  45. package/src/scss/core-components/_tables.scss +2 -134
  46. package/src/scss/variables/_components.scss +17 -2
  47. package/scripts/download-themes.js +0 -351
@@ -32,19 +32,19 @@
32
32
 
33
33
  <!-- BADGE SIZES -->
34
34
 
35
- <!-- Extra Small Badge -->
35
+ <!-- Extra Small Badge (10px) -->
36
36
  <span class="pa-badge pa-badge--primary pa-badge--xs">XS</span>
37
37
 
38
- <!-- Small Badge -->
38
+ <!-- Small Badge (12px) -->
39
39
  <span class="pa-badge pa-badge--primary pa-badge--sm">Small</span>
40
40
 
41
- <!-- Default Badge -->
41
+ <!-- Default Badge (12px) -->
42
42
  <span class="pa-badge pa-badge--primary">Default</span>
43
43
 
44
- <!-- Large Badge -->
44
+ <!-- Large Badge (14px) -->
45
45
  <span class="pa-badge pa-badge--primary pa-badge--lg">Large</span>
46
46
 
47
- <!-- Extra Large Badge -->
47
+ <!-- Extra Large Badge (16px) -->
48
48
  <span class="pa-badge pa-badge--primary pa-badge--xl">XL</span>
49
49
 
50
50
 
@@ -59,7 +59,7 @@
59
59
 
60
60
  <!-- BADGES WITH ICONS -->
61
61
 
62
- <!-- Badge with Icon -->
62
+ <!-- Badge with Icon — __icon gets font-size-2xs (10px) so it stays proportional -->
63
63
  <span class="pa-badge pa-badge--success">
64
64
  <span class="pa-badge__icon">✓</span>
65
65
  Verified
@@ -72,8 +72,13 @@
72
72
  </span>
73
73
 
74
74
 
75
- <!-- FIXED WIDTH BADGES -->
76
- <!-- Use wr-*/minwr-*/maxwr-* utilities with text-truncate for ellipsis -->
75
+ <!--
76
+ FIXED WIDTH BADGES
77
+ minwr-*/maxwr-*/wr-* are utility classes (not part of the badge component)
78
+ that set min-/max-/width in 1rem increments. Combine with text-truncate for
79
+ clean ellipsis. Adding text-truncate to a pa-badge auto-switches it from
80
+ inline-flex to inline-block because ellipsis doesn't work on flex containers.
81
+ -->
77
82
 
78
83
  <!-- Fixed Width 8rem -->
79
84
  <span class="pa-badge pa-badge--primary minwr-8 maxwr-8 text-truncate">Status</span>
@@ -83,39 +88,93 @@
83
88
  <span class="pa-badge pa-badge--info minwr-15 maxwr-15 text-truncate">Very Long Badge Text That Needs Truncation</span>
84
89
  </span>
85
90
 
86
- <!-- Fixed Width with Start-Side Ellipsis (for paths, breadcrumbs) -->
91
+ <!--
92
+ --ellipsis-start: truncates from the start instead of the end. Uses
93
+ direction: rtl + text-align: left under the hood so the visible tail is
94
+ what matters (good for file paths, breadcrumbs, hierarchies where the
95
+ rightmost segment is the key info). In RTL document mode the override
96
+ reverses so the user sees the same behaviour.
97
+ -->
87
98
  <span class="pa-tooltip pa-tooltip--bottom pa-tooltip--multiline" data-tooltip="Settings > User Preferences > Notifications > Email">
88
99
  <span class="pa-badge pa-badge--secondary minwr-10 maxwr-10 text-truncate pa-badge--ellipsis-start">Settings > User Preferences > Notifications > Email</span>
89
100
  </span>
90
101
 
91
102
 
92
- <!-- COMPOSITE BADGES -->
103
+ <!--
104
+ COMPOSITE BADGES — three-section inline structure: [icon][label][button].
105
+ Use for notification pills, status + count, interactive chips.
106
+ -->
93
107
 
94
- <!-- Standard Composite Badge -->
108
+ <!-- Standard all sections follow the variant colour -->
95
109
  <div class="pa-composite-badge pa-composite-badge--primary">
96
110
  <span class="pa-composite-badge__icon">🔔</span>
97
111
  <span class="pa-composite-badge__label">Notifications</span>
98
112
  <span class="pa-composite-badge__button">5</span>
99
113
  </div>
100
114
 
101
- <!-- Success Composite Badge -->
102
115
  <div class="pa-composite-badge pa-composite-badge--success">
103
116
  <span class="pa-composite-badge__icon">✓</span>
104
117
  <span class="pa-composite-badge__label">Completed</span>
105
118
  <span class="pa-composite-badge__button">12</span>
106
119
  </div>
107
120
 
108
- <!-- Danger Composite Badge -->
109
121
  <div class="pa-composite-badge pa-composite-badge--danger">
110
122
  <span class="pa-composite-badge__icon">⚠</span>
111
123
  <span class="pa-composite-badge__label">Errors</span>
112
124
  <span class="pa-composite-badge__button">3</span>
113
125
  </div>
114
126
 
127
+ <div class="pa-composite-badge pa-composite-badge--warning">
128
+ <span class="pa-composite-badge__icon">!</span>
129
+ <span class="pa-composite-badge__label">Pending</span>
130
+ <span class="pa-composite-badge__button">7</span>
131
+ </div>
132
+
133
+ <div class="pa-composite-badge pa-composite-badge--info">
134
+ <span class="pa-composite-badge__icon">ℹ</span>
135
+ <span class="pa-composite-badge__label">Updates</span>
136
+ <span class="pa-composite-badge__button">2</span>
137
+ </div>
138
+
139
+ <!-- Pattern: pa-composite-badge--{primary|secondary|success|danger|warning|info|light|dark} -->
140
+
141
+ <!--
142
+ MIXED COLOUR COMPOSITES
143
+ --label-* and --btn-* override only that section. Combine with a base
144
+ variant (or skip it) to build badges like "success icon + neutral label
145
+ + danger dismiss button".
146
+ -->
147
+
148
+ <!-- Primary icon, info-tinted label, danger dismiss button -->
149
+ <div class="pa-composite-badge pa-composite-badge--primary pa-composite-badge--label-info pa-composite-badge--btn-primary">
150
+ <span class="pa-composite-badge__icon">📧</span>
151
+ <span class="pa-composite-badge__label">New messages</span>
152
+ <span class="pa-composite-badge__button">×</span>
153
+ </div>
154
+
155
+ <!-- Success icon, secondary-grey label, success button -->
156
+ <div class="pa-composite-badge pa-composite-badge--success pa-composite-badge--label-secondary pa-composite-badge--btn-success">
157
+ <span class="pa-composite-badge__icon">✓</span>
158
+ <span class="pa-composite-badge__label">CI passed</span>
159
+ <span class="pa-composite-badge__button">9</span>
160
+ </div>
161
+
162
+ <!-- Patterns:
163
+ pa-composite-badge--label-{primary|secondary|success|danger|warning|info|light|dark}
164
+ pa-composite-badge--btn-{primary|secondary|success|warning|info|light|dark}
165
+ Note: --btn-danger is NOT defined (base __button already renders
166
+ danger-coloured by default, so it would be a no-op).
167
+ -->
168
+
115
169
 
116
170
  <!-- BADGE GROUP -->
117
171
 
118
- <!-- Badge Group (shows first 5, then "more") -->
172
+ <!--
173
+ .pa-badge-group hides any badges past the 6th except the last one, which
174
+ stays visible. Common pattern: put 5 real badges + a "N more" summary
175
+ badge at the end; extras between them get hidden but render in DOM so
176
+ filtering/sorting still works.
177
+ -->
119
178
  <div class="pa-badge-group">
120
179
  <span class="pa-badge pa-badge--primary">JavaScript</span>
121
180
  <span class="pa-badge pa-badge--info">React</span>
@@ -128,7 +187,8 @@
128
187
  </span>
129
188
  </div>
130
189
 
131
- <!-- Badge Group - Show All -->
190
+ <!-- --show-all disables the visible limit. Useful when the parent
191
+ component expands (e.g. a "show all tags" toggle). -->
132
192
  <div class="pa-badge-group pa-badge-group--show-all">
133
193
  <span class="pa-badge pa-badge--primary">Tag 1</span>
134
194
  <span class="pa-badge pa-badge--info">Tag 2</span>
@@ -139,7 +199,9 @@
139
199
 
140
200
  <!-- ================================
141
201
  LABELS
142
- Lightweight inline indicators
202
+ Lightweight inline indicators — tinted background + border in the
203
+ variant colour. Font-weight is medium (badges are not weighted).
204
+ Labels have the same size scale as badges but no --light / --dark.
143
205
  ================================ -->
144
206
 
145
207
  <!-- Basic Labels -->
@@ -150,13 +212,17 @@
150
212
  <span class="pa-label pa-label--warning">Warning</span>
151
213
  <span class="pa-label pa-label--info">Info</span>
152
214
 
153
- <!-- Labels are lighter-weight than badges -->
154
- <!-- Use for inline status indicators, tags, categories -->
155
-
156
- <!-- Label Sizes -->
215
+ <!-- Label Sizes (same scale as badges: xs / sm / default / lg / xl) -->
216
+ <span class="pa-label pa-label--primary pa-label--xs">XS</span>
157
217
  <span class="pa-label pa-label--primary pa-label--sm">Small</span>
158
218
  <span class="pa-label pa-label--primary">Default</span>
159
219
  <span class="pa-label pa-label--primary pa-label--lg">Large</span>
220
+ <span class="pa-label pa-label--primary pa-label--xl">XL</span>
221
+
222
+ <!-- Outline Labels — transparent background, coloured border + text -->
223
+ <span class="pa-label pa-label--primary pa-label--outline">Primary outline</span>
224
+ <span class="pa-label pa-label--success pa-label--outline">Success outline</span>
225
+ <span class="pa-label pa-label--danger pa-label--outline">Danger outline</span>
160
226
 
161
227
 
162
228
  <!-- ================================
@@ -165,49 +231,115 @@
165
231
 
166
232
  <!--
167
233
  BADGE CLASSES:
168
- - .pa-badge: Base badge class
169
-
170
- VARIANTS (colors):
171
- - .pa-badge--primary: Blue badge
172
- - .pa-badge--secondary: Gray badge
173
- - .pa-badge--success: Green badge
174
- - .pa-badge--danger: Red badge
175
- - .pa-badge--warning: Yellow/orange badge
176
- - .pa-badge--info: Cyan badge
177
- - .pa-badge--light: Light gray badge
178
- - .pa-badge--dark: Dark badge
234
+ - .pa-badge: Base badge (inline-flex, rounded, variant-agnostic)
235
+
236
+ VARIANTS:
237
+ - .pa-badge--primary / --secondary / --success / --warning / --danger
238
+ / --info / --light / --dark (all 8 btn-style colour pairs)
179
239
 
180
240
  SIZES:
181
- - .pa-badge--xs: Extra small (10px font)
182
- - .pa-badge--sm: Small (12px font)
183
- - (default): Standard size (12px font, standard padding)
184
- - .pa-badge--lg: Large (14px font)
185
- - .pa-badge--xl: Extra large (16px font)
186
-
187
- MODIFIERS:
188
- - .pa-badge--pill: Rounded pill shape
189
- - .pa-badge--ellipsis-start: Truncate from start instead of end
190
- - Use utilities for fixed width: maxwr-* text-truncate
191
-
192
- ELEMENTS:
193
- - .pa-badge__icon: Icon container inside badge
194
-
195
- COMPOSITE BADGE:
196
- - .pa-composite-badge: Three-part badge container
197
- - .pa-composite-badge--{variant}: Color variants
198
- - .pa-composite-badge__icon: Icon section
199
- - .pa-composite-badge__label: Label/text section
200
- - .pa-composite-badge__button: Button/count section
201
- - .pa-composite-badge--label-{variant}: Label section color override
202
- - .pa-composite-badge--btn-{variant}: Button section color override
241
+ - .pa-badge--xs 10px / tight padding
242
+ - .pa-badge--sm 12px
243
+ - (default) 12px / normal padding
244
+ - .pa-badge--lg 14px
245
+ - .pa-badge--xl 16px / wide padding
246
+
247
+ SHAPE:
248
+ - .pa-badge--pill border-radius: 50rem (full round ends)
249
+
250
+ ELLIPSIS / TRUNCATION:
251
+ - .pa-badge--ellipsis-start truncates from the start instead of end.
252
+ Uses direction: rtl internally; RTL
253
+ document mode flips it back automatically.
254
+ Best for paths / breadcrumbs where the end
255
+ is the informative part.
256
+ - .text-truncate ellipsis from the end. Adding this to a
257
+ pa-badge auto-switches the badge from
258
+ inline-flex to inline-block (ellipsis
259
+ doesn't work on flex containers).
260
+ - minwr-{n} / maxwr-{n} / wr-{n} separate width utilities in 1rem
261
+ increments; combine with text-truncate.
262
+
263
+ ELEMENT:
264
+ - .pa-badge__icon inline icon — font-size-2xs (10px) so it stays
265
+ proportional. Any child element works since the
266
+ badge is flex + gap.
267
+
268
+ AUTOMATIC BEHAVIOURS:
269
+ - .pa-badge.text-truncate flips display to inline-block (see above).
270
+
271
+ COMPOSITE BADGE — three-section container:
272
+ .pa-composite-badge
273
+ .pa-composite-badge__icon fixed-width left section
274
+ .pa-composite-badge__label flexible middle (clickable, hover state)
275
+ .pa-composite-badge__button fixed-width right section (default
276
+ renders danger-coloured for dismiss)
277
+
278
+ All-sections variants:
279
+ .pa-composite-badge--{primary | secondary | success | danger | warning
280
+ | info | light | dark}
281
+
282
+ Section overrides (compose with the base variant or use alone):
283
+ .pa-composite-badge--label-{primary | secondary | success | danger
284
+ | warning | info | light | dark}
285
+ .pa-composite-badge--btn-{primary | secondary | success | warning
286
+ | info | light | dark}
287
+ (No --btn-danger — base __button is already danger-coloured, so it
288
+ would be a no-op. File a framework issue if you need explicit parity.)
203
289
 
204
290
  BADGE GROUP:
205
- - .pa-badge-group: Container for multiple badges
206
- - .pa-badge-group--show-all: Show all badges (disable limit)
207
-
208
- LABELS (lightweight alternative to badges):
209
- - .pa-label: Base label class
210
- - .pa-label--primary, --secondary, --success, --danger, --warning, --info: Color variants
211
- - .pa-label--sm: Small size
212
- - .pa-label--lg: Large size
291
+ - .pa-badge-group Flex wrap container; hides children past
292
+ $badge-group-visible-limit (default 6) EXCEPT
293
+ the last one, which always shows (for "+N
294
+ more" indicators). Hidden badges stay in DOM.
295
+ - .pa-badge-group--show-all Disables the limit; all children visible.
296
+
297
+ LABEL CLASSES:
298
+ - .pa-label Lighter tag-style indicator — tinted bg +
299
+ coloured border, medium weight.
300
+
301
+ LABEL VARIANTS:
302
+ - .pa-label--primary / --secondary / --success / --danger / --warning / --info
303
+ (No --light / --dark, unlike badges.)
304
+
305
+ LABEL SIZES (same scale as badges):
306
+ - .pa-label--xs / --sm / (default) / --lg / --xl
307
+
308
+ LABEL MODIFIER:
309
+ - .pa-label--outline Transparent background; on hover fills with
310
+ the tinted colour. Composes with colour
311
+ variants: .pa-label--danger.pa-label--outline.
312
+
313
+ BADGE vs LABEL:
314
+ - Badge filled tint + border matching bg; nowrap; heavier. Good for
315
+ counts, status chips, categorical tags in tables.
316
+ - Label lighter tint + visible border; medium weight; $line-height-tight.
317
+ Good for inline content tags, category chips in prose.
318
+
319
+ STRUCTURE PATTERNS:
320
+
321
+ Badge with icon:
322
+ <span class="pa-badge pa-badge--success">
323
+ <span class="pa-badge__icon">✓</span> Verified
324
+ </span>
325
+
326
+ Fixed-width badge with truncation:
327
+ <span class="pa-badge pa-badge--primary minwr-12 maxwr-12 text-truncate">…</span>
328
+
329
+ Composite badge with mixed section colours:
330
+ <div class="pa-composite-badge pa-composite-badge--primary pa-composite-badge--label-info">
331
+ <span class="pa-composite-badge__icon">📧</span>
332
+ <span class="pa-composite-badge__label">…</span>
333
+ <span class="pa-composite-badge__button">×</span>
334
+ </div>
335
+
336
+ Badge group with "+N more" tail:
337
+ <div class="pa-badge-group">
338
+ <span class="pa-badge pa-badge--primary">…</span>
339
+ … (up to 5)
340
+ <span class="pa-badge pa-badge--secondary">+N more</span>
341
+ </div>
342
+
343
+ Outline label:
344
+ <span class="pa-label pa-label--success pa-label--outline">Active</span>
213
345
  -->
@@ -68,6 +68,25 @@
68
68
  <!-- Outline Info -->
69
69
  <button class="pa-btn pa-btn--outline-info">Info</button>
70
70
 
71
+ <!-- Note: no pa-btn--outline-light or pa-btn--outline-dark — SCSS only
72
+ defines outline variants for primary/secondary/success/warning/
73
+ danger/info. -->
74
+
75
+
76
+ <!-- THEME COLOR SLOT BUTTONS (color-1 through color-9) -->
77
+
78
+ <!-- Filled theme color slot -->
79
+ <button class="pa-btn pa-btn--color-1">Color 1</button>
80
+ <button class="pa-btn pa-btn--color-3">Color 3</button>
81
+ <button class="pa-btn pa-btn--color-5">Color 5</button>
82
+
83
+ <!-- Outline theme color slot -->
84
+ <button class="pa-btn pa-btn--outline-color-1">Outline 1</button>
85
+ <button class="pa-btn pa-btn--outline-color-3">Outline 3</button>
86
+
87
+ <!-- Pattern: pa-btn--color-{1..9} (filled) and pa-btn--outline-color-{1..9}
88
+ Colour + text colour both track the active theme's --pa-color-N slot. -->
89
+
71
90
 
72
91
  <!-- BUTTON STATES -->
73
92
 
@@ -373,3 +392,162 @@
373
392
  <button class="pa-btn pa-btn--primary pa-btn--ripple" data-loading-demo data-ripple>
374
393
  Save Changes
375
394
  </button>
395
+
396
+ <!--
397
+ data-ripple / data-loading-demo are DEMO-wiring attributes picked up by
398
+ external JS in the demo app — they aren't framework class hooks. The
399
+ framework's only ripple contract is pa-btn--ripple (the CSS animation)
400
+ plus pa-btn--ripple-active (set by your own JS during the click). The
401
+ data-* attributes just tell the demo's script to call `.classList.add`
402
+ with that class at the right time.
403
+ -->
404
+
405
+
406
+ <!-- ================================
407
+ COMPONENT REFERENCE
408
+ ================================ -->
409
+
410
+ <!--
411
+ BUTTON CLASSES:
412
+ - .pa-btn Base button; inline-block, $btn-height-base,
413
+ centred text, $font-size-sm, medium weight.
414
+
415
+ COLOUR VARIANTS (solid):
416
+ - .pa-btn--primary / --secondary / --success / --warning / --danger
417
+ / --info / --light / --dark
418
+
419
+ OUTLINE VARIANTS (transparent bg, fills on hover):
420
+ - .pa-btn--outline-primary / --outline-secondary / --outline-success
421
+ / --outline-warning / --outline-danger / --outline-info
422
+ (No --outline-light / --outline-dark — SCSS doesn't define them.)
423
+
424
+ THEME COLOUR SLOT VARIANTS (1-9):
425
+ - .pa-btn--color-{1..9} filled theme slot
426
+ - .pa-btn--outline-color-{1..9} outline theme slot
427
+
428
+ SIZES:
429
+ - .pa-btn--xs / --sm / (default) / --lg / --xl
430
+ Each size adjusts height, padding, and font-size from the $btn-*
431
+ scale. Size classes compose with every variant.
432
+
433
+ STATES:
434
+ - :disabled attribute 50% opacity, not-allowed cursor, no transform
435
+ (opt-in disable state — no class needed)
436
+ - .pa-btn--loading hides text (text-fill transparent) and
437
+ positions a .pa-btn__spinner centred in the
438
+ button; keep the label text so the width
439
+ stays the same during load.
440
+
441
+ LAYOUT MODIFIERS:
442
+ - .pa-btn--block width: 100%; display: block (full-width CTA)
443
+ - .pa-btn--icon-only square aspect; padding: 0; flex-centred icon
444
+ (size-aware — composes with --xs/--sm/--lg/--xl
445
+ to set the square dimension)
446
+
447
+ CONTENT ALIGNMENT (affects justify-content inside the button):
448
+ - .pa-btn--align-start flush-start (default behaviour)
449
+ - .pa-btn--align-end flush-end
450
+ - .pa-btn--align-center centred, __label flexes to fill
451
+ - .pa-btn--align-justify space-between (icon on one side, text on the other)
452
+
453
+ EFFECTS:
454
+ - .pa-btn--ripple enables the CSS ripple base styles
455
+ - .pa-btn--ripple-active added/removed by your own JS to trigger the
456
+ ripple expansion (see note above about
457
+ data-ripple which is a demo-wiring attribute)
458
+
459
+ ELEMENTS:
460
+ - .pa-btn__icon icon container. Gets margin-inline-end by default;
461
+ on :last-child (icon AFTER text) the margin flips to
462
+ inline-start so spacing reads correctly in both
463
+ positions.
464
+ - .pa-btn__label text wrapper used by --align-center to flex-fill
465
+ and centre its text within the button.
466
+ - .pa-btn__spinner only used inside .pa-btn--loading; CSS handles
467
+ positioning + animation, no extra classes needed.
468
+
469
+ IMPLICIT BEHAVIOUR:
470
+ - Any .pa-btn containing a .pa-btn__icon child auto-switches to
471
+ inline-flex, align-items: center, gap: $spacing-sm, and
472
+ text-align: start (logical — flips in RTL). You don't need to add
473
+ --align-start manually for the common icon-then-text pattern.
474
+
475
+ BUTTON GROUP (.pa-btn-group):
476
+ - default inline-flex, wrap, $btn-group-gap, aligned centre
477
+ - --vertical flex-column; aligns to flex-start by default
478
+ - --vertical --center vertical + centre cross-axis alignment
479
+ - --vertical --end vertical + flex-end alignment
480
+ - --vertical --stretch vertical + stretch (all children go 100% width)
481
+ - --nowrap prevents wrapping on overflow
482
+ - --{sm|md|lg|xl}-vertical responsive: column at that breakpoint
483
+ - --{sm|md|lg|xl}-horizontal responsive: row at that breakpoint
484
+ - (Use .gap-{n} utilities to override the default gap size.)
485
+
486
+ SPLIT BUTTON (.pa-btn-split):
487
+ Structure:
488
+ .pa-btn-split
489
+ .pa-btn (primary action)
490
+ .pa-btn.pa-btn-split__toggle
491
+ .pa-btn-split__chevron (optional — rotates on --open)
492
+ .pa-btn-split__menu
493
+ .pa-btn-split__menu-inner
494
+ .pa-btn-split__item
495
+ .pa-btn-split__item--danger
496
+
497
+ State:
498
+ - .pa-btn-split--open set by JS; adds rotation to __chevron
499
+ - .pa-btn-split__menu--open set by JS; displays the menu
500
+
501
+ Attributes:
502
+ - data-placement="top-end" consumed by the demo's split-button JS
503
+ (Floating UI placement value)
504
+
505
+ Item row (for menu items with a trailing action button):
506
+ .pa-btn-split__item-row
507
+ .pa-btn-split__item (flex: 1)
508
+ .pa-btn (flex-shrink: 0, end-margin)
509
+ .pa-btn-split__item-icon optional leading icon
510
+
511
+ Requires JS: the dropdown won't open/close or reposition without a
512
+ script that toggles --open classes and positions __menu. The demo
513
+ uses demo/js/split-button.js — snippet authors will need to wire
514
+ their own equivalent.
515
+
516
+ STRUCTURE PATTERNS:
517
+
518
+ Icon-then-text button (most common):
519
+ <button class="pa-btn pa-btn--primary">
520
+ <span class="pa-btn__icon"><i class="fa-solid fa-floppy-disk"></i></span>
521
+ Save
522
+ </button>
523
+
524
+ Icon-only at XS for tables:
525
+ <button class="pa-btn pa-btn--danger pa-btn--icon-only pa-btn--xs" title="Delete">
526
+ <i class="fa-solid fa-trash"></i>
527
+ </button>
528
+
529
+ Loading button (preserves width):
530
+ <button class="pa-btn pa-btn--primary pa-btn--loading">
531
+ <span class="pa-btn__spinner"></span>
532
+ Saving…
533
+ </button>
534
+
535
+ Fixed-width button with truncation:
536
+ <button class="pa-btn pa-btn--primary minwr-10 maxwr-10">
537
+ <span class="pa-btn__icon">✓</span>
538
+ <span class="text-truncate">Save All Changes</span>
539
+ </button>
540
+
541
+ Full-width vertical action stack:
542
+ <div class="pa-btn-group pa-btn-group--vertical pa-btn-group--stretch">
543
+ <button class="pa-btn pa-btn--primary">Save</button>
544
+ <button class="pa-btn pa-btn--secondary">Cancel</button>
545
+ </div>
546
+
547
+ Responsive direction (row on mobile, column at md+):
548
+ <div class="pa-btn-group pa-btn-group--md-vertical">
549
+ <button class="pa-btn pa-btn--primary">Save</button>
550
+ <button class="pa-btn pa-btn--secondary">Cancel</button>
551
+ </div>
552
+ -->
553
+