@keenmate/pure-admin-core 2.4.0 → 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 (44) hide show
  1. package/README.md +11 -6
  2. package/dist/css/main.css +47 -130
  3. package/package.json +1 -1
  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/_tables.scss +2 -134
  44. package/src/scss/variables/_components.scss +17 -2
@@ -4,8 +4,6 @@
4
4
  ================================ -->
5
5
 
6
6
  <!-- BASIC CARD -->
7
-
8
- <!-- Simple Card -->
9
7
  <div class="pa-card">
10
8
  <div class="pa-card__body">
11
9
  This is a simple card with just a body.
@@ -14,8 +12,6 @@
14
12
 
15
13
 
16
14
  <!-- CARD WITH HEADER -->
17
-
18
- <!-- Card with Header -->
19
15
  <div class="pa-card">
20
16
  <div class="pa-card__header">
21
17
  <h3>Card Title</h3>
@@ -27,8 +23,6 @@
27
23
 
28
24
 
29
25
  <!-- CARD WITH FOOTER -->
30
-
31
- <!-- Card with Footer -->
32
26
  <div class="pa-card">
33
27
  <div class="pa-card__body">
34
28
  Card content goes here.
@@ -39,9 +33,7 @@
39
33
  </div>
40
34
 
41
35
 
42
- <!-- COMPLETE CARD -->
43
-
44
- <!-- Card with Header, Body, and Footer -->
36
+ <!-- COMPLETE CARD (header + body + footer) -->
45
37
  <div class="pa-card">
46
38
  <div class="pa-card__header">
47
39
  <h3>Complete Card</h3>
@@ -56,120 +48,83 @@
56
48
  </div>
57
49
 
58
50
 
59
- <!-- CARD WITH TABS -->
51
+ <!-- ================================
52
+ THREE-PART HEADER LAYOUT
53
+ .pa-card__header is a flex row with automatic behaviour:
54
+ [title (truncates)] — [description <p> (flexes and truncates)] — [actions (fixed)]
55
+ Any h1..h6 / <p> children get ellipsis on overflow so narrow cards
56
+ never push content out of the header. Use .pa-card__header--wrap
57
+ if you'd rather have the text wrap to multiple lines instead.
58
+ ================================ -->
60
59
 
61
- <!-- Card with Tabs -->
62
60
  <div class="pa-card">
63
61
  <div class="pa-card__header">
64
- <div class="pa-card__tabs">
65
- <button class="pa-card__tab pa-card__tab--active">Overview</button>
66
- <button class="pa-card__tab">Details</button>
67
- <button class="pa-card__tab">Settings</button>
62
+ <h3>Dashboard</h3>
63
+ <p>Live metrics across every connected service — updated every 30 seconds.</p>
64
+ <div class="pa-card__actions">
65
+ <button class="pa-btn pa-btn--sm pa-btn--secondary">Refresh</button>
68
66
  </div>
69
67
  </div>
70
- <div class="pa-card__body">
71
- <p>Tab content goes here.</p>
72
- </div>
68
+ <div class="pa-card__body">Body content.</div>
73
69
  </div>
74
70
 
75
-
76
- <!-- CARD VARIANTS -->
77
-
78
- <!-- Primary Card -->
79
- <div class="pa-card pa-card--primary">
80
- <div class="pa-card__header">
81
- <h3>Primary Card</h3>
82
- </div>
83
- <div class="pa-card__body">
84
- Content here.
85
- </div>
86
- </div>
87
-
88
- <!-- Success Card -->
89
- <div class="pa-card pa-card--success">
90
- <div class="pa-card__header">
91
- <h3>Success Card</h3>
92
- </div>
93
- <div class="pa-card__body">
94
- Content here.
71
+ <!-- Wrap instead of truncate -->
72
+ <div class="pa-card">
73
+ <div class="pa-card__header pa-card__header--wrap">
74
+ <h3>Wrapping Header</h3>
75
+ <p>This description wraps to multiple lines when the header gets narrow, instead of being clipped with an ellipsis.</p>
76
+ <div class="pa-card__actions">
77
+ <button class="pa-btn pa-btn--sm pa-btn--secondary">Action</button>
78
+ </div>
95
79
  </div>
