@keenmate/pure-admin-core 2.7.1 → 2.9.0-rc01
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.
- package/README.md +14 -24
- package/dist/css/main.css +628 -97
- package/package.json +1 -1
- package/snippets/profile.html +15 -10
- package/src/scss/_base-css-variables.scss +18 -8
- package/src/scss/core-components/_cards.scss +15 -2
- package/src/scss/core-components/_kpi-bento.scss +41 -6
- package/src/scss/core-components/_kpi-comparison-gauges.scss +60 -23
- package/src/scss/core-components/_kpi-editorial-minimal.scss +63 -20
- package/src/scss/core-components/_kpi-hero-supporting.scss +15 -1
- package/src/scss/core-components/_kpi-numeric-strip.scss +74 -15
- package/src/scss/core-components/_kpi-sparkline-list.scss +56 -4
- package/src/scss/core-components/_kpi-terminal.scss +22 -15
- package/src/scss/core-components/_profile.scss +6 -14
- package/src/scss/main.scss +11 -0
- package/src/scss/variables/_base.scss +3 -11
- package/src/scss/variables/_colors.scss +19 -19
- package/src/scss/variables/_components.scss +0 -1
- package/src/scss/variables/_system.scss +8 -0
- package/src/scss/.claude/settings.local.json +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keenmate/pure-admin-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0-rc01",
|
|
4
4
|
"description": "Lightweight, data-focused HTML/CSS admin framework built with PureCSS foundation and comprehensive component system",
|
|
5
5
|
"style": "dist/css/main.css",
|
|
6
6
|
"exports": {
|
package/snippets/profile.html
CHANGED
|
@@ -58,7 +58,7 @@ to save horizontal space in the navbar.
|
|
|
58
58
|
<!-- title= attrs give a tooltip when the text truncates with ellipsis -->
|
|
59
59
|
<h3 class="pa-profile-panel__name" title="John Doe">John Doe</h3>
|
|
60
60
|
<p class="pa-profile-panel__email" title="john.doe@company.com">john.doe@company.com</p>
|
|
61
|
-
<span class="pa-
|
|
61
|
+
<span class="pa-badge">Administrator</span>
|
|
62
62
|
</div>
|
|
63
63
|
<button class="pa-profile-panel__close" onclick="closeProfilePanel()" aria-label="Close Profile">
|
|
64
64
|
✕
|
|
@@ -124,7 +124,7 @@ to save horizontal space in the navbar.
|
|
|
124
124
|
<div class="pa-profile-panel__info">
|
|
125
125
|
<h3 class="pa-profile-panel__name">John Doe</h3>
|
|
126
126
|
<p class="pa-profile-panel__email">john.doe@company.com</p>
|
|
127
|
-
<span class="pa-
|
|
127
|
+
<span class="pa-badge">Administrator</span>
|
|
128
128
|
</div>
|
|
129
129
|
<button class="pa-profile-panel__close" onclick="closeProfilePanel()" aria-label="Close Profile">✕</button>
|
|
130
130
|
</div>
|
|
@@ -170,7 +170,7 @@ to save horizontal space in the navbar.
|
|
|
170
170
|
<div class="pa-profile-panel__info">
|
|
171
171
|
<h3 class="pa-profile-panel__name">Jane Smith</h3>
|
|
172
172
|
<p class="pa-profile-panel__email">jane.smith@corp.example</p>
|
|
173
|
-
<span class="pa-
|
|
173
|
+
<span class="pa-badge">Analyst</span>
|
|
174
174
|
</div>
|
|
175
175
|
<button class="pa-profile-panel__close" onclick="closeProfilePanel()" aria-label="Close Profile">✕</button>
|
|
176
176
|
</div>
|
|
@@ -207,7 +207,7 @@ to save horizontal space in the navbar.
|
|
|
207
207
|
<div class="pa-profile-panel__info">
|
|
208
208
|
<h3 class="pa-profile-panel__name">John Doe</h3>
|
|
209
209
|
<p class="pa-profile-panel__email">john.doe@company.com</p>
|
|
210
|
-
<span class="pa-
|
|
210
|
+
<span class="pa-badge">Administrator</span>
|
|
211
211
|
</div>
|
|
212
212
|
<button class="pa-profile-panel__close" onclick="closeProfilePanel()" aria-label="Close Profile">✕</button>
|
|
213
213
|
</div>
|
|
@@ -425,7 +425,10 @@ HEADER:
|
|
|
425
425
|
- .pa-profile-panel__info Text column (name + email + role).
|
|
426
426
|
- .pa-profile-panel__name User name (ellipsis on overflow).
|
|
427
427
|
- .pa-profile-panel__email Email (ellipsis on overflow).
|
|
428
|
-
- .pa-
|
|
428
|
+
- .pa-badge Role chip (standard badge component;
|
|
429
|
+
add `.pa-badge--primary` / `--info` /
|
|
430
|
+
`--success` / `--warning` / `--danger`
|
|
431
|
+
/ `--light` for variant styling).
|
|
429
432
|
- .pa-profile-panel__close Close button (top-end corner).
|
|
430
433
|
|
|
431
434
|
Theme-colour design choices (why they're like this):
|
|
@@ -433,11 +436,13 @@ Theme-colour design choices (why they're like this):
|
|
|
433
436
|
colour the header uses for the user's name. This guarantees contrast
|
|
434
437
|
against dark / coloured header backgrounds across all themes (body
|
|
435
438
|
text colours would read wrong on a dark header).
|
|
436
|
-
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
--pa-
|
|
440
|
-
|
|
439
|
+
- Role uses the standard `.pa-badge` component (var(--pa-btn-secondary-bg)
|
|
440
|
+
/ -text by default), which themes already tune for both light and dark
|
|
441
|
+
modes. Previously this was a custom `.pa-profile-panel__role` element
|
|
442
|
+
coupled to --pa-header-profile-name-color — that token is sized for the
|
|
443
|
+
header (e.g. black on yellow in Express) and went invisible on dark
|
|
444
|
+
panel bodies. Migrated to `.pa-badge` in 2.9.0; older snippet markup
|
|
445
|
+
using `pa-profile-panel__role` needs the class swap.
|
|
441
446
|
|
|
442
447
|
TABS (optional — sits between __header and __body):
|
|
443
448
|
- .pa-profile-panel__tabs Tabs container (border-bottom + header-bg).
|
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
// --ms-accent-color: var(--base-accent-color, #3b82f6);
|
|
15
15
|
// ============================================================================
|
|
16
16
|
|
|
17
|
+
// Make variables resolvable when this file is loaded as a @use module
|
|
18
|
+
// (e.g. from main.scss). Legacy @import callers (themes) are unaffected —
|
|
19
|
+
// Sass places @use'd members into the importing file's global scope, where
|
|
20
|
+
// theme-set overrides already live.
|
|
21
|
+
@use 'variables/index' as *;
|
|
22
|
+
|
|
17
23
|
@mixin output-base-css-variables {
|
|
18
24
|
// === Accent Colors ===
|
|
19
25
|
--base-accent-color: #{$base-accent-color};
|
|
@@ -41,14 +47,6 @@
|
|
|
41
47
|
--base-disabled-bg: #{$base-disabled-bg};
|
|
42
48
|
--base-elevated-bg: #{$base-elevated-bg};
|
|
43
49
|
|
|
44
|
-
// === Background Colors (legacy aliases) ===
|
|
45
|
-
--base-surface-1: #{$base-surface-1};
|
|
46
|
-
--base-surface-2: #{$base-surface-2};
|
|
47
|
-
--base-surface-3: #{$base-surface-3};
|
|
48
|
-
--base-surface-inverse: #{$base-surface-inverse};
|
|
49
|
-
--base-primary-bg: #{$base-primary-bg};
|
|
50
|
-
--base-primary-bg-hover: #{$base-primary-bg-hover};
|
|
51
|
-
|
|
52
50
|
// === Border Colors ===
|
|
53
51
|
--base-border-color: #{$base-border-color};
|
|
54
52
|
--base-border: #{$base-border};
|
|
@@ -259,6 +257,18 @@
|
|
|
259
257
|
// ============================================================================
|
|
260
258
|
|
|
261
259
|
@mixin output-pa-css-variables {
|
|
260
|
+
// =========================================================================
|
|
261
|
+
// COLOR SCHEME SIGNAL
|
|
262
|
+
// Tells the browser whether this scope is light or dark so native UA
|
|
263
|
+
// elements (scrollbars, form controls) and `light-dark()` resolve
|
|
264
|
+
// correctly. Drives web components (e.g. <web-multiselect>) that ship
|
|
265
|
+
// adaptive palettes via `light-dark()`. Override $theme-color-scheme
|
|
266
|
+
// before importing variables for always-dark themes; for dual-mode
|
|
267
|
+
// themes leave default `light` here and add `color-scheme: dark;` to
|
|
268
|
+
// the `.pa-mode-dark` block.
|
|
269
|
+
// =========================================================================
|
|
270
|
+
color-scheme: #{$theme-color-scheme};
|
|
271
|
+
|
|
262
272
|
// =========================================================================
|
|
263
273
|
// CORE COLORS
|
|
264
274
|
// =========================================================================
|
|
@@ -23,8 +23,13 @@
|
|
|
23
23
|
&__header {
|
|
24
24
|
padding: $card-header-padding-v $card-header-padding-h;
|
|
25
25
|
min-height: $card-header-min-height;
|
|
26
|
-
border-top-
|
|
27
|
-
border-
|
|
26
|
+
// No own border-top-radius — the card's `overflow: hidden` + outer
|
|
27
|
+
// border-radius clips the header's square top corners to match. Setting
|
|
28
|
+
// a radius here makes the header curve at 8px while the card's INNER
|
|
29
|
+
// corner is ~7px (outer 8px minus the 1px border), leaving a thin
|
|
30
|
+
// wedge of card background visible at each top corner — most obvious
|
|
31
|
+
// on coloured variants (--primary/--success/--warning/--danger/--color-*)
|
|
32
|
+
// where the wedge shows as a white sliver against the variant colour.
|
|
28
33
|
border-bottom: $border-width-base solid var(--pa-border-color);
|
|
29
34
|
background: var(--pa-card-header-bg);
|
|
30
35
|
display: flex;
|
|
@@ -240,11 +245,15 @@
|
|
|
240
245
|
}
|
|
241
246
|
|
|
242
247
|
// Card variants
|
|
248
|
+
// Coloured variants override the header's border-bottom-color to match the
|
|
249
|
+
// variant — otherwise the default light-gray hairline shows as a visible
|
|
250
|
+
// strip against the coloured surroundings (header bg + card border above).
|
|
243
251
|
&--primary {
|
|
244
252
|
border-color: var(--pa-accent);
|
|
245
253
|
|
|
246
254
|
.pa-card__header {
|
|
247
255
|
background-color: var(--pa-accent);
|
|
256
|
+
border-bottom-color: var(--pa-accent);
|
|
248
257
|
color: var(--pa-btn-primary-text);
|
|
249
258
|
|
|
250
259
|
h1,
|
|
@@ -263,6 +272,7 @@
|
|
|
263
272
|
|
|
264
273
|
.pa-card__header {
|
|
265
274
|
background-color: var(--pa-success-bg);
|
|
275
|
+
border-bottom-color: var(--pa-success-bg);
|
|
266
276
|
color: var(--pa-btn-success-text);
|
|
267
277
|
|
|
268
278
|
h1,
|
|
@@ -281,6 +291,7 @@
|
|
|
281
291
|
|
|
282
292
|
.pa-card__header {
|
|
283
293
|
background-color: var(--pa-warning-bg);
|
|
294
|
+
border-bottom-color: var(--pa-warning-bg);
|
|
284
295
|
color: var(--pa-btn-warning-text);
|
|
285
296
|
|
|
286
297
|
h1,
|
|
@@ -299,6 +310,7 @@
|
|
|
299
310
|
|
|
300
311
|
.pa-card__header {
|
|
301
312
|
background-color: var(--pa-danger-bg);
|
|
313
|
+
border-bottom-color: var(--pa-danger-bg);
|
|
302
314
|
color: var(--pa-btn-danger-text);
|
|
303
315
|
|
|
304
316
|
h1,
|
|
@@ -366,6 +378,7 @@
|
|
|
366
378
|
|
|
367
379
|
.pa-card__header {
|
|
368
380
|
background-color: var(--pa-color-#{$i});
|
|
381
|
+
border-bottom-color: var(--pa-color-#{$i});
|
|
369
382
|
color: var(--pa-color-#{$i}-text);
|
|
370
383
|
|
|
371
384
|
h1,
|
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
/* ========================================
|
|
2
2
|
KPI · Bento layout
|
|
3
3
|
Magazine-style asymmetric tile sizing with sparklines as soft background
|
|
4
|
-
fills behind the values. 6
|
|
4
|
+
fills behind the values. Default 6-tile layout on a 6-col × 3-row grid
|
|
5
5
|
(hero left-half × 2 rows, two stacked right-half × 2 rows, three equal
|
|
6
|
-
tiles bottom row). Tile placement by source order via :nth-child
|
|
6
|
+
tiles bottom row). Tile placement is by source order via :nth-child, so
|
|
7
|
+
markup stays identical across layout modifiers.
|
|
8
|
+
|
|
9
|
+
Layout modifiers (below) swap `grid-template-areas` to provide
|
|
10
|
+
alternative compositions:
|
|
11
|
+
· default (no modifier) — 6 tiles, hero on the left
|
|
12
|
+
· `--hero-right` — 6 tiles, mirror of default (hero on right)
|
|
13
|
+
· `--5-tile` — 5 tiles, hero + 4 supporting
|
|
14
|
+
Row height is a CSS variable (`--pa-kpi-bento-row-height`, default
|
|
15
|
+
`12rem`) so authors can dial tile height per instance.
|
|
7
16
|
======================================== */
|
|
8
17
|
@use '../variables' as *;
|
|
9
18
|
|
|
10
19
|
.pa-kpi-bento {
|
|
11
20
|
container-type: inline-size;
|
|
21
|
+
--pa-kpi-bento-row-height: 12rem;
|
|
12
22
|
}
|
|
13
23
|
.pa-kpi-bento__body { padding: 1.6rem; }
|
|
14
24
|
|
|
15
|
-
/* ----- Bento grid
|
|
25
|
+
/* ----- Bento grid (default: 6 tiles, hero on left) ---------------------- */
|
|
16
26
|
.pa-kpi-bento__grid {
|
|
17
27
|
display: grid;
|
|
18
28
|
grid-template-columns: repeat(6, 1fr);
|
|
19
|
-
grid-template-rows:
|
|
29
|
+
grid-template-rows: repeat(3, var(--pa-kpi-bento-row-height));
|
|
20
30
|
grid-template-areas:
|
|
21
31
|
"hero hero hero a a a"
|
|
22
32
|
"hero hero hero b b b"
|
|
@@ -31,8 +41,33 @@
|
|
|
31
41
|
> :nth-child(6) { grid-area: e; }
|
|
32
42
|
}
|
|
33
43
|
|
|
34
|
-
/*
|
|
35
|
-
|
|
44
|
+
/* Modifier: --hero-right — mirror of default. Hero on the right half,
|
|
45
|
+
two stacked tiles on the left of rows 1-2, three equal tiles below.
|
|
46
|
+
Same 6-tile contract as default; only the template flips. Source
|
|
47
|
+
order stays unchanged (1st = hero, 2nd = a, …). */
|
|
48
|
+
.pa-kpi-bento__grid--hero-right {
|
|
49
|
+
grid-template-areas:
|
|
50
|
+
"a a a hero hero hero"
|
|
51
|
+
"b b b hero hero hero"
|
|
52
|
+
"c c d d e e";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Modifier: --5-tile — hero + 4 supporting. Hero spans the left half ×
|
|
56
|
+
2 rows, two stacked tiles on the right (rows 1-2), two equal halves on
|
|
57
|
+
the bottom row. Requires exactly 5 tiles — a 6th tile (if present)
|
|
58
|
+
would be auto-placed in a new row and break the layout. */
|
|
59
|
+
.pa-kpi-bento__grid--5-tile {
|
|
60
|
+
grid-template-areas:
|
|
61
|
+
"hero hero hero a a a"
|
|
62
|
+
"hero hero hero b b b"
|
|
63
|
+
"c c c d d d";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Narrow card → stack everything single column. Resets `grid-area: auto`
|
|
67
|
+
on every tile so the same markup works regardless of which layout
|
|
68
|
+
modifier the grid carries (the @container override sets
|
|
69
|
+
`grid-template-areas: none` and the `grid-area: auto` on nth-child
|
|
70
|
+
together neutralise any modifier's template). */
|
|
36
71
|
@container (max-width: 700px) {
|
|
37
72
|
.pa-kpi-bento__grid {
|
|
38
73
|
grid-template-columns: 1fr;
|
|
@@ -3,55 +3,92 @@
|
|
|
3
3
|
Goal-oriented progress bars. Each KPI shows label · value, a bar with a
|
|
4
4
|
target tick, and a 0 · tgt scale below. Bar fill = value/target * 100%,
|
|
5
5
|
capped visually so overshoots are signalled by colour, not overflow.
|
|
6
|
+
|
|
7
|
+
Layout is a cell-min-driven `auto-fit` grid — cells stay at least
|
|
8
|
+
`--pa-kpi-gauge-cell-min` wide, the grid fits as many columns as the
|
|
9
|
+
container allows, and the responsive cascade is intrinsic to the grid
|
|
10
|
+
template (no `@container` queries). `--max-N` cap modifiers cap the
|
|
11
|
+
column count at N while still collapsing below the cell-min × N
|
|
12
|
+
threshold. Same pattern as `_kpi-editorial-minimal.scss`.
|
|
6
13
|
======================================== */
|
|
7
14
|
@use '../variables' as *;
|
|
8
15
|
|
|
9
|
-
.pa-kpi-gauge-list {
|
|
10
|
-
container-type: inline-size;
|
|
11
|
-
}
|
|
12
16
|
.pa-kpi-gauge-list__body { padding: 0; }
|
|
13
17
|
|
|
14
|
-
/*
|
|
18
|
+
/* ----- Grid + hairline rules -------------------------------------------
|
|
19
|
+
Cell-min-driven responsive layout. Override `--pa-kpi-gauge-cell-min`
|
|
20
|
+
per instance to change density (smaller min → more columns at the same
|
|
21
|
+
container width).
|
|
22
|
+
|
|
23
|
+
`gap: 1px` over `background: var(--pa-border-color)` with each tile
|
|
24
|
+
painting `background: var(--pa-card-bg)` on top — only the gap shows
|
|
25
|
+
through, giving single-pixel hairlines on every interior boundary
|
|
26
|
+
regardless of column count. The card's outer border supplies the
|
|
27
|
+
perimeter. Replaces the previous per-tile `border-right` +
|
|
28
|
+
`border-bottom` + nth-child suppression machinery, which only worked
|
|
29
|
+
for the hardcoded 2-col layout. */
|
|
15
30
|
.pa-kpi-gauge-list__grid {
|
|
16
31
|
display: grid;
|
|
17
|
-
grid-template-columns: repeat(
|
|
32
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--pa-kpi-gauge-cell-min, 20rem), 1fr));
|
|
33
|
+
gap: 1px;
|
|
34
|
+
background: var(--pa-border-color);
|
|
18
35
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
36
|
+
|
|
37
|
+
/* Modifier: force exactly 2 columns regardless of cell-min or container
|
|
38
|
+
width. For placements wanting a deterministic 2×N layout. */
|
|
39
|
+
.pa-kpi-gauge-list__grid--2col { grid-template-columns: repeat(2, 1fr); }
|
|
40
|
+
|
|
41
|
+
/* Cap-at-N modifiers: combine auto-fit with a ceiling on the column
|
|
42
|
+
count. Cells stay at least --pa-kpi-gauge-cell-min wide, but the grid
|
|
43
|
+
never exceeds N columns even when the container is wide enough to fit
|
|
44
|
+
more. Below the cell-min × N threshold the grid still collapses
|
|
45
|
+
responsively — these modifiers cap the maximum, not the minimum.
|
|
46
|
+
|
|
47
|
+
How the calc reads: each track's effective min is
|
|
48
|
+
max(cell-min, (container − total-gap) / N)
|
|
49
|
+
On a wide container the calc wins (so tracks grow, you stay at N).
|
|
50
|
+
On a narrow container cell-min wins (so the grid collapses).
|
|
51
|
+
|
|
52
|
+
Pick the cap so your item count divides into clean rows. */
|
|
53
|
+
.pa-kpi-gauge-list__grid--max-2 {
|
|
54
|
+
grid-template-columns:
|
|
55
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-gauge-cell-min, 20rem), calc((100% - 1px) / 2)), 1fr));
|
|
56
|
+
}
|
|
57
|
+
.pa-kpi-gauge-list__grid--max-3 {
|
|
58
|
+
grid-template-columns:
|
|
59
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-gauge-cell-min, 20rem), calc((100% - 1px * 2) / 3)), 1fr));
|
|
60
|
+
}
|
|
61
|
+
.pa-kpi-gauge-list__grid--max-4 {
|
|
62
|
+
grid-template-columns:
|
|
63
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-gauge-cell-min, 20rem), calc((100% - 1px * 3) / 4)), 1fr));
|
|
64
|
+
}
|
|
65
|
+
.pa-kpi-gauge-list__grid--max-5 {
|
|
66
|
+
grid-template-columns:
|
|
67
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-gauge-cell-min, 20rem), calc((100% - 1px * 4) / 5)), 1fr));
|
|
68
|
+
}
|
|
69
|
+
.pa-kpi-gauge-list__grid--max-6 {
|
|
70
|
+
grid-template-columns:
|
|
71
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-gauge-cell-min, 20rem), calc((100% - 1px * 5) / 6)), 1fr));
|
|
23
72
|
}
|
|
24
73
|
|
|
25
74
|
/* ----- Gauge tile (label/value head · bar · 0/tgt scale) ---------------- */
|
|
26
75
|
.pa-kpi-gauge {
|
|
27
76
|
position: relative;
|
|
77
|
+
background: var(--pa-card-bg);
|
|
28
78
|
padding: 1.6rem 2rem;
|
|
29
|
-
|
|
30
|
-
border-right: 1px solid var(--pa-border-color);
|
|
79
|
+
min-width: 0;
|
|
31
80
|
|
|
32
81
|
/* Per-tile bar colour cascade — modifiers below set the var, the fill
|
|
33
82
|
reads it. Cleaner than per-modifier-per-element rules; host apps can
|
|
34
83
|
override at the tile level via inline style="--pa-kpi-bar-color: …". */
|
|
35
84
|
--pa-kpi-bar-color: var(--pa-positive);
|
|
36
85
|
|
|
37
|
-
&:nth-child(2n) { border-right: 0; }
|
|
38
|
-
&:nth-last-child(-n+2) { border-bottom: 0; }
|
|
39
|
-
|
|
40
86
|
&--positive { --pa-kpi-bar-color: var(--pa-positive); }
|
|
41
87
|
&--warning { --pa-kpi-bar-color: var(--pa-warning); }
|
|
42
88
|
&--negative { --pa-kpi-bar-color: var(--pa-negative); }
|
|
43
89
|
&--neutral { --pa-kpi-bar-color: color-mix(in srgb, var(--pa-text-color-1) 70%, transparent); }
|
|
44
90
|
}
|
|
45
91
|
|
|
46
|
-
@container (max-width: 600px) {
|
|
47
|
-
.pa-kpi-gauge {
|
|
48
|
-
border-right: 0;
|
|
49
|
-
|
|
50
|
-
&:nth-last-child(-n+2) { border-bottom: 1px solid var(--pa-border-color); }
|
|
51
|
-
&:last-child { border-bottom: 0; }
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
92
|
/* ----- Head: label left, value right (baseline-aligned) ----------------- */
|
|
56
93
|
.pa-kpi-gauge__head {
|
|
57
94
|
display: flex;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* ========================================
|
|
2
2
|
KPI · Editorial minimal
|
|
3
|
-
|
|
3
|
+
KPI tiles in a responsive grid with hairline rules between cells,
|
|
4
4
|
generous space, and an extra-light-weight number as the focal point per
|
|
5
5
|
tile. No charts, no pills — the design's whole identity is the thin
|
|
6
6
|
numeral. Renders as a table card (zero card-body padding) so hairlines
|
|
@@ -11,32 +11,73 @@
|
|
|
11
11
|
.pa-kpi-edit__body { padding: 0; }
|
|
12
12
|
|
|
13
13
|
/* ----- Grid + hairline rules -------------------------------------------
|
|
14
|
+
Cell-min-driven responsive layout: cells stay at least
|
|
15
|
+
--pa-kpi-edit-cell-min wide; the grid fits as many columns as the
|
|
16
|
+
container allows. No @container queries — `auto-fit + minmax` handles
|
|
17
|
+
the cascade intrinsically. Override the min per instance to change
|
|
18
|
+
density (smaller min → more columns at the same container width).
|
|
19
|
+
|
|
14
20
|
`gap: 1px` over `background: var(--pa-border-color)` with each tile
|
|
15
|
-
painting `background: var(--pa-card-bg)` on top
|
|
16
|
-
through, giving
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
painting `background: var(--pa-card-bg)` on top — only the gap shows
|
|
22
|
+
through, giving single-pixel hairlines on every interior boundary
|
|
23
|
+
regardless of column count. The card's outer border supplies the
|
|
24
|
+
perimeter. */
|
|
19
25
|
.pa-kpi-edit__grid {
|
|
20
26
|
display: grid;
|
|
21
|
-
grid-template-columns: repeat(
|
|
27
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--pa-kpi-edit-cell-min, 14rem), 1fr));
|
|
22
28
|
gap: 1px;
|
|
23
29
|
background: var(--pa-border-color);
|
|
24
|
-
container-type: inline-size;
|
|
25
|
-
}
|
|
26
|
-
@container (max-width: 640px) {
|
|
27
|
-
.pa-kpi-edit__grid { grid-template-columns: repeat(2, 1fr); }
|
|
28
|
-
}
|
|
29
|
-
@container (max-width: 360px) {
|
|
30
|
-
.pa-kpi-edit__grid { grid-template-columns: 1fr; }
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
/* Modifier: force 2
|
|
34
|
-
a deterministic 2×N layout (e.g. 4 tiles
|
|
35
|
-
|
|
32
|
+
/* Modifier: force exactly 2 columns regardless of cell-min or container
|
|
33
|
+
width. For placements wanting a deterministic 2×N layout (e.g. 4 tiles
|
|
34
|
+
as a clean 2×2 even when the container is wide enough for more). */
|
|
36
35
|
.pa-kpi-edit__grid--2col { grid-template-columns: repeat(2, 1fr); }
|
|
37
36
|
|
|
38
|
-
/*
|
|
37
|
+
/* Cap-at-N modifiers: combine auto-fit with a ceiling on the column
|
|
38
|
+
count. Cells stay at least --pa-kpi-edit-cell-min wide, but the grid
|
|
39
|
+
never exceeds N columns even when the container is wide enough to fit
|
|
40
|
+
more. Below the cell-min × N threshold the grid still collapses
|
|
41
|
+
responsively — these modifiers cap the maximum, not the minimum.
|
|
42
|
+
|
|
43
|
+
How the calc reads: each track's effective min is
|
|
44
|
+
max(cell-min, (container − total-gap) / N)
|
|
45
|
+
On a wide container the calc wins (so tracks grow, you stay at N).
|
|
46
|
+
On a narrow container cell-min wins (so the grid collapses).
|
|
47
|
+
|
|
48
|
+
Why this matters for the gray-void edge case: `auto-fit` keeps as many
|
|
49
|
+
tracks as fit the container, then only collapses tracks empty across
|
|
50
|
+
the *whole* grid. With 6 items at 4-col auto-fit, tracks 1–4 all have
|
|
51
|
+
row-1 items, so row 2's tracks 3–4 stay (and show the gap background).
|
|
52
|
+
Capping at 3 makes 6 items pack 3×2 cleanly. Pick the cap so your item
|
|
53
|
+
count divides into clean rows. */
|
|
54
|
+
.pa-kpi-edit__grid--max-2 {
|
|
55
|
+
grid-template-columns:
|
|
56
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-edit-cell-min, 14rem), calc((100% - 1px) / 2)), 1fr));
|
|
57
|
+
}
|
|
58
|
+
.pa-kpi-edit__grid--max-3 {
|
|
59
|
+
grid-template-columns:
|
|
60
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-edit-cell-min, 14rem), calc((100% - 1px * 2) / 3)), 1fr));
|
|
61
|
+
}
|
|
62
|
+
.pa-kpi-edit__grid--max-4 {
|
|
63
|
+
grid-template-columns:
|
|
64
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-edit-cell-min, 14rem), calc((100% - 1px * 3) / 4)), 1fr));
|
|
65
|
+
}
|
|
66
|
+
.pa-kpi-edit__grid--max-5 {
|
|
67
|
+
grid-template-columns:
|
|
68
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-edit-cell-min, 14rem), calc((100% - 1px * 4) / 5)), 1fr));
|
|
69
|
+
}
|
|
70
|
+
.pa-kpi-edit__grid--max-6 {
|
|
71
|
+
grid-template-columns:
|
|
72
|
+
repeat(auto-fit, minmax(max(var(--pa-kpi-edit-cell-min, 14rem), calc((100% - 1px * 5) / 6)), 1fr));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* ----- Tile (editorial spacing leans on the 2.4rem padding) -------------
|
|
76
|
+
Per-cell container: the value's `cqi`-based font-size scales with
|
|
77
|
+
*this* tile's width, not the whole grid's. Keeps typography legible as
|
|
78
|
+
the grid packs more cells into the same row. */
|
|
39
79
|
.pa-kpi-edit__tile {
|
|
80
|
+
container-type: inline-size;
|
|
40
81
|
background: var(--pa-card-bg);
|
|
41
82
|
padding: 2.4rem 2rem;
|
|
42
83
|
display: flex;
|
|
@@ -69,11 +110,13 @@
|
|
|
69
110
|
"monospace at low contrast".
|
|
70
111
|
- font-weight: 200 (extra-light). 300 was tested first but didn't read
|
|
71
112
|
distinctly enough as "light" against the body's 400 default.
|
|
72
|
-
- clamp() lets the number shrink in narrow
|
|
73
|
-
|
|
113
|
+
- clamp() lets the number shrink in narrow cells without manual
|
|
114
|
+
breakpoints. `cqi` measures per-cell (tile is a container) so the
|
|
115
|
+
value tracks each cell's actual width as the grid packs more
|
|
116
|
+
columns into a wider container. */
|
|
74
117
|
.pa-kpi-edit__value {
|
|
75
118
|
font-family: var(--base-font-family);
|
|
76
|
-
font-size: clamp(3.2rem,
|
|
119
|
+
font-size: clamp(3.2rem, 22cqi, 5.6rem);
|
|
77
120
|
font-weight: 200;
|
|
78
121
|
letter-spacing: -0.02em;
|
|
79
122
|
line-height: 1;
|
|
@@ -12,12 +12,26 @@
|
|
|
12
12
|
}
|
|
13
13
|
.pa-kpi-hero-list__body { padding: 1.6rem; }
|
|
14
14
|
|
|
15
|
-
/* ----- Layout: hero left, rail right ------------------------------------
|
|
15
|
+
/* ----- Layout: hero left, rail right ------------------------------------
|
|
16
|
+
Default split is 1:1 (50% hero / 50% rail). Modifiers below shift the
|
|
17
|
+
weight to the hero, which is the more common "executive dashboard"
|
|
18
|
+
shape — one big headline, supporting tiles compressed into a narrower
|
|
19
|
+
rail. Pick a modifier per instance; the markup stays unchanged. */
|
|
16
20
|
.pa-kpi-hero-list__layout {
|
|
17
21
|
display: grid;
|
|
18
22
|
grid-template-columns: 1fr 1fr;
|
|
19
23
|
gap: 1.4rem;
|
|
20
24
|
}
|
|
25
|
+
/* Hero 2/3, rail 1/3. */
|
|
26
|
+
.pa-kpi-hero-list__layout--hero-2-3 {
|
|
27
|
+
grid-template-columns: 2fr 1fr;
|
|
28
|
+
}
|
|
29
|
+
/* Hero 3/4, rail 1/4 — hero-dominant; rail is a thin sidebar. */
|
|
30
|
+
.pa-kpi-hero-list__layout--hero-3-4 {
|
|
31
|
+
grid-template-columns: 3fr 1fr;
|
|
32
|
+
}
|
|
33
|
+
/* Narrow card → stack to single column. Overrides any --hero-N-M modifier
|
|
34
|
+
that lives on the same element. */
|
|
21
35
|
@container (max-width: 700px) {
|
|
22
36
|
.pa-kpi-hero-list__layout {
|
|
23
37
|
grid-template-columns: 1fr;
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
/* ========================================
|
|
2
2
|
KPI · Numeric strip (densest)
|
|
3
|
-
Tabular "spreadsheet-style" table card with metric/now/prev
|
|
4
|
-
columns — most data per pixel, no chart chrome. Each row is its
|
|
5
|
-
grid sharing the same column template so cells align across rows
|
|
3
|
+
Tabular "spreadsheet-style" table card with metric / now / prev / Δ% /
|
|
4
|
+
target columns — most data per pixel, no chart chrome. Each row is its
|
|
5
|
+
own grid sharing the same column template so cells align across rows
|
|
6
6
|
without needing subgrid. Wide-only by design — no responsive collapse;
|
|
7
7
|
narrow placements should use Comparison gauges instead.
|
|
8
|
+
|
|
9
|
+
Column contract: `metric` + `now` are always present; `prev`, `delta`,
|
|
10
|
+
and `target` are independently optional via toggle modifiers on the
|
|
11
|
+
strip (`--no-prev`, `--no-delta`, `--no-target`). Modifiers compose, so
|
|
12
|
+
the visible column count ranges from 2 (all three optional columns
|
|
13
|
+
dropped) to 5 (none dropped). Each combination has its own template
|
|
14
|
+
selector below so the grid tracks always match the visible cell count.
|
|
8
15
|
======================================== */
|
|
9
16
|
@use '../variables' as *;
|
|
10
17
|
|
|
18
|
+
/* Per-column track widths — referenced from every template selector. */
|
|
19
|
+
$strip-col-metric: minmax(0, 2fr);
|
|
20
|
+
$strip-col-now: minmax(0, 1.1fr);
|
|
21
|
+
$strip-col-prev: minmax(0, 1fr);
|
|
22
|
+
$strip-col-delta: minmax(0, 1fr);
|
|
23
|
+
$strip-col-target: minmax(0, 1.6fr);
|
|
24
|
+
|
|
11
25
|
.pa-kpi-strip__body { padding: 0; }
|
|
12
26
|
|
|
13
27
|
/* ----- Table layout ----------------------------------------------------- */
|
|
@@ -15,11 +29,11 @@
|
|
|
15
29
|
.pa-kpi-strip__head-row {
|
|
16
30
|
display: grid;
|
|
17
31
|
grid-template-columns:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
$strip-col-metric
|
|
33
|
+
$strip-col-now
|
|
34
|
+
$strip-col-prev
|
|
35
|
+
$strip-col-delta
|
|
36
|
+
$strip-col-target;
|
|
23
37
|
column-gap: 1.6rem;
|
|
24
38
|
align-items: center;
|
|
25
39
|
position: relative;
|
|
@@ -142,13 +156,58 @@
|
|
|
142
156
|
line-height: 1;
|
|
143
157
|
}
|
|
144
158
|
|
|
145
|
-
/* -----
|
|
146
|
-
|
|
159
|
+
/* ----- Toggle modifiers ------------------------------------------------
|
|
160
|
+
`--no-prev`, `--no-delta`, `--no-target` are independently composable.
|
|
161
|
+
Each hides its column's cells (data + header) and the matching template
|
|
162
|
+
selector below adjusts `grid-template-columns` to the visible cell
|
|
163
|
+
count, so source order (metric, now, prev, delta, target) is preserved
|
|
164
|
+
and the remaining cells slot into the right tracks.
|
|
165
|
+
|
|
166
|
+
`metric` and `now` are mandatory — no toggle drops them. If a strip
|
|
167
|
+
doesn't need a focal value, it's a different design (use comparison
|
|
168
|
+
gauges or editorial-minimal). */
|
|
169
|
+
.pa-kpi-strip--no-prev .pa-kpi-strip__prev,
|
|
170
|
+
.pa-kpi-strip--no-prev .pa-kpi-strip__head--prev { display: none; }
|
|
171
|
+
.pa-kpi-strip--no-delta .pa-kpi-strip__delta,
|
|
172
|
+
.pa-kpi-strip--no-delta .pa-kpi-strip__head--delta { display: none; }
|
|
173
|
+
.pa-kpi-strip--no-target .pa-kpi-strip__target,
|
|
174
|
+
.pa-kpi-strip--no-target .pa-kpi-strip__head--target { display: none; }
|
|
175
|
+
|
|
176
|
+
/* ----- Grid templates per visible-column combination -------------------
|
|
177
|
+
8 combos (1 default + 3 single-drops + 3 double-drops + 1 triple-drop).
|
|
178
|
+
Each lists the visible columns in source order with their declared
|
|
179
|
+
`$strip-col-*` width. */
|
|
180
|
+
|
|
181
|
+
/* 4-col: one optional column dropped */
|
|
147
182
|
.pa-kpi-strip--no-prev .pa-kpi-strip__row,
|
|
148
183
|
.pa-kpi-strip--no-prev .pa-kpi-strip__head-row {
|
|
149
|
-
grid-template-columns:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
184
|
+
grid-template-columns: $strip-col-metric $strip-col-now $strip-col-delta $strip-col-target;
|
|
185
|
+
}
|
|
186
|
+
.pa-kpi-strip--no-delta .pa-kpi-strip__row,
|
|
187
|
+
.pa-kpi-strip--no-delta .pa-kpi-strip__head-row {
|
|
188
|
+
grid-template-columns: $strip-col-metric $strip-col-now $strip-col-prev $strip-col-target;
|
|
189
|
+
}
|
|
190
|
+
.pa-kpi-strip--no-target .pa-kpi-strip__row,
|
|
191
|
+
.pa-kpi-strip--no-target .pa-kpi-strip__head-row {
|
|
192
|
+
grid-template-columns: $strip-col-metric $strip-col-now $strip-col-prev $strip-col-delta;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* 3-col: two optional columns dropped */
|
|
196
|
+
.pa-kpi-strip--no-prev.pa-kpi-strip--no-delta .pa-kpi-strip__row,
|
|
197
|
+
.pa-kpi-strip--no-prev.pa-kpi-strip--no-delta .pa-kpi-strip__head-row {
|
|
198
|
+
grid-template-columns: $strip-col-metric $strip-col-now $strip-col-target;
|
|
199
|
+
}
|
|
200
|
+
.pa-kpi-strip--no-prev.pa-kpi-strip--no-target .pa-kpi-strip__row,
|
|
201
|
+
.pa-kpi-strip--no-prev.pa-kpi-strip--no-target .pa-kpi-strip__head-row {
|
|
202
|
+
grid-template-columns: $strip-col-metric $strip-col-now $strip-col-delta;
|
|
203
|
+
}
|
|
204
|
+
.pa-kpi-strip--no-delta.pa-kpi-strip--no-target .pa-kpi-strip__row,
|
|
205
|
+
.pa-kpi-strip--no-delta.pa-kpi-strip--no-target .pa-kpi-strip__head-row {
|
|
206
|
+
grid-template-columns: $strip-col-metric $strip-col-now $strip-col-prev;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* 2-col: all three optional columns dropped (metric + now only) */
|
|
210
|
+
.pa-kpi-strip--no-prev.pa-kpi-strip--no-delta.pa-kpi-strip--no-target .pa-kpi-strip__row,
|
|
211
|
+
.pa-kpi-strip--no-prev.pa-kpi-strip--no-delta.pa-kpi-strip--no-target .pa-kpi-strip__head-row {
|
|
212
|
+
grid-template-columns: $strip-col-metric $strip-col-now;
|
|
154
213
|
}
|