80
+ <div class="pa-card__body">Body.</div>
96
81
  </div>
97
82
 
98
- <!-- Warning Card -->
99
- <div class="pa-card pa-card--warning">
100
- <div class="pa-card__header">
101
- <h3>Warning Card</h3>
102
- </div>
103
- <div class="pa-card__body">
104
- Content here.
105
- </div>
106
- </div>
107
83
 
108
- <!-- Danger Card -->
109
- <div class="pa-card pa-card--danger">
110
- <div class="pa-card__header">
111
- <h3>Danger Card</h3>
112
- </div>
113
- <div class="pa-card__body">
114
- Content here.
115
- </div>
116
- </div>
84
+ <!-- ================================
85
+ HEADER UNDERLINE MODIFIER
86
+ Puts an accent-coloured border under the heading inside the header.
87
+ Semantic variants and theme colour slots both swap the border tint.
88
+ ================================ -->
117
89
 
118
- <!-- Stat Card (Basic) -->
119
- <div class="pa-card pa-card--stat">
120
- <div class="pa-card__body">
121
- <div class="pa-stat">
122
- <div class="pa-stat__value">1,234</div>
123
- <div class="pa-stat__label">Total Users</div>
124
- </div>
90
+ <!-- Default (accent-coloured underline) -->
91
+ <div class="pa-card">
92
+ <div class="pa-card__header pa-card__header--underlined">
93
+ <h3>Section</h3>
125
94
  </div>
95
+ <div class="pa-card__body">Body content.</div>
126
96
  </div>
127
97
 
128
- <!-- Stat Card with Icon -->
129
- <div class="pa-card pa-card--stat">
130
- <div class="pa-card__body">
131
- <div class="pa-stat pa-stat--with-icon">
132
- <div class="pa-stat__icon">👥</div>
133
- <div class="pa-stat__content">
134
- <div class="pa-stat__value">1,234</div>
135
- <div class="pa-stat__label">Total Users</div>
136
- </div>
137
- </div>
98
+ <!-- Semantic colour variants -->
99
+ <div class="pa-card">
100
+ <div class="pa-card__header pa-card__header--underlined pa-card__header--underline-success">
101
+ <h3>Success underline</h3>
138
102
  </div>
103
+ <div class="pa-card__body">Body.</div>
139
104
  </div>
140
105
 
141
- <!-- Stat Card with Trend -->
142
- <div class="pa-card pa-card--stat">
143
- <div class="pa-card__body">
144
- <div class="pa-stat">
145
- <div class="pa-stat__value">$12,345</div>
146
- <div class="pa-stat__label">Revenue</div>
147
- <div class="pa-stat__trend pa-stat__trend--up">+12.5%</div>
148
- </div>
106
+ <div class="pa-card">
107
+ <div class="pa-card__header pa-card__header--underlined pa-card__header--underline-danger">
108
+ <h3>Danger underline</h3>
149
109
  </div>
110
+ <div class="pa-card__body">Body.</div>
150
111
  </div>
151
112
 
152
-
153
- <!-- CARD WITH ACTIONS IN HEADER -->
154
-
155
- <!-- Card with Header Actions -->
113
+ <!-- Theme colour slot (1..9) -->
156
114
  <div class="pa-card">
157
- <div class="pa-card__header">
158
- <h3>Card with Actions</h3>
159
- <div class="pa-btn-group">
160
- <button class="pa-btn pa-btn--sm pa-btn--secondary">Cancel</button>
161
- <button class="pa-btn pa-btn--sm pa-btn--success">Save</button>
162
- </div>
163
- </div>
164
- <div class="pa-card__body">
165
- Card content.
115
+ <div class="pa-card__header pa-card__header--underlined pa-card__header--underline-color-3">
116
+ <h3>Theme colour 3 underline</h3>
166
117
  </div>
118
+ <div class="pa-card__body">Body.</div>
167
119
  </div>
168
120
 
121
+ <!-- Patterns:
122
+ pa-card__header--underline-{success|warning|danger|info}
123
+ pa-card__header--underline-color-{1..9}
124
+ -->
169
125
 
170
- <!-- CARD WITH TITLE COMPONENTS -->
171
126
 
172
- <!-- Card with Title Icon and Text -->
127
+ <!-- CARD WITH TITLE COMPONENTS (icon + truncating text) -->
173
128
  <div class="pa-card">
174
129
  <div class="pa-card__header">
175
130
  <div class="pa-card__title">
@@ -181,35 +136,41 @@
181
136
  </div>
182
137
  </div>
183
138
  <div class="pa-card__body">
184
- Dashboard content with title icon and tools.
139
+ Use .pa-card__title when you need the title-icon combo + __actions
140
+ alignment; h3 alone works too when no icon is needed.
185
141
  </div>
186
142
  </div>
187
143
 
188
144
 
189
145
  <!-- CARD WITH METADATA -->
190
-
191
- <!-- Card with Meta Information -->
192
146
  <div class="pa-card">
193
147
  <div class="pa-card__header">
194
148
  <h3>Article Title</h3>
195
149
  <span class="pa-card__meta">Published 2 hours ago</span>
196
150
  </div>
197
- <div class="pa-card__body">
198
- Article content goes here.
151
+ <div class="pa-card__body">Article content.</div>
152
+ </div>
153
+
154
+
155
+ <!-- CARD WITH ACTIONS IN HEADER -->
156
+ <div class="pa-card">
157
+ <div class="pa-card__header">
158
+ <h3>Card with Actions</h3>
159
+ <div class="pa-btn-group">
160
+ <button class="pa-btn pa-btn--sm pa-btn--secondary">Cancel</button>
161
+ <button class="pa-btn pa-btn--sm pa-btn--success">Save</button>
162
+ </div>
199
163
  </div>
164
+ <div class="pa-card__body">Card content.</div>
200
165
  </div>
201
166
 
202
167
 
203
168
  <!-- CARD WITH FOOTER ACTIONS -->
204
-
205
- <!-- Card with Footer Actions -->
206
169
  <div class="pa-card">
207
170
  <div class="pa-card__header">
208
171
  <h3>Form Card</h3>
209
172
  </div>
210
- <div class="pa-card__body">
211
- Form content here.
212
- </div>
173
+ <div class="pa-card__body">Form content here.</div>
213
174
  <div class="pa-card__footer">
214
175
  <div></div>
215
176
  <div class="pa-card__actions">
@@ -220,9 +181,7 @@
220
181
  </div>
221
182
 
222
183
 
223
- <!-- CARD WITH NO PADDING BODY -->
224
-
225
- <!-- Card with No Padding Body (for tables) -->
184
+ <!-- CARD WITH NO-PADDING BODY (for flush tables / lists) -->
226
185
  <div class="pa-card">
227
186
  <div class="pa-card__header">
228
187
  <h3>User List</h3>
@@ -230,119 +189,253 @@
230
189
  <div class="pa-card__body pa-card__body--no-padding">
231
190
  <table class="pa-table">
232
191
  <thead>
233
- <tr>
234
- <th>Name</th>
235
- <th>Email</th>
236
- </tr>
192
+ <tr><th>Name</th><th>Email</th></tr>
237
193
  </thead>
238
194
  <tbody>
239
- <tr>
240
- <td>John Doe</td>
241
- <td>john@example.com</td>
242
- </tr>
195
+ <tr><td>John Doe</td><td>john@example.com</td></tr>
243
196
  </tbody>
244
197
  </table>
245
198
  </div>
246
199
  </div>
200
+ <!-- For most table-in-card scenarios, reach for .pa-table-card instead
201
+ — it has purpose-built header/body/footer + --scrollable modifier. -->
202
+
203
+
204
+ <!-- ================================
205
+ CARD VARIANTS — SEMANTIC COLOURS
206
+ Only 4 semantic variants exist: primary / success / warning / danger.
207
+ No --secondary / --info / --light / --dark. The header background
208
+ is filled; body stays on the default card background.
209
+ ================================ -->
210
+
211
+ <div class="pa-card pa-card--primary">
212
+ <div class="pa-card__header"><h3>Primary Card</h3></div>
213
+ <div class="pa-card__body">Body content.</div>
214
+ </div>
215
+
216
+ <div class="pa-card pa-card--success">
217
+ <div class="pa-card__header"><h3>Success Card</h3></div>
218
+ <div class="pa-card__body">Body content.</div>
219
+ </div>
220
+
221
+ <div class="pa-card pa-card--warning">
222
+ <div class="pa-card__header"><h3>Warning Card</h3></div>
223
+ <div class="pa-card__body">Body content.</div>
224
+ </div>
225
+
226
+ <div class="pa-card pa-card--danger">
227
+ <div class="pa-card__header"><h3>Danger Card</h3></div>
228
+ <div class="pa-card__body">Body content.</div>
229
+ </div>
230
+
231
+
232
+ <!-- THEME COLOUR SLOT VARIANTS (color-1 through color-9) -->
233
+
234
+ <div class="pa-card pa-card--color-1">
235
+ <div class="pa-card__header"><h3>Theme colour 1</h3></div>
236
+ <div class="pa-card__body">Body content.</div>
237
+ </div>
238
+
239
+ <div class="pa-card pa-card--color-5">
240
+ <div class="pa-card__header"><h3>Theme colour 5</h3></div>
241
+ <div class="pa-card__body">Body content.</div>
242
+ </div>
243
+
244
+ <!-- Pattern: pa-card--color-{1..9}.
245
+ Header bg = --pa-color-N, header text = --pa-color-N-text. -->
246
+
247
+
248
+ <!-- ================================
249
+ GHOST CARD
250
+ Invisible container — same structure + spacing as pa-card, but
251
+ transparent background, no border, no shadow. Useful for wrapping
252
+ stat tiles or content blocks that need card-like layout without
253
+ the visual chrome (see KPI dashboard).
254
+ Uses !important to beat dark-mode scoped overrides.
255
+ ================================ -->
256
+
257
+ <div class="pa-card pa-card--ghost pa-card--stat">
258
+ <div class="pa-card__body">
259
+ <div class="pa-stat pa-stat--hero-compact">
260
+ <div class="pa-stat__label">Total Customers</div>
261
+ <div class="pa-stat__value">156,340</div>
262
+ <div class="pa-stat__change pa-stat__change--positive">▲ 6.8% vs last month</div>
263
+ </div>
264
+ </div>
265
+ </div>
266
+
267
+
268
+ <!-- STAT CARDS (pa-card--stat) -->
269
+
270
+ <!-- Basic stat card — tighter body padding for compact KPI tiles -->
271
+ <div class="pa-card pa-card--stat">
272
+ <div class="pa-card__body">
273
+ <div class="pa-stat">
274
+ <div class="pa-stat__value">1,234</div>
275
+ <div class="pa-stat__label">Total Users</div>
276
+ </div>
277
+ </div>
278
+ </div>
247
279
 
280
+ <!-- Stat card with icon -->
281
+ <div class="pa-card pa-card--stat">
282
+ <div class="pa-card__body">
283
+ <div class="pa-stat pa-stat--with-icon">
284
+ <div class="pa-stat__icon">👥</div>
285
+ <div class="pa-stat__content">
286
+ <div class="pa-stat__value">1,234</div>
287
+ <div class="pa-stat__label">Total Users</div>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ </div>
248
292
 
249
- <!-- CARD WITH TAB CONTENT -->
293
+ <!-- Stat card with trend indicator -->
294
+ <div class="pa-card pa-card--stat">
295
+ <div class="pa-card__body">
296
+ <div class="pa-stat">
297
+ <div class="pa-stat__value">$12,345</div>
298
+ <div class="pa-stat__label">Revenue</div>
299
+ <div class="pa-stat__trend pa-stat__trend--up">+12.5%</div>
300
+ </div>
301
+ </div>
302
+ </div>
250
303
 
251
- <!-- Card with Tab Content Areas -->
304
+ <!-- Note: .pa-stat itself is defined in _statistics.scss (not _cards.scss).
305
+ The pa-card--stat modifier just tightens card body padding so tiles
306
+ look compact on a dashboard. A fuller statistics reference is in the
307
+ pending statistics.html snippet. -->
308
+
309
+
310
+ <!-- ================================
311
+ LIVE-DATA STATES
312
+ Persistent tinted background reflecting the latest change. JS
313
+ swaps the class on each data update; the colour stays until the
314
+ next update (so the user sees what just changed). Good for
315
+ real-time dashboards, live orders, ticker rows.
316
+ ================================ -->
317
+
318
+ <div class="pa-card pa-card--live-up">
319
+ <div class="pa-card__body">Value went up — card tinted green until next tick.</div>
320
+ </div>
321
+
322
+ <div class="pa-card pa-card--live-down">
323
+ <div class="pa-card__body">Value went down — card tinted red until next tick.</div>
324
+ </div>
325
+
326
+ <div class="pa-card pa-card--live-neutral">
327
+ <div class="pa-card__body">Neutral state — back to the default card background.</div>
328
+ </div>
329
+
330
+
331
+ <!-- ================================
332
+ CARD TABS
333
+ Two tab styles in the header: default (bordered tabs inside
334
+ __tabs) and --inline (compact pill tabs that can sit next to
335
+ title/actions in the same header row).
336
+ ================================ -->
337
+
338
+ <!-- Default tabs (below title, full-width row) -->
252
339
  <div class="pa-card">
253
340
  <div class="pa-card__header">
254
341
  <div class="pa-card__tabs">
255
- <button class="pa-card__tab pa-card__tab--active" onclick="switchTab(this, 'tab1')">Tab 1</button>
256
- <button class="pa-card__tab" onclick="switchTab(this, 'tab2')">Tab 2</button>
257
- <button class="pa-card__tab" onclick="switchTab(this, 'tab3')">Tab 3</button>
342
+ <button class="pa-card__tab pa-card__tab--active" onclick="switchTab(this, 'tab1')">Overview</button>
343
+ <button class="pa-card__tab" onclick="switchTab(this, 'tab2')">Details</button>
344
+ <button class="pa-card__tab" onclick="switchTab(this, 'tab3')">Settings</button>
258
345
  </div>
259
346
  </div>
260
347
  <div class="pa-card__body">
261
- <div class="pa-card__tab-content pa-card__tab-content--active" id="tab1">
262
- Content for Tab 1
263
- </div>
264
- <div class="pa-card__tab-content" id="tab2">
265
- Content for Tab 2
266
- </div>
267
- <div class="pa-card__tab-content" id="tab3">
268
- Content for Tab 3
348
+ <div class="pa-card__tab-content pa-card__tab-content--active" id="tab1">Tab 1</div>
349
+ <div class="pa-card__tab-content" id="tab2">Tab 2</div>
350
+ <div class="pa-card__tab-content" id="tab3">Tab 3</div>
351
+ </div>
352
+ </div>
353
+
354
+ <!-- Inline tabs — pills that live in the header row -->
355
+ <div class="pa-card">
356
+ <div class="pa-card__header">
357
+ <h3>Sales</h3>
358
+ <div class="pa-card__tabs pa-card__tabs--inline">
359
+ <button class="pa-card__tab pa-card__tab--active">Day</button>
360
+ <button class="pa-card__tab">Week</button>
361
+ <button class="pa-card__tab">Month</button>
269
362
  </div>
270
363
  </div>
364
+ <div class="pa-card__body">Chart area.</div>
271
365
  </div>
272
366
 
273
367
 
274
- <!-- SAME HEIGHT CARDS -->
368
+ <!-- CLICKABLE CARD (anchor-wrapped) -->
369
+
370
+ <!-- When the whole card should be a link, wrap the card with <a>.
371
+ a.pa-card resets text-decoration and color so the card looks
372
+ identical, but the entire area becomes clickable. -->
373
+ <a href="/products/42" class="pa-card">
374
+ <div class="pa-card__header">
375
+ <h3>Widget Pro</h3>
376
+ </div>
377
+ <div class="pa-card__body">
378
+ <p>Click anywhere on this card to navigate.</p>
379
+ </div>
380
+ </a>
381
+
382
+
383
+ <!-- SAME-HEIGHT CARDS IN A GRID ROW -->
275
384
 
276
- <!-- Equal Height Cards in a Row -->
277
385
  <div class="pa-row pa-row--same-height">
278
386
  <div class="pa-col-100 pa-col-md-1-3">
279
387
  <div class="pa-card">
280
- <div class="pa-card__header">
281
- <h3>Short Card</h3>
282
- </div>
283
- <div class="pa-card__body">
284
- <p>Minimal content.</p>
285
- </div>
388
+ <div class="pa-card__header"><h3>Short Card</h3></div>
389
+ <div class="pa-card__body"><p>Minimal content.</p></div>
286
390
  </div>
287
391
  </div>
288
392
  <div class="pa-col-100 pa-col-md-1-3">
289
393
  <div class="pa-card">
290
- <div class="pa-card__header">
291
- <h3>Tall Card</h3>
292
- </div>
394
+ <div class="pa-card__header"><h3>Tall Card</h3></div>
293
395
  <div class="pa-card__body">
294
- <p>This card has more content.</p>
295
- <p>All cards stretch to match this height.</p>
296
- <p>Useful for consistent dashboard layouts.</p>
396
+ <p>More content.</p>
397
+ <p>Siblings stretch to match.</p>
297
398
  </div>
298
399
  </div>
299
400
  </div>
300
401
  <div class="pa-col-100 pa-col-md-1-3">
301
402
  <div class="pa-card">
302
- <div class="pa-card__header">
303
- <h3>Medium Card</h3>
304
- </div>
305
- <div class="pa-card__body">
306
- <p>Also stretches to match.</p>
307
- </div>
403
+ <div class="pa-card__header"><h3>Medium Card</h3></div>
404
+ <div class="pa-card__body"><p>Also stretches.</p></div>
308
405
  </div>
309
406
  </div>
310
407
  </div>
311
408
 
312
409
 
313
- <!-- CARD SECTION -->
410
+ <!-- CARD SECTION — underlined heading above a card -->
314
411
 
315
- <!-- Section with Heading -->
316
412
  <div class="pa-section">
317
413
  <h3>Section Title</h3>
318
414
  <div class="pa-card">
319
415
  <div class="pa-card__body">
320
- Content inside section
416
+ The section heading ties multiple cards together with an accent
417
+ underline above them.
321
418
  </div>
322
419
  </div>
323
420
  </div>
324
421
 
422
+ <!-- Standalone section title (not tied to a .pa-section container) -->
423
+ <h3 class="pa-section-title">Standalone Section Title</h3>
424
+
325
425
 
326
426
  <!-- JAVASCRIPT FOR TAB SWITCHING -->
327
427
  <script>
328
428
  function switchTab(button, tabId) {
329
- // Remove active class from all tabs
330
429
  const tabs = button.parentElement.querySelectorAll('.pa-card__tab');
331
430
  tabs.forEach(tab => tab.classList.remove('pa-card__tab--active'));
332
-
333
- // Add active class to clicked tab
334
431
  button.classList.add('pa-card__tab--active');
335
432
 
336
- // Hide all tab content
337
433
  const card = button.closest('.pa-card');
338
434
  const contents = card.querySelectorAll('.pa-card__tab-content');
339
- contents.forEach(content => content.classList.remove('pa-card__tab-content--active'));
435
+ contents.forEach(c => c.classList.remove('pa-card__tab-content--active'));
340
436
 
341
- // Show selected tab content
342
- const selectedContent = card.querySelector(`#${tabId}`);
343
- if (selectedContent) {
344
- selectedContent.classList.add('pa-card__tab-content--active');
345
- }
437
+ const selected = card.querySelector(`#${tabId}`);
438
+ if (selected) selected.classList.add('pa-card__tab-content--active');
346
439
  }
347
440
  </script>
348
441
 
@@ -352,41 +445,131 @@ function switchTab(button, tabId) {
352
445
  ================================ -->
353
446
 
354
447
  <!--
355
- CARD CLASSES:
356
- - .pa-card: Base card class
357
- - .pa-card--primary, --success, --warning, --danger: Colored header variants
358
- - .pa-card--stat: Stat card variant (compact, centered)
359
-
360
- CARD ELEMENTS:
361
- - .pa-card__header: Card header container
362
- - .pa-card__body: Card body/content container
363
- - .pa-card__body--no-padding: Remove body padding (for tables)
364
- - .pa-card__footer: Card footer container
365
- - .pa-card__meta: Metadata text (dates, author, etc.)
366
- - .pa-card__title: Title container
367
- - .pa-card__title-icon: Icon in title
368
- - .pa-card__title-text: Title text
369
- - .pa-card__actions: Actions container (used in header and footer)
370
-
371
- CARD TABS:
372
- - .pa-card__tabs: Tab container in header
373
- - .pa-card__tab: Individual tab button
374
- - .pa-card__tab--active: Active tab state
375
- - .pa-card__tab-content: Tab panel content
376
- - .pa-card__tab-content--active: Active tab panel
377
-
378
- STAT COMPONENT (inside stat cards):
379
- - .pa-stat: Stat container
380
- - .pa-stat--with-icon: Stat with icon layout
381
- - .pa-stat__icon: Stat icon
382
- - .pa-stat__content: Content wrapper (when using icon)
383
- - .pa-stat__value: Stat value (large number)
384
- - .pa-stat__label: Stat label/description
385
- - .pa-stat__trend: Trend indicator
386
- - .pa-stat__trend--up: Positive trend (green)
387
- - .pa-stat__trend--down: Negative trend (red)
388
-
389
- LAYOUT:
390
- - .pa-row--same-height: Equal height cards in a row
391
- - .pa-section: Section container with heading
448
+ pa-card — THE CARD CONTAINER:
449
+ - .pa-card flex column, shadow, hover lift, overflow:hidden
450
+ so children respect the rounded border.
451
+
452
+ VARIANTS (fill the header with a semantic colour):
453
+ - .pa-card--primary
454
+ - .pa-card--success
455
+ - .pa-card--warning
456
+ - .pa-card--danger
457
+ (No --secondary / --info / --light / --dark — not defined in SCSS.)
458
+
459
+ THEME COLOUR VARIANTS (1-9):
460
+ - .pa-card--color-{1..9} header bg = --pa-color-N,
461
+ header text = --pa-color-N-text
462
+
463
+ LAYOUT / STATE MODIFIERS:
464
+ - .pa-card--stat Tighter body padding for compact KPI tiles.
465
+ - .pa-card--ghost Invisible container: transparent bg, no
466
+ border, no shadow. Uses !important to
467
+ beat dark-mode scoped overrides.
468
+ - .pa-card--live-up Persistent green tint on update.
469
+ - .pa-card--live-down Persistent red tint on update.
470
+ - .pa-card--live-neutral Reset to default card background.
471
+
472
+ CLICKABLE CARD:
473
+ - <a class="pa-card"> Full-card link; styles reset so it
474
+ looks identical to a regular card.
475
+
476
+ SUB-ELEMENTS:
477
+ - .pa-card__header Flex row: [title] — [description] — [actions].
478
+ Direct h1..h6 and <p> children auto-truncate.
479
+ Native tags inside get margin/padding/border
480
+ reset so they inherit the header layout cleanly.
481
+ - .pa-card__body flex: 1; standard padding.
482
+ - .pa-card__footer Border-top + footer background; flex row.
483
+ - .pa-card__actions Button/control container (gap + align-center).
484
+ flex-shrink: 0 inside header.
485
+ - .pa-card__meta Muted secondary text (dates, byline, etc.).
486
+
487
+ TITLE SUB-COMPONENT:
488
+ - .pa-card__title Flex row wrapping icon + text; flex: 1 so
489
+ the actions sibling stays on the right.
490
+ - .pa-card__title-icon Fixed-size icon.
491
+ - .pa-card__title-text Truncates with ellipsis on overflow.
492
+
493
+ BODY MODIFIER:
494
+ - .pa-card__body--no-padding Strips body padding (for tables / lists
495
+ that should meet the card borders).
496
+ For a proper table-in-card, reach for
497
+ .pa-table-card instead (see tables.html).
498
+
499
+ HEADER MODIFIERS:
500
+ - .pa-card__header--underlined
501
+ Accent-coloured border under h1..h6 in the header. Composes with:
502
+ --underline-success / --underline-warning / --underline-danger
503
+ --underline-info / --underline-color-{1..9}
504
+ (e.g. pa-card__header--underlined pa-card__header--underline-success)
505
+
506
+ - .pa-card__header--wrap
507
+ Allow heading + description to wrap to multiple lines instead of
508
+ being truncated with an ellipsis. Description reflows to its own
509
+ line.
510
+
511
+ TABS:
512
+ - .pa-card__tabs Full-width tab strip inside the header
513
+ (sits below the title).
514
+ - .pa-card__tabs--inline Compact pill-style tabs that fit on the
515
+ same row as title/actions.
516
+ - .pa-card__tab Individual tab button (pill or strip,
517
+ depending on --inline).
518
+ - .pa-card__tab--active Current tab state.
519
+ - .pa-card__tab-content Tab panel; hidden by default.
520
+ - .pa-card__tab-content--active Visible tab panel.
521
+
522
+ SECTION WRAPPERS (lighter than a card, for heading-only groupings):
523
+ - .pa-section Container with a muted h3 heading that
524
+ carries an accent-underlined border.
525
+ - .pa-section-title Standalone heading style — same accent
526
+ underline, no container behaviour.
527
+
528
+ IMPLICIT BEHAVIOURS:
529
+ - The header is flex with auto-truncation: direct h1..h6 and <p>
530
+ children get white-space: nowrap + text-overflow: ellipsis. This
531
+ is why long card titles look "cut off" in narrow columns — use
532
+ --wrap to opt out.
533
+ - Buttons inside the header get -0.25rem vertical margin so they
534
+ don't grow the header height past $card-header-min-height.
535
+ - Card body :first-child gets margin-top: 0 to avoid double-spacing
536
+ with the body padding.
537
+
538
+ STRUCTURE PATTERNS:
539
+
540
+ Card with three-part header:
541
+ <div class="pa-card">
542
+ <div class="pa-card__header">
543
+ <h3>Title</h3>
544
+ <p>Description (truncates)</p>
545
+ <div class="pa-card__actions">
546
+ <button class="pa-btn pa-btn--sm">Action</button>
547
+ </div>
548
+ </div>
549
+ <div class="pa-card__body">…</div>
550
+ </div>
551
+
552
+ Card with underlined header (semantic variant):
553
+ <div class="pa-card">
554
+ <div class="pa-card__header pa-card__header--underlined pa-card__header--underline-danger">
555
+ <h3>Critical Settings</h3>
556
+ </div>
557
+ <div class="pa-card__body">…</div>
558
+ </div>
559
+
560
+ Ghost stat tile in a dashboard:
561
+ <div class="pa-card pa-card--ghost pa-card--stat">
562
+ <div class="pa-card__body">
563
+ <div class="pa-stat">
564
+ <div class="pa-stat__value">1,234</div>
565
+ <div class="pa-stat__label">Users</div>
566
+ </div>
567
+ </div>
568
+ </div>
569
+
570
+ Clickable card:
571
+ <a href="/item/42" class="pa-card">
572
+ <div class="pa-card__header"><h3>Item 42</h3></div>
573
+ <div class="pa-card__body">Click anywhere.</div>
574
+ </a>
392
575
  -->