@keenmate/pure-admin-core 2.7.0 → 2.7.1
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 +8 -9
- package/dist/css/main.css +1520 -0
- package/package.json +1 -1
- package/src/scss/_core.scss +11 -0
- package/src/scss/core-components/_kpi-base.scss +169 -0
- package/src/scss/core-components/_kpi-bento.scss +182 -0
- package/src/scss/core-components/_kpi-comparison-gauges.scss +132 -0
- package/src/scss/core-components/_kpi-editorial-minimal.scss +128 -0
- package/src/scss/core-components/_kpi-hero-supporting.scss +210 -0
- package/src/scss/core-components/_kpi-numeric-strip.scss +154 -0
- package/src/scss/core-components/_kpi-sparkline-list.scss +171 -0
- package/src/scss/core-components/_kpi-terminal.scss +229 -0
package/dist/css/main.css
CHANGED
|
@@ -16651,6 +16651,1526 @@ code {
|
|
|
16651
16651
|
height: 0.3rem;
|
|
16652
16652
|
}
|
|
16653
16653
|
|
|
16654
|
+
/* ========================================
|
|
16655
|
+
KPI · shared base
|
|
16656
|
+
Cross-cutting building blocks used by every pa-kpi-* showcase.
|
|
16657
|
+
Tokens (--pa-positive, --pa-detail-bg, --pa-chart-trendline-*) live in
|
|
16658
|
+
_base-css-variables.scss; this file only defines the shared class
|
|
16659
|
+
surface that consumes them.
|
|
16660
|
+
======================================== */
|
|
16661
|
+
/* ----- LIVE indicator (title-bar pulse) ---------------------------------
|
|
16662
|
+
Used in every KPI card header — a small mono "LIVE" caption with a
|
|
16663
|
+
pulsing green dot. Sits next to the card title. */
|
|
16664
|
+
.pa-kpi-live {
|
|
16665
|
+
display: inline-flex;
|
|
16666
|
+
align-items: center;
|
|
16667
|
+
gap: 0.6rem;
|
|
16668
|
+
font-family: var(--base-font-family-mono);
|
|
16669
|
+
font-size: 1.2rem;
|
|
16670
|
+
font-weight: 600;
|
|
16671
|
+
letter-spacing: 0.06em;
|
|
16672
|
+
color: var(--pa-text-secondary);
|
|
16673
|
+
}
|
|
16674
|
+
.pa-kpi-live__dot {
|
|
16675
|
+
width: 0.8rem;
|
|
16676
|
+
height: 0.8rem;
|
|
16677
|
+
border-radius: 50%;
|
|
16678
|
+
background: var(--pa-positive);
|
|
16679
|
+
box-shadow: 0 0 6px var(--pa-positive);
|
|
16680
|
+
animation: pa-kpi-pulse 1.6s ease-in-out infinite;
|
|
16681
|
+
}
|
|
16682
|
+
|
|
16683
|
+
@keyframes pa-kpi-pulse {
|
|
16684
|
+
50% {
|
|
16685
|
+
opacity: 0.35;
|
|
16686
|
+
}
|
|
16687
|
+
}
|
|
16688
|
+
/* ----- Card header row --------------------------------------------------
|
|
16689
|
+
Title (h2/h3 by author choice) on one side, controls + LIVE on the other.
|
|
16690
|
+
Wraps onto multiple rows on narrow cards. Every showcase uses this shape. */
|
|
16691
|
+
.pa-kpi-header {
|
|
16692
|
+
display: flex;
|
|
16693
|
+
justify-content: space-between;
|
|
16694
|
+
align-items: center;
|
|
16695
|
+
gap: 1.6rem;
|
|
16696
|
+
flex-wrap: wrap;
|
|
16697
|
+
}
|
|
16698
|
+
|
|
16699
|
+
/* ----- Card footer caption ---------------------------------------------
|
|
16700
|
+
Two-line mono caption row at the bottom of the card (left: data source,
|
|
16701
|
+
right: timestamp). Strong text inside picks up the focal color so things
|
|
16702
|
+
like a metric name or count stand out. */
|
|
16703
|
+
.pa-kpi-footer {
|
|
16704
|
+
display: flex;
|
|
16705
|
+
justify-content: space-between;
|
|
16706
|
+
align-items: center;
|
|
16707
|
+
flex-wrap: wrap;
|
|
16708
|
+
gap: 1rem;
|
|
16709
|
+
font-family: var(--base-font-family-mono);
|
|
16710
|
+
font-size: 1.2rem;
|
|
16711
|
+
color: var(--pa-text-secondary);
|
|
16712
|
+
}
|
|
16713
|
+
.pa-kpi-footer strong {
|
|
16714
|
+
color: var(--pa-text-color-1);
|
|
16715
|
+
font-weight: 700;
|
|
16716
|
+
}
|
|
16717
|
+
|
|
16718
|
+
/* ----- Sparkline endpoint dot ------------------------------------------
|
|
16719
|
+
The SVG circle that marks the end of a sparkline is converted to a CSS
|
|
16720
|
+
span at init time — the SVG uses preserveAspectRatio="none" so an
|
|
16721
|
+
embedded <circle> renders as an oval at non-square aspect ratios.
|
|
16722
|
+
See kpi-showcases.js for the conversion; here we only style the result. */
|
|
16723
|
+
.pa-kpi-spark-dot {
|
|
16724
|
+
position: absolute;
|
|
16725
|
+
width: 6px;
|
|
16726
|
+
height: 6px;
|
|
16727
|
+
margin: -3px 0 0 -3px; /* centre on the (left, top) anchor */
|
|
16728
|
+
border-radius: 50%;
|
|
16729
|
+
background: currentColor; /* inherits sentiment color from chart wrapper */
|
|
16730
|
+
pointer-events: none;
|
|
16731
|
+
}
|
|
16732
|
+
|
|
16733
|
+
/* Wrapper inserted around an SVG sparkline at init time when its parent
|
|
16734
|
+
isn't already a positioned anchor — so the .pa-kpi-spark-dot can be
|
|
16735
|
+
absolutely positioned relative to the chart. */
|
|
16736
|
+
.pa-kpi-spark-wrap {
|
|
16737
|
+
display: block;
|
|
16738
|
+
position: relative;
|
|
16739
|
+
width: 100%;
|
|
16740
|
+
}
|
|
16741
|
+
|
|
16742
|
+
/* ----- Hover detail popover --------------------------------------------
|
|
16743
|
+
Bloomberg-dark by default regardless of host theme (terminal/data-dashboard
|
|
16744
|
+
aesthetic). Override the --pa-detail-* tokens at :root or .pa-kpi-detail
|
|
16745
|
+
level for a light/theme-aware variant.
|
|
16746
|
+
|
|
16747
|
+
Positioned by Floating UI anchored to a virtual element at the cursor —
|
|
16748
|
+
the JS appends each popover to <body> at init so ancestor overflow:hidden
|
|
16749
|
+
doesn't clip it. position: fixed because cursor coords are viewport-
|
|
16750
|
+
relative; pointer-events:none so the cursor passes through cleanly and
|
|
16751
|
+
tile mouseleave fires reliably. */
|
|
16752
|
+
.pa-kpi-detail {
|
|
16753
|
+
position: fixed;
|
|
16754
|
+
top: 0;
|
|
16755
|
+
left: 0;
|
|
16756
|
+
visibility: hidden;
|
|
16757
|
+
pointer-events: none;
|
|
16758
|
+
z-index: 9000;
|
|
16759
|
+
min-width: 26rem;
|
|
16760
|
+
max-width: 32rem;
|
|
16761
|
+
background: var(--pa-detail-bg);
|
|
16762
|
+
color: var(--pa-detail-text);
|
|
16763
|
+
padding: 1.2rem 1.5rem;
|
|
16764
|
+
font-family: var(--base-font-family-mono);
|
|
16765
|
+
font-size: 1.25rem;
|
|
16766
|
+
line-height: 1.5;
|
|
16767
|
+
border-radius: 0.4rem;
|
|
16768
|
+
box-shadow: var(--pa-detail-shadow);
|
|
16769
|
+
}
|
|
16770
|
+
.pa-kpi-detail[data-show] {
|
|
16771
|
+
visibility: visible;
|
|
16772
|
+
}
|
|
16773
|
+
.pa-kpi-detail__title {
|
|
16774
|
+
text-transform: uppercase;
|
|
16775
|
+
letter-spacing: 0.08em;
|
|
16776
|
+
font-size: 1.05rem;
|
|
16777
|
+
font-weight: 700;
|
|
16778
|
+
color: var(--pa-detail-title);
|
|
16779
|
+
margin-bottom: 0.6rem;
|
|
16780
|
+
}
|
|
16781
|
+
.pa-kpi-detail dl {
|
|
16782
|
+
display: grid;
|
|
16783
|
+
grid-template-columns: 1fr auto;
|
|
16784
|
+
gap: 0.35rem 1.6rem;
|
|
16785
|
+
margin: 0;
|
|
16786
|
+
}
|
|
16787
|
+
.pa-kpi-detail dt {
|
|
16788
|
+
margin: 0;
|
|
16789
|
+
color: var(--pa-detail-row-label);
|
|
16790
|
+
font-weight: 400;
|
|
16791
|
+
}
|
|
16792
|
+
.pa-kpi-detail dd {
|
|
16793
|
+
margin: 0;
|
|
16794
|
+
text-align: end;
|
|
16795
|
+
font-weight: 600;
|
|
16796
|
+
font-variant-numeric: tabular-nums;
|
|
16797
|
+
}
|
|
16798
|
+
.pa-kpi-detail {
|
|
16799
|
+
/* Inline sentiment hints for dd content (e.g. <dd>+12% <span class="pos">…</span></dd>) */
|
|
16800
|
+
}
|
|
16801
|
+
.pa-kpi-detail .pos {
|
|
16802
|
+
color: var(--pa-positive);
|
|
16803
|
+
}
|
|
16804
|
+
.pa-kpi-detail .neg {
|
|
16805
|
+
color: var(--pa-negative);
|
|
16806
|
+
}
|
|
16807
|
+
.pa-kpi-detail .warn {
|
|
16808
|
+
color: var(--pa-warning);
|
|
16809
|
+
}
|
|
16810
|
+
|
|
16811
|
+
/* ----- Section heading strip used outside card chrome -------------------
|
|
16812
|
+
The 7 showcases each render a "stress-test" section that places tiles
|
|
16813
|
+
directly inside .pa-col-* page-grid cells (no card wrapper). The strip
|
|
16814
|
+
above those layouts hosts a label or LIVE indicator at the row's end. */
|
|
16815
|
+
.pa-kpi-sectionhead {
|
|
16816
|
+
display: flex;
|
|
16817
|
+
justify-content: flex-end;
|
|
16818
|
+
align-items: center;
|
|
16819
|
+
gap: 1.6rem;
|
|
16820
|
+
margin-bottom: 1.2rem;
|
|
16821
|
+
}
|
|
16822
|
+
|
|
16823
|
+
/* ========================================
|
|
16824
|
+
KPI · Terminal grid
|
|
16825
|
+
Bloomberg-style dense panel: mono numbers, status pills, inline SVG
|
|
16826
|
+
sparklines, ▲▼ deltas, segmented view-mode toggle (VALUE/Δ%/TREND).
|
|
16827
|
+
Shared chrome (header, live, footer, detail popover, spark-dot) is in
|
|
16828
|
+
_kpi-base.scss.
|
|
16829
|
+
======================================== */
|
|
16830
|
+
/* ----- View-mode toggle (segmented button group) ------------------------ */
|
|
16831
|
+
.pa-kpi-terminal__controls {
|
|
16832
|
+
display: inline-flex;
|
|
16833
|
+
align-items: center;
|
|
16834
|
+
gap: 1.6rem;
|
|
16835
|
+
}
|
|
16836
|
+
|
|
16837
|
+
.pa-kpi-terminal__viewtoggle {
|
|
16838
|
+
display: inline-flex;
|
|
16839
|
+
border: 1px solid var(--pa-border-color);
|
|
16840
|
+
border-radius: 0.4rem;
|
|
16841
|
+
overflow: hidden;
|
|
16842
|
+
}
|
|
16843
|
+
|
|
16844
|
+
.pa-kpi-terminal__viewbtn {
|
|
16845
|
+
background: transparent;
|
|
16846
|
+
border: 0;
|
|
16847
|
+
color: var(--pa-text-color-2);
|
|
16848
|
+
padding: 0.4rem 1.1rem;
|
|
16849
|
+
font-family: var(--base-font-family-mono);
|
|
16850
|
+
font-size: 1.1rem;
|
|
16851
|
+
font-weight: 600;
|
|
16852
|
+
letter-spacing: 0.06em;
|
|
16853
|
+
cursor: pointer;
|
|
16854
|
+
transition: background-color 0.1s ease-out, color 0.1s ease-out;
|
|
16855
|
+
}
|
|
16856
|
+
.pa-kpi-terminal__viewbtn:hover {
|
|
16857
|
+
color: var(--pa-text-color-1);
|
|
16858
|
+
}
|
|
16859
|
+
.pa-kpi-terminal__viewbtn.is-active {
|
|
16860
|
+
background: var(--pa-text-color-1);
|
|
16861
|
+
color: var(--pa-card-bg);
|
|
16862
|
+
}
|
|
16863
|
+
|
|
16864
|
+
/* ----- Grid + tile borders ----------------------------------------------
|
|
16865
|
+
Hairline 1px borders between tiles, no gap. Last-row/last-column
|
|
16866
|
+
borders suppressed via :nth-last-child / :nth-child selectors. */
|
|
16867
|
+
.pa-kpi-terminal__body {
|
|
16868
|
+
padding: 0;
|
|
16869
|
+
}
|
|
16870
|
+
|
|
16871
|
+
.pa-kpi-terminal__grid {
|
|
16872
|
+
display: grid;
|
|
16873
|
+
grid-template-columns: repeat(2, 1fr);
|
|
16874
|
+
}
|
|
16875
|
+
.pa-kpi-terminal__grid .pa-kpi-tile {
|
|
16876
|
+
border-bottom: 1px solid var(--pa-border-color);
|
|
16877
|
+
border-right: 1px solid var(--pa-border-color);
|
|
16878
|
+
}
|
|
16879
|
+
|
|
16880
|
+
.pa-kpi-terminal__grid--2col .pa-kpi-tile:nth-child(2n) {
|
|
16881
|
+
border-right: 0;
|
|
16882
|
+
}
|
|
16883
|
+
.pa-kpi-terminal__grid--2col .pa-kpi-tile:nth-last-child(-n+2) {
|
|
16884
|
+
border-bottom: 0;
|
|
16885
|
+
}
|
|
16886
|
+
|
|
16887
|
+
/* ----- Tile (per-KPI panel) --------------------------------------------- */
|
|
16888
|
+
.pa-kpi-tile {
|
|
16889
|
+
position: relative;
|
|
16890
|
+
padding: 1.4rem 1.8rem 1.6rem;
|
|
16891
|
+
min-height: 16rem;
|
|
16892
|
+
display: flex;
|
|
16893
|
+
flex-direction: column;
|
|
16894
|
+
/* Standalone modifier: tile lives directly inside a .pa-col-* (no
|
|
16895
|
+
neighbour cells in a parent grid) — gets a full border + card bg so
|
|
16896
|
+
it doesn't look orphaned. */
|
|
16897
|
+
}
|
|
16898
|
+
.pa-kpi-tile--standalone {
|
|
16899
|
+
background: var(--pa-card-bg);
|
|
16900
|
+
border: 1px solid var(--pa-border-color);
|
|
16901
|
+
margin-bottom: 1.2rem;
|
|
16902
|
+
}
|
|
16903
|
+
.pa-kpi-tile--standalone:last-child {
|
|
16904
|
+
margin-bottom: 0;
|
|
16905
|
+
}
|
|
16906
|
+
|
|
16907
|
+
/* ----- Tile head: ID · period + status pill ----------------------------- */
|
|
16908
|
+
.pa-kpi-tile__head {
|
|
16909
|
+
display: flex;
|
|
16910
|
+
justify-content: space-between;
|
|
16911
|
+
align-items: center;
|
|
16912
|
+
font-family: var(--base-font-family-mono);
|
|
16913
|
+
font-size: 1.3rem;
|
|
16914
|
+
letter-spacing: 0.04em;
|
|
16915
|
+
margin-bottom: 0.3rem;
|
|
16916
|
+
}
|
|
16917
|
+
|
|
16918
|
+
.pa-kpi-tile__id {
|
|
16919
|
+
color: var(--pa-text-tertiary);
|
|
16920
|
+
font-weight: 600;
|
|
16921
|
+
}
|
|
16922
|
+
|
|
16923
|
+
.pa-kpi-tile__status {
|
|
16924
|
+
font-family: var(--base-font-family-mono);
|
|
16925
|
+
font-size: 1.2rem;
|
|
16926
|
+
font-weight: 700;
|
|
16927
|
+
letter-spacing: 0.08em;
|
|
16928
|
+
padding: 0.3rem 0.9rem;
|
|
16929
|
+
line-height: 1.3;
|
|
16930
|
+
}
|
|
16931
|
+
.pa-kpi-tile__status--warn {
|
|
16932
|
+
background: var(--pa-warning-bg);
|
|
16933
|
+
color: var(--pa-btn-warning-text);
|
|
16934
|
+
}
|
|
16935
|
+
.pa-kpi-tile__status {
|
|
16936
|
+
/* GOOD is the "default" state — text-only, no chrome */
|
|
16937
|
+
}
|
|
16938
|
+
.pa-kpi-tile__status--good {
|
|
16939
|
+
background: transparent;
|
|
16940
|
+
color: var(--pa-text-color-1);
|
|
16941
|
+
padding: 0.2rem 0;
|
|
16942
|
+
}
|
|
16943
|
+
.pa-kpi-tile__status--neutral {
|
|
16944
|
+
background: color-mix(in srgb, var(--pa-text-color-2) 25%, transparent);
|
|
16945
|
+
color: var(--pa-text-color-1);
|
|
16946
|
+
}
|
|
16947
|
+
|
|
16948
|
+
/* ----- Label ------------------------------------------------------------ */
|
|
16949
|
+
.pa-kpi-tile__label {
|
|
16950
|
+
font-family: var(--base-font-family-mono);
|
|
16951
|
+
font-size: 1.4rem;
|
|
16952
|
+
font-weight: 700;
|
|
16953
|
+
letter-spacing: 0.1em;
|
|
16954
|
+
text-transform: uppercase;
|
|
16955
|
+
color: var(--pa-text-strong);
|
|
16956
|
+
margin-bottom: 0.8rem;
|
|
16957
|
+
}
|
|
16958
|
+
|
|
16959
|
+
/* ----- Big value with 3-mode swap --------------------------------------
|
|
16960
|
+
Author renders three .pa-kpi-tile__value siblings (data-mode="value" /
|
|
16961
|
+
"delta" / "trend"); the active mode is selected via the
|
|
16962
|
+
.pa-kpi-terminal[data-view="X"] attribute. JS toggles that attribute
|
|
16963
|
+
when the segmented control is clicked. */
|
|
16964
|
+
.pa-kpi-tile__values {
|
|
16965
|
+
margin-bottom: 0.4rem;
|
|
16966
|
+
}
|
|
16967
|
+
|
|
16968
|
+
.pa-kpi-tile__value {
|
|
16969
|
+
display: none;
|
|
16970
|
+
align-items: baseline;
|
|
16971
|
+
gap: 0.3rem;
|
|
16972
|
+
font-family: var(--base-font-family-mono);
|
|
16973
|
+
line-height: 1;
|
|
16974
|
+
}
|
|
16975
|
+
.pa-kpi-tile__value--very-positive .pa-kpi-tile__num {
|
|
16976
|
+
color: var(--pa-very-positive);
|
|
16977
|
+
}
|
|
16978
|
+
.pa-kpi-tile__value--positive .pa-kpi-tile__num {
|
|
16979
|
+
color: var(--pa-positive);
|
|
16980
|
+
}
|
|
16981
|
+
.pa-kpi-tile__value--neutral .pa-kpi-tile__num {
|
|
16982
|
+
color: var(--pa-neutral);
|
|
16983
|
+
}
|
|
16984
|
+
.pa-kpi-tile__value--negative .pa-kpi-tile__num {
|
|
16985
|
+
color: var(--pa-negative);
|
|
16986
|
+
}
|
|
16987
|
+
.pa-kpi-tile__value--very-negative .pa-kpi-tile__num {
|
|
16988
|
+
color: var(--pa-very-negative);
|
|
16989
|
+
}
|
|
16990
|
+
|
|
16991
|
+
.pa-kpi-terminal[data-view=value] .pa-kpi-tile__value[data-mode=value],
|
|
16992
|
+
.pa-kpi-terminal[data-view=delta] .pa-kpi-tile__value[data-mode=delta],
|
|
16993
|
+
.pa-kpi-terminal[data-view=trend] .pa-kpi-tile__value[data-mode=trend] {
|
|
16994
|
+
display: inline-flex;
|
|
16995
|
+
}
|
|
16996
|
+
|
|
16997
|
+
.pa-kpi-tile__num {
|
|
16998
|
+
font-size: 3.8rem;
|
|
16999
|
+
font-weight: 700;
|
|
17000
|
+
letter-spacing: -0.02em;
|
|
17001
|
+
color: var(--pa-text-color-1);
|
|
17002
|
+
}
|
|
17003
|
+
|
|
17004
|
+
.pa-kpi-tile__unit {
|
|
17005
|
+
font-size: 1.6rem;
|
|
17006
|
+
font-weight: 500;
|
|
17007
|
+
color: var(--pa-text-secondary);
|
|
17008
|
+
}
|
|
17009
|
+
|
|
17010
|
+
/* ----- Previous-value + delta row -------------------------------------- */
|
|
17011
|
+
.pa-kpi-tile__prev {
|
|
17012
|
+
display: flex;
|
|
17013
|
+
justify-content: space-between;
|
|
17014
|
+
align-items: center;
|
|
17015
|
+
font-family: var(--base-font-family-mono);
|
|
17016
|
+
font-size: 1.3rem;
|
|
17017
|
+
margin-top: auto; /* push to bottom of flex column */
|
|
17018
|
+
margin-bottom: 0.4rem;
|
|
17019
|
+
color: var(--pa-text-tertiary);
|
|
17020
|
+
}
|
|
17021
|
+
|
|
17022
|
+
.pa-kpi-tile__delta--very-positive {
|
|
17023
|
+
color: var(--pa-very-positive);
|
|
17024
|
+
}
|
|
17025
|
+
.pa-kpi-tile__delta--positive {
|
|
17026
|
+
color: var(--pa-positive);
|
|
17027
|
+
}
|
|
17028
|
+
.pa-kpi-tile__delta--neutral {
|
|
17029
|
+
color: var(--pa-neutral);
|
|
17030
|
+
}
|
|
17031
|
+
.pa-kpi-tile__delta--negative {
|
|
17032
|
+
color: var(--pa-negative);
|
|
17033
|
+
}
|
|
17034
|
+
.pa-kpi-tile__delta--very-negative {
|
|
17035
|
+
color: var(--pa-very-negative);
|
|
17036
|
+
}
|
|
17037
|
+
|
|
17038
|
+
/* ----- Sparkline -------------------------------------------------------- */
|
|
17039
|
+
.pa-kpi-tile__spark {
|
|
17040
|
+
display: block;
|
|
17041
|
+
width: 100%;
|
|
17042
|
+
height: var(--pa-chart-trendline-height);
|
|
17043
|
+
overflow: visible;
|
|
17044
|
+
}
|
|
17045
|
+
.pa-kpi-tile__spark polyline {
|
|
17046
|
+
fill: none;
|
|
17047
|
+
stroke: currentColor;
|
|
17048
|
+
stroke-width: var(--pa-chart-trendline-stroke);
|
|
17049
|
+
stroke-linecap: round;
|
|
17050
|
+
stroke-linejoin: round;
|
|
17051
|
+
}
|
|
17052
|
+
|
|
17053
|
+
/* Sentiment-coloured sparkline. Class names use up/down wording but pick
|
|
17054
|
+
colours from the sentiment-of-the-change axis, not line shape — so an
|
|
17055
|
+
error-rate metric whose line is falling but the change is good uses
|
|
17056
|
+
--up. See showcase docs for the rationale. Colour is set on both the
|
|
17057
|
+
SVG and the JS-inserted .pa-kpi-spark-wrap so currentColor resolves
|
|
17058
|
+
for the SVG content (line) and the HTML dot (inside the wrap). */
|
|
17059
|
+
.pa-kpi-tile--up-strong .pa-kpi-tile__spark, .pa-kpi-tile--up-strong .pa-kpi-spark-wrap {
|
|
17060
|
+
color: var(--pa-very-positive);
|
|
17061
|
+
}
|
|
17062
|
+
.pa-kpi-tile--up .pa-kpi-tile__spark, .pa-kpi-tile--up .pa-kpi-spark-wrap {
|
|
17063
|
+
color: var(--pa-positive);
|
|
17064
|
+
}
|
|
17065
|
+
.pa-kpi-tile--flat .pa-kpi-tile__spark, .pa-kpi-tile--flat .pa-kpi-spark-wrap {
|
|
17066
|
+
color: var(--pa-neutral);
|
|
17067
|
+
}
|
|
17068
|
+
.pa-kpi-tile--down .pa-kpi-tile__spark, .pa-kpi-tile--down .pa-kpi-spark-wrap {
|
|
17069
|
+
color: var(--pa-negative);
|
|
17070
|
+
}
|
|
17071
|
+
.pa-kpi-tile--down-strong .pa-kpi-tile__spark, .pa-kpi-tile--down-strong .pa-kpi-spark-wrap {
|
|
17072
|
+
color: var(--pa-very-negative);
|
|
17073
|
+
}
|
|
17074
|
+
|
|
17075
|
+
/* ========================================
|
|
17076
|
+
KPI · Sparkline list
|
|
17077
|
+
Each KPI is one row: label · sparkline · value · Δ%. Built for vertical
|
|
17078
|
+
scanning rather than per-tile depth — no view-mode toggle, no status
|
|
17079
|
+
pills. Container queries collapse 4-col → 2-row → 3-row as the card
|
|
17080
|
+
narrows.
|
|
17081
|
+
======================================== */
|
|
17082
|
+
/* Card is a query container so rows react to *card* width, not viewport. */
|
|
17083
|
+
.pa-kpi-spark-list {
|
|
17084
|
+
container-type: inline-size;
|
|
17085
|
+
}
|
|
17086
|
+
|
|
17087
|
+
.pa-kpi-spark-list__body {
|
|
17088
|
+
padding: 0;
|
|
17089
|
+
}
|
|
17090
|
+
|
|
17091
|
+
/* ----- Row: wide 4-column grid (label · chart · value · delta) ---------- */
|
|
17092
|
+
.pa-kpi-spark-row {
|
|
17093
|
+
display: grid;
|
|
17094
|
+
grid-template-columns: minmax(14rem, 28%) minmax(10rem, 1fr) minmax(8rem, 18%) minmax(7rem, 12%);
|
|
17095
|
+
align-items: center;
|
|
17096
|
+
gap: 1.6rem;
|
|
17097
|
+
padding: 1.4rem 2rem;
|
|
17098
|
+
border-bottom: 1px solid var(--pa-border-color);
|
|
17099
|
+
}
|
|
17100
|
+
.pa-kpi-spark-row:last-child {
|
|
17101
|
+
border-bottom: 0;
|
|
17102
|
+
}
|
|
17103
|
+
|
|
17104
|
+
/* Mid-narrow card (1×3 page-grid + 45% column): stack to 2 rows.
|
|
17105
|
+
Label/value/delta on top, full-width chart below. Default order is
|
|
17106
|
+
value-above-chart; use .pa-kpi-spark-list--chart-first to flip. */
|
|
17107
|
+
@container (max-width: 640px) {
|
|
17108
|
+
.pa-kpi-spark-row {
|
|
17109
|
+
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
17110
|
+
grid-template-rows: auto auto;
|
|
17111
|
+
grid-template-areas: "label value delta" "chart chart chart";
|
|
17112
|
+
column-gap: 1.2rem;
|
|
17113
|
+
row-gap: 0.4rem;
|
|
17114
|
+
align-items: baseline;
|
|
17115
|
+
padding: 1.2rem 1.6rem;
|
|
17116
|
+
}
|
|
17117
|
+
.pa-kpi-spark-row__label {
|
|
17118
|
+
grid-area: label;
|
|
17119
|
+
align-self: center;
|
|
17120
|
+
font-size: 1.25rem;
|
|
17121
|
+
}
|
|
17122
|
+
.pa-kpi-spark-row__value {
|
|
17123
|
+
grid-area: value;
|
|
17124
|
+
}
|
|
17125
|
+
.pa-kpi-spark-row__delta {
|
|
17126
|
+
grid-area: delta;
|
|
17127
|
+
font-size: 1.25rem;
|
|
17128
|
+
}
|
|
17129
|
+
.pa-kpi-spark-row__chart {
|
|
17130
|
+
grid-area: chart;
|
|
17131
|
+
}
|
|
17132
|
+
.pa-kpi-spark-row__num {
|
|
17133
|
+
font-size: 2rem;
|
|
17134
|
+
}
|
|
17135
|
+
/* --chart-first: rotates the canonical L→R order 90°. Label on top,
|
|
17136
|
+
chart in the middle, value+delta side-by-side at the bottom. */
|
|
17137
|
+
.pa-kpi-spark-list--chart-first .pa-kpi-spark-row {
|
|
17138
|
+
grid-template-columns: 1fr auto;
|
|
17139
|
+
grid-template-rows: auto auto auto;
|
|
17140
|
+
grid-template-areas: "label label" "chart chart" "value delta";
|
|
17141
|
+
row-gap: 0.5rem;
|
|
17142
|
+
column-gap: 1rem;
|
|
17143
|
+
padding: 1.2rem 1.6rem;
|
|
17144
|
+
}
|
|
17145
|
+
.pa-kpi-spark-list--chart-first .pa-kpi-spark-row__label {
|
|
17146
|
+
align-self: start;
|
|
17147
|
+
}
|
|
17148
|
+
.pa-kpi-spark-list--chart-first .pa-kpi-spark-row__value {
|
|
17149
|
+
text-align: start;
|
|
17150
|
+
align-self: baseline;
|
|
17151
|
+
}
|
|
17152
|
+
.pa-kpi-spark-list--chart-first .pa-kpi-spark-row__delta {
|
|
17153
|
+
align-self: baseline;
|
|
17154
|
+
}
|
|
17155
|
+
}
|
|
17156
|
+
/* Very narrow card (~280–360px, 25% page-grid stress test): force the
|
|
17157
|
+
chart-first 3-row layout regardless of modifier. */
|
|
17158
|
+
@container (max-width: 360px) {
|
|
17159
|
+
.pa-kpi-spark-row {
|
|
17160
|
+
grid-template-columns: 1fr auto;
|
|
17161
|
+
grid-template-rows: auto auto auto;
|
|
17162
|
+
grid-template-areas: "label label" "chart chart" "value delta";
|
|
17163
|
+
row-gap: 0.5rem;
|
|
17164
|
+
column-gap: 1rem;
|
|
17165
|
+
padding: 1.2rem 1.4rem;
|
|
17166
|
+
}
|
|
17167
|
+
.pa-kpi-spark-row__label {
|
|
17168
|
+
grid-area: label;
|
|
17169
|
+
align-self: start;
|
|
17170
|
+
}
|
|
17171
|
+
.pa-kpi-spark-row__chart {
|
|
17172
|
+
grid-area: chart;
|
|
17173
|
+
}
|
|
17174
|
+
.pa-kpi-spark-row__value {
|
|
17175
|
+
grid-area: value;
|
|
17176
|
+
text-align: start;
|
|
17177
|
+
align-self: baseline;
|
|
17178
|
+
}
|
|
17179
|
+
.pa-kpi-spark-row__delta {
|
|
17180
|
+
grid-area: delta;
|
|
17181
|
+
align-self: baseline;
|
|
17182
|
+
}
|
|
17183
|
+
}
|
|
17184
|
+
/* ----- Cell typography -------------------------------------------------- */
|
|
17185
|
+
.pa-kpi-spark-row__label {
|
|
17186
|
+
font-family: var(--base-font-family-mono);
|
|
17187
|
+
font-size: 1.4rem;
|
|
17188
|
+
font-weight: 700;
|
|
17189
|
+
letter-spacing: 0.1em;
|
|
17190
|
+
text-transform: uppercase;
|
|
17191
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 60%, transparent);
|
|
17192
|
+
}
|
|
17193
|
+
|
|
17194
|
+
/* Sparkline cell — line + filled area + trailing dot (the dot is rendered
|
|
17195
|
+
as a CSS span by the JS init pass; see kpi-showcases.js). */
|
|
17196
|
+
.pa-kpi-spark-row__chart {
|
|
17197
|
+
position: relative; /* anchor for .pa-kpi-spark-dot */
|
|
17198
|
+
}
|
|
17199
|
+
.pa-kpi-spark-row__chart svg {
|
|
17200
|
+
display: block;
|
|
17201
|
+
width: 100%;
|
|
17202
|
+
height: var(--pa-chart-trendline-height);
|
|
17203
|
+
overflow: visible;
|
|
17204
|
+
}
|
|
17205
|
+
.pa-kpi-spark-row__chart polyline {
|
|
17206
|
+
fill: none;
|
|
17207
|
+
stroke: currentColor;
|
|
17208
|
+
stroke-width: var(--pa-chart-trendline-stroke);
|
|
17209
|
+
stroke-linecap: round;
|
|
17210
|
+
stroke-linejoin: round;
|
|
17211
|
+
}
|
|
17212
|
+
.pa-kpi-spark-row__chart polygon {
|
|
17213
|
+
fill: currentColor;
|
|
17214
|
+
fill-opacity: 0.18; /* same hue as line, soft area shading */
|
|
17215
|
+
stroke: none;
|
|
17216
|
+
}
|
|
17217
|
+
|
|
17218
|
+
/* Sentiment-coloured sparkline. Color is set on the chart wrapper so
|
|
17219
|
+
currentColor resolves for both the SVG content (line/area) and the
|
|
17220
|
+
dot inside the wrapper. */
|
|
17221
|
+
.pa-kpi-spark-row--up-strong .pa-kpi-spark-row__chart {
|
|
17222
|
+
color: var(--pa-very-positive);
|
|
17223
|
+
}
|
|
17224
|
+
.pa-kpi-spark-row--up .pa-kpi-spark-row__chart {
|
|
17225
|
+
color: var(--pa-positive);
|
|
17226
|
+
}
|
|
17227
|
+
.pa-kpi-spark-row--flat .pa-kpi-spark-row__chart {
|
|
17228
|
+
color: var(--pa-neutral);
|
|
17229
|
+
}
|
|
17230
|
+
.pa-kpi-spark-row--down .pa-kpi-spark-row__chart {
|
|
17231
|
+
color: var(--pa-negative);
|
|
17232
|
+
}
|
|
17233
|
+
.pa-kpi-spark-row--down-strong .pa-kpi-spark-row__chart {
|
|
17234
|
+
color: var(--pa-very-negative);
|
|
17235
|
+
}
|
|
17236
|
+
|
|
17237
|
+
/* ----- Value (focal white number + muted unit) ------------------------- */
|
|
17238
|
+
.pa-kpi-spark-row__value {
|
|
17239
|
+
font-family: var(--base-font-family-mono);
|
|
17240
|
+
text-align: end;
|
|
17241
|
+
line-height: 1;
|
|
17242
|
+
}
|
|
17243
|
+
|
|
17244
|
+
.pa-kpi-spark-row__num {
|
|
17245
|
+
font-size: 2.6rem;
|
|
17246
|
+
font-weight: 700;
|
|
17247
|
+
letter-spacing: -0.02em;
|
|
17248
|
+
color: var(--pa-text-color-1);
|
|
17249
|
+
}
|
|
17250
|
+
|
|
17251
|
+
.pa-kpi-spark-row__unit {
|
|
17252
|
+
font-size: 1.3rem;
|
|
17253
|
+
font-weight: 500;
|
|
17254
|
+
color: var(--pa-text-secondary);
|
|
17255
|
+
margin-left: 0.2rem;
|
|
17256
|
+
}
|
|
17257
|
+
|
|
17258
|
+
/* ----- Delta (sentiment-coloured) -------------------------------------- */
|
|
17259
|
+
.pa-kpi-spark-row__delta {
|
|
17260
|
+
font-family: var(--base-font-family-mono);
|
|
17261
|
+
font-size: 1.4rem;
|
|
17262
|
+
font-weight: 600;
|
|
17263
|
+
text-align: end;
|
|
17264
|
+
font-variant-numeric: tabular-nums;
|
|
17265
|
+
}
|
|
17266
|
+
.pa-kpi-spark-row__delta--very-positive {
|
|
17267
|
+
color: var(--pa-very-positive);
|
|
17268
|
+
}
|
|
17269
|
+
.pa-kpi-spark-row__delta--positive {
|
|
17270
|
+
color: var(--pa-positive);
|
|
17271
|
+
}
|
|
17272
|
+
.pa-kpi-spark-row__delta--neutral {
|
|
17273
|
+
color: var(--pa-neutral);
|
|
17274
|
+
}
|
|
17275
|
+
.pa-kpi-spark-row__delta--negative {
|
|
17276
|
+
color: var(--pa-negative);
|
|
17277
|
+
}
|
|
17278
|
+
.pa-kpi-spark-row__delta--very-negative {
|
|
17279
|
+
color: var(--pa-very-negative);
|
|
17280
|
+
}
|
|
17281
|
+
|
|
17282
|
+
/* ========================================
|
|
17283
|
+
KPI · Comparison gauges
|
|
17284
|
+
Goal-oriented progress bars. Each KPI shows label · value, a bar with a
|
|
17285
|
+
target tick, and a 0 · tgt scale below. Bar fill = value/target * 100%,
|
|
17286
|
+
capped visually so overshoots are signalled by colour, not overflow.
|
|
17287
|
+
======================================== */
|
|
17288
|
+
.pa-kpi-gauge-list {
|
|
17289
|
+
container-type: inline-size;
|
|
17290
|
+
}
|
|
17291
|
+
|
|
17292
|
+
.pa-kpi-gauge-list__body {
|
|
17293
|
+
padding: 0;
|
|
17294
|
+
}
|
|
17295
|
+
|
|
17296
|
+
/* 2-column internal grid by default; collapses to 1-col when card narrows. */
|
|
17297
|
+
.pa-kpi-gauge-list__grid {
|
|
17298
|
+
display: grid;
|
|
17299
|
+
grid-template-columns: repeat(2, 1fr);
|
|
17300
|
+
}
|
|
17301
|
+
|
|
17302
|
+
@container (max-width: 600px) {
|
|
17303
|
+
.pa-kpi-gauge-list__grid {
|
|
17304
|
+
grid-template-columns: 1fr;
|
|
17305
|
+
}
|
|
17306
|
+
}
|
|
17307
|
+
/* ----- Gauge tile (label/value head · bar · 0/tgt scale) ---------------- */
|
|
17308
|
+
.pa-kpi-gauge {
|
|
17309
|
+
position: relative;
|
|
17310
|
+
padding: 1.6rem 2rem;
|
|
17311
|
+
border-bottom: 1px solid var(--pa-border-color);
|
|
17312
|
+
border-right: 1px solid var(--pa-border-color);
|
|
17313
|
+
/* Per-tile bar colour cascade — modifiers below set the var, the fill
|
|
17314
|
+
reads it. Cleaner than per-modifier-per-element rules; host apps can
|
|
17315
|
+
override at the tile level via inline style="--pa-kpi-bar-color: …". */
|
|
17316
|
+
--pa-kpi-bar-color: var(--pa-positive);
|
|
17317
|
+
}
|
|
17318
|
+
.pa-kpi-gauge:nth-child(2n) {
|
|
17319
|
+
border-right: 0;
|
|
17320
|
+
}
|
|
17321
|
+
.pa-kpi-gauge:nth-last-child(-n+2) {
|
|
17322
|
+
border-bottom: 0;
|
|
17323
|
+
}
|
|
17324
|
+
.pa-kpi-gauge--positive {
|
|
17325
|
+
--pa-kpi-bar-color: var(--pa-positive);
|
|
17326
|
+
}
|
|
17327
|
+
.pa-kpi-gauge--warning {
|
|
17328
|
+
--pa-kpi-bar-color: var(--pa-warning);
|
|
17329
|
+
}
|
|
17330
|
+
.pa-kpi-gauge--negative {
|
|
17331
|
+
--pa-kpi-bar-color: var(--pa-negative);
|
|
17332
|
+
}
|
|
17333
|
+
.pa-kpi-gauge--neutral {
|
|
17334
|
+
--pa-kpi-bar-color: color-mix(in srgb, var(--pa-text-color-1) 70%, transparent);
|
|
17335
|
+
}
|
|
17336
|
+
|
|
17337
|
+
@container (max-width: 600px) {
|
|
17338
|
+
.pa-kpi-gauge {
|
|
17339
|
+
border-right: 0;
|
|
17340
|
+
}
|
|
17341
|
+
.pa-kpi-gauge:nth-last-child(-n+2) {
|
|
17342
|
+
border-bottom: 1px solid var(--pa-border-color);
|
|
17343
|
+
}
|
|
17344
|
+
.pa-kpi-gauge:last-child {
|
|
17345
|
+
border-bottom: 0;
|
|
17346
|
+
}
|
|
17347
|
+
}
|
|
17348
|
+
/* ----- Head: label left, value right (baseline-aligned) ----------------- */
|
|
17349
|
+
.pa-kpi-gauge__head {
|
|
17350
|
+
display: flex;
|
|
17351
|
+
justify-content: space-between;
|
|
17352
|
+
align-items: baseline;
|
|
17353
|
+
gap: 1.2rem;
|
|
17354
|
+
margin-bottom: 0.8rem;
|
|
17355
|
+
}
|
|
17356
|
+
|
|
17357
|
+
.pa-kpi-gauge__label {
|
|
17358
|
+
font-family: var(--base-font-family-mono);
|
|
17359
|
+
font-size: 1.4rem;
|
|
17360
|
+
font-weight: 700;
|
|
17361
|
+
letter-spacing: 0.1em;
|
|
17362
|
+
text-transform: uppercase;
|
|
17363
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 60%, transparent);
|
|
17364
|
+
}
|
|
17365
|
+
|
|
17366
|
+
.pa-kpi-gauge__value {
|
|
17367
|
+
font-family: var(--base-font-family-mono);
|
|
17368
|
+
line-height: 1;
|
|
17369
|
+
}
|
|
17370
|
+
|
|
17371
|
+
.pa-kpi-gauge__num {
|
|
17372
|
+
font-size: 2.6rem;
|
|
17373
|
+
font-weight: 700;
|
|
17374
|
+
letter-spacing: -0.02em;
|
|
17375
|
+
color: var(--pa-text-color-1);
|
|
17376
|
+
}
|
|
17377
|
+
|
|
17378
|
+
.pa-kpi-gauge__unit {
|
|
17379
|
+
font-size: 1.3rem;
|
|
17380
|
+
font-weight: 500;
|
|
17381
|
+
color: var(--pa-text-secondary);
|
|
17382
|
+
margin-left: 0.2rem;
|
|
17383
|
+
}
|
|
17384
|
+
|
|
17385
|
+
/* ----- Bar (track + sentiment-coloured fill + target tick) -------------- */
|
|
17386
|
+
.pa-kpi-gauge__bar {
|
|
17387
|
+
/* Author-controlled tick position (default 100% — the target sits at the
|
|
17388
|
+
right edge of the bar's "0 → target" scale). Override per-tile via
|
|
17389
|
+
style="--pa-kpi-gauge-tick-pos: 80%" if the bar represents a wider
|
|
17390
|
+
scale where the target sits inside the bar. */
|
|
17391
|
+
--pa-kpi-gauge-tick-pos: 100%;
|
|
17392
|
+
--pa-kpi-gauge-tick-color: var(--pa-text-color-1);
|
|
17393
|
+
position: relative;
|
|
17394
|
+
height: 0.7rem;
|
|
17395
|
+
background: var(--pa-surface-track);
|
|
17396
|
+
margin-bottom: 0.5rem;
|
|
17397
|
+
overflow: visible; /* tick can sit just outside the track */
|
|
17398
|
+
/* Target tick — small bar slightly taller than the track. Centred on
|
|
17399
|
+
--pa-kpi-gauge-tick-pos via the negative margin-left (matches half
|
|
17400
|
+
the tick width). Full opacity so it stays readable on dark themes
|
|
17401
|
+
against bright orange/green fills. */
|
|
17402
|
+
}
|
|
17403
|
+
.pa-kpi-gauge__bar::after {
|
|
17404
|
+
content: "";
|
|
17405
|
+
position: absolute;
|
|
17406
|
+
left: var(--pa-kpi-gauge-tick-pos);
|
|
17407
|
+
margin-left: -0.15rem;
|
|
17408
|
+
top: -0.2rem;
|
|
17409
|
+
bottom: -0.2rem;
|
|
17410
|
+
width: 0.3rem;
|
|
17411
|
+
background: var(--pa-kpi-gauge-tick-color);
|
|
17412
|
+
}
|
|
17413
|
+
|
|
17414
|
+
.pa-kpi-gauge__fill {
|
|
17415
|
+
height: 100%;
|
|
17416
|
+
background: var(--pa-kpi-bar-color);
|
|
17417
|
+
/* Width set inline per tile via style="width: X%". */
|
|
17418
|
+
transition: width 0.3s ease;
|
|
17419
|
+
}
|
|
17420
|
+
|
|
17421
|
+
/* ----- Scale row (0 left · tgt XYZ right) ------------------------------- */
|
|
17422
|
+
.pa-kpi-gauge__scale {
|
|
17423
|
+
display: flex;
|
|
17424
|
+
justify-content: space-between;
|
|
17425
|
+
font-family: var(--base-font-family-mono);
|
|
17426
|
+
font-size: 1.2rem;
|
|
17427
|
+
color: var(--pa-text-tertiary);
|
|
17428
|
+
}
|
|
17429
|
+
|
|
17430
|
+
/* ========================================
|
|
17431
|
+
KPI · Hero + supporting
|
|
17432
|
+
Marketing/exec dashboard pattern: one headline metric on the left (huge
|
|
17433
|
+
container-query-relative value, inline meta row, big filled-area
|
|
17434
|
+
sparkline), and a vertical rail of compact supporting tiles on the
|
|
17435
|
+
right. Container query collapses to single column on narrow cards.
|
|
17436
|
+
======================================== */
|
|
17437
|
+
.pa-kpi-hero-list {
|
|
17438
|
+
container-type: inline-size;
|
|
17439
|
+
}
|
|
17440
|
+
|
|
17441
|
+
.pa-kpi-hero-list__body {
|
|
17442
|
+
padding: 1.6rem;
|
|
17443
|
+
}
|
|
17444
|
+
|
|
17445
|
+
/* ----- Layout: hero left, rail right ------------------------------------ */
|
|
17446
|
+
.pa-kpi-hero-list__layout {
|
|
17447
|
+
display: grid;
|
|
17448
|
+
grid-template-columns: 1fr 1fr;
|
|
17449
|
+
gap: 1.4rem;
|
|
17450
|
+
}
|
|
17451
|
+
|
|
17452
|
+
@container (max-width: 700px) {
|
|
17453
|
+
.pa-kpi-hero-list__layout {
|
|
17454
|
+
grid-template-columns: 1fr;
|
|
17455
|
+
}
|
|
17456
|
+
}
|
|
17457
|
+
.pa-kpi-hero-list__rail {
|
|
17458
|
+
display: flex;
|
|
17459
|
+
flex-direction: column;
|
|
17460
|
+
gap: 1rem;
|
|
17461
|
+
}
|
|
17462
|
+
|
|
17463
|
+
/* ----- HERO panel (label · big value · meta row · sparkline) ------------ */
|
|
17464
|
+
.pa-kpi-hero-main {
|
|
17465
|
+
position: relative;
|
|
17466
|
+
padding: 1.8rem 2rem;
|
|
17467
|
+
border: 1px solid var(--pa-border-color);
|
|
17468
|
+
display: flex;
|
|
17469
|
+
flex-direction: column;
|
|
17470
|
+
gap: 0.6rem;
|
|
17471
|
+
/* Sentiment cascade — chart and delta inherit via currentColor. */
|
|
17472
|
+
--pa-kpi-accent: var(--pa-positive);
|
|
17473
|
+
}
|
|
17474
|
+
.pa-kpi-hero-main--positive {
|
|
17475
|
+
--pa-kpi-accent: var(--pa-positive);
|
|
17476
|
+
}
|
|
17477
|
+
.pa-kpi-hero-main--negative {
|
|
17478
|
+
--pa-kpi-accent: var(--pa-negative);
|
|
17479
|
+
}
|
|
17480
|
+
.pa-kpi-hero-main--neutral {
|
|
17481
|
+
--pa-kpi-accent: var(--pa-neutral);
|
|
17482
|
+
}
|
|
17483
|
+
.pa-kpi-hero-main--up-strong {
|
|
17484
|
+
--pa-kpi-accent: var(--pa-very-positive);
|
|
17485
|
+
}
|
|
17486
|
+
|
|
17487
|
+
.pa-kpi-hero-main__label {
|
|
17488
|
+
font-family: var(--base-font-family-mono);
|
|
17489
|
+
font-size: 1.4rem;
|
|
17490
|
+
font-weight: 700;
|
|
17491
|
+
letter-spacing: 0.1em;
|
|
17492
|
+
text-transform: uppercase;
|
|
17493
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 60%, transparent);
|
|
17494
|
+
}
|
|
17495
|
+
|
|
17496
|
+
.pa-kpi-hero-main__value {
|
|
17497
|
+
display: inline-flex;
|
|
17498
|
+
align-items: baseline;
|
|
17499
|
+
font-family: var(--base-font-family-mono);
|
|
17500
|
+
line-height: 1;
|
|
17501
|
+
margin: 0.4rem 0 0.6rem;
|
|
17502
|
+
}
|
|
17503
|
+
|
|
17504
|
+
.pa-kpi-hero-main__num {
|
|
17505
|
+
/* Container-query-relative: scales with the hero panel's width.
|
|
17506
|
+
Floor keeps it readable in narrow page-grid cards. */
|
|
17507
|
+
font-size: clamp(4rem, 17cqi, 7rem);
|
|
17508
|
+
font-weight: 700;
|
|
17509
|
+
letter-spacing: -0.02em;
|
|
17510
|
+
color: var(--pa-text-color-1);
|
|
17511
|
+
}
|
|
17512
|
+
|
|
17513
|
+
.pa-kpi-hero-main__unit {
|
|
17514
|
+
font-size: clamp(1.8rem, 8cqi, 3rem);
|
|
17515
|
+
font-weight: 500;
|
|
17516
|
+
color: var(--pa-text-secondary);
|
|
17517
|
+
margin: 0 0.1rem;
|
|
17518
|
+
}
|
|
17519
|
+
|
|
17520
|
+
/* Meta row: inline delta + period text + target on one baseline. */
|
|
17521
|
+
.pa-kpi-hero-main__meta {
|
|
17522
|
+
display: grid;
|
|
17523
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
17524
|
+
align-items: baseline;
|
|
17525
|
+
gap: 0.4rem 1.4rem;
|
|
17526
|
+
font-family: var(--base-font-family-mono);
|
|
17527
|
+
font-size: 1.3rem;
|
|
17528
|
+
}
|
|
17529
|
+
|
|
17530
|
+
.pa-kpi-hero-main__delta {
|
|
17531
|
+
display: inline-flex;
|
|
17532
|
+
align-items: baseline;
|
|
17533
|
+
gap: 0.4rem;
|
|
17534
|
+
color: var(--pa-kpi-accent);
|
|
17535
|
+
font-weight: 700;
|
|
17536
|
+
font-size: 1.5rem;
|
|
17537
|
+
line-height: 1.2;
|
|
17538
|
+
}
|
|
17539
|
+
|
|
17540
|
+
.pa-kpi-hero-main__period {
|
|
17541
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 60%, transparent);
|
|
17542
|
+
line-height: 1.3;
|
|
17543
|
+
}
|
|
17544
|
+
|
|
17545
|
+
.pa-kpi-hero-main__target {
|
|
17546
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 50%, transparent);
|
|
17547
|
+
text-align: end;
|
|
17548
|
+
}
|
|
17549
|
+
|
|
17550
|
+
/* Hero sparkline — chart container fills extra vertical space (when the
|
|
17551
|
+
rail forces a tall row); SVG inside stays at fixed pixel height so the
|
|
17552
|
+
line shape is never distorted along Y. The SVG uses
|
|
17553
|
+
preserveAspectRatio="none", so any element that should keep its shape
|
|
17554
|
+
needs to live outside that scaling or have fixed pixel dimensions. */
|
|
17555
|
+
.pa-kpi-hero-main__chart {
|
|
17556
|
+
flex: 1 1 10rem;
|
|
17557
|
+
min-height: 10rem;
|
|
17558
|
+
margin-top: 0.6rem;
|
|
17559
|
+
color: var(--pa-kpi-accent);
|
|
17560
|
+
display: flex;
|
|
17561
|
+
align-items: flex-end; /* SVG wrap pinned to bottom */
|
|
17562
|
+
}
|
|
17563
|
+
.pa-kpi-hero-main__chart polyline {
|
|
17564
|
+
fill: none;
|
|
17565
|
+
stroke: currentColor;
|
|
17566
|
+
stroke-width: var(--pa-chart-trendline-stroke);
|
|
17567
|
+
stroke-linecap: round;
|
|
17568
|
+
stroke-linejoin: round;
|
|
17569
|
+
}
|
|
17570
|
+
.pa-kpi-hero-main__chart polygon {
|
|
17571
|
+
fill: currentColor;
|
|
17572
|
+
fill-opacity: 0.18;
|
|
17573
|
+
stroke: none;
|
|
17574
|
+
}
|
|
17575
|
+
|
|
17576
|
+
.pa-kpi-hero-main__chart-svg {
|
|
17577
|
+
position: relative;
|
|
17578
|
+
display: block;
|
|
17579
|
+
width: 100%;
|
|
17580
|
+
height: var(--pa-chart-trendline-height);
|
|
17581
|
+
}
|
|
17582
|
+
.pa-kpi-hero-main__chart-svg svg {
|
|
17583
|
+
display: block;
|
|
17584
|
+
width: 100%;
|
|
17585
|
+
height: 100%;
|
|
17586
|
+
overflow: visible;
|
|
17587
|
+
}
|
|
17588
|
+
|
|
17589
|
+
/* ----- SIDE rail tile (2×2 grid, value spans both rows on right) -------- */
|
|
17590
|
+
.pa-kpi-hero-side {
|
|
17591
|
+
position: relative;
|
|
17592
|
+
padding: 1.2rem 1.4rem;
|
|
17593
|
+
border: 1px solid var(--pa-border-color);
|
|
17594
|
+
display: grid;
|
|
17595
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
17596
|
+
grid-template-areas: "label value" "delta value";
|
|
17597
|
+
column-gap: 1.2rem;
|
|
17598
|
+
row-gap: 0.4rem;
|
|
17599
|
+
align-items: center;
|
|
17600
|
+
--pa-kpi-accent: var(--pa-positive);
|
|
17601
|
+
}
|
|
17602
|
+
.pa-kpi-hero-side--positive {
|
|
17603
|
+
--pa-kpi-accent: var(--pa-positive);
|
|
17604
|
+
}
|
|
17605
|
+
.pa-kpi-hero-side--negative {
|
|
17606
|
+
--pa-kpi-accent: var(--pa-negative);
|
|
17607
|
+
}
|
|
17608
|
+
.pa-kpi-hero-side--neutral {
|
|
17609
|
+
--pa-kpi-accent: var(--pa-neutral);
|
|
17610
|
+
}
|
|
17611
|
+
.pa-kpi-hero-side--up-strong {
|
|
17612
|
+
--pa-kpi-accent: var(--pa-very-positive);
|
|
17613
|
+
}
|
|
17614
|
+
|
|
17615
|
+
.pa-kpi-hero-side__label {
|
|
17616
|
+
grid-area: label;
|
|
17617
|
+
align-self: end; /* tucks against the vertically-centred value */
|
|
17618
|
+
font-family: var(--base-font-family-mono);
|
|
17619
|
+
font-size: 1.3rem;
|
|
17620
|
+
font-weight: 700;
|
|
17621
|
+
letter-spacing: 0.1em;
|
|
17622
|
+
text-transform: uppercase;
|
|
17623
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 60%, transparent);
|
|
17624
|
+
line-height: 1.25;
|
|
17625
|
+
}
|
|
17626
|
+
|
|
17627
|
+
.pa-kpi-hero-side__value {
|
|
17628
|
+
grid-area: value;
|
|
17629
|
+
align-self: center;
|
|
17630
|
+
font-family: var(--base-font-family-mono);
|
|
17631
|
+
line-height: 1;
|
|
17632
|
+
white-space: nowrap;
|
|
17633
|
+
display: inline-flex;
|
|
17634
|
+
align-items: baseline;
|
|
17635
|
+
}
|
|
17636
|
+
|
|
17637
|
+
.pa-kpi-hero-side__num {
|
|
17638
|
+
font-size: 2.4rem;
|
|
17639
|
+
font-weight: 700;
|
|
17640
|
+
letter-spacing: -0.02em;
|
|
17641
|
+
color: var(--pa-text-color-1);
|
|
17642
|
+
}
|
|
17643
|
+
|
|
17644
|
+
.pa-kpi-hero-side__unit {
|
|
17645
|
+
font-size: 1.5rem;
|
|
17646
|
+
font-weight: 500;
|
|
17647
|
+
color: var(--pa-text-secondary);
|
|
17648
|
+
margin: 0 0.35rem;
|
|
17649
|
+
}
|
|
17650
|
+
|
|
17651
|
+
.pa-kpi-hero-side__delta {
|
|
17652
|
+
grid-area: delta;
|
|
17653
|
+
align-self: start;
|
|
17654
|
+
font-family: var(--base-font-family-mono);
|
|
17655
|
+
font-size: 1.2rem;
|
|
17656
|
+
font-weight: 600;
|
|
17657
|
+
color: var(--pa-kpi-accent);
|
|
17658
|
+
}
|
|
17659
|
+
|
|
17660
|
+
/* ========================================
|
|
17661
|
+
KPI · Bento layout
|
|
17662
|
+
Magazine-style asymmetric tile sizing with sparklines as soft background
|
|
17663
|
+
fills behind the values. 6 tiles arranged on a 6-col × 3-row grid
|
|
17664
|
+
(hero left-half × 2 rows, two stacked right-half × 2 rows, three equal
|
|
17665
|
+
tiles bottom row). Tile placement by source order via :nth-child.
|
|
17666
|
+
======================================== */
|
|
17667
|
+
.pa-kpi-bento {
|
|
17668
|
+
container-type: inline-size;
|
|
17669
|
+
}
|
|
17670
|
+
|
|
17671
|
+
.pa-kpi-bento__body {
|
|
17672
|
+
padding: 1.6rem;
|
|
17673
|
+
}
|
|
17674
|
+
|
|
17675
|
+
/* ----- Bento grid ------------------------------------------------------- */
|
|
17676
|
+
.pa-kpi-bento__grid {
|
|
17677
|
+
display: grid;
|
|
17678
|
+
grid-template-columns: repeat(6, 1fr);
|
|
17679
|
+
grid-template-rows: 12rem 12rem 12rem;
|
|
17680
|
+
grid-template-areas: "hero hero hero a a a" "hero hero hero b b b" "c c d d e e";
|
|
17681
|
+
gap: 1rem;
|
|
17682
|
+
}
|
|
17683
|
+
.pa-kpi-bento__grid > :nth-child(1) {
|
|
17684
|
+
grid-area: hero;
|
|
17685
|
+
}
|
|
17686
|
+
.pa-kpi-bento__grid > :nth-child(2) {
|
|
17687
|
+
grid-area: a;
|
|
17688
|
+
}
|
|
17689
|
+
.pa-kpi-bento__grid > :nth-child(3) {
|
|
17690
|
+
grid-area: b;
|
|
17691
|
+
}
|
|
17692
|
+
.pa-kpi-bento__grid > :nth-child(4) {
|
|
17693
|
+
grid-area: c;
|
|
17694
|
+
}
|
|
17695
|
+
.pa-kpi-bento__grid > :nth-child(5) {
|
|
17696
|
+
grid-area: d;
|
|
17697
|
+
}
|
|
17698
|
+
.pa-kpi-bento__grid > :nth-child(6) {
|
|
17699
|
+
grid-area: e;
|
|
17700
|
+
}
|
|
17701
|
+
|
|
17702
|
+
/* Narrow card → stack everything single column. Hero modifier still
|
|
17703
|
+
bumps the value font-size so it reads as the headline. */
|
|
17704
|
+
@container (max-width: 700px) {
|
|
17705
|
+
.pa-kpi-bento__grid {
|
|
17706
|
+
grid-template-columns: 1fr;
|
|
17707
|
+
grid-template-rows: auto;
|
|
17708
|
+
grid-template-areas: none;
|
|
17709
|
+
gap: 0.8rem;
|
|
17710
|
+
}
|
|
17711
|
+
.pa-kpi-bento__grid > :nth-child(n) {
|
|
17712
|
+
grid-area: auto;
|
|
17713
|
+
}
|
|
17714
|
+
.pa-kpi-bento-tile {
|
|
17715
|
+
min-height: 10rem;
|
|
17716
|
+
}
|
|
17717
|
+
.pa-kpi-bento-tile--hero {
|
|
17718
|
+
min-height: 14rem;
|
|
17719
|
+
}
|
|
17720
|
+
}
|
|
17721
|
+
/* ----- Tile (per-KPI bento cell) ---------------------------------------- */
|
|
17722
|
+
.pa-kpi-bento-tile {
|
|
17723
|
+
/* Per-tile inline-size container so the value font-size scales with
|
|
17724
|
+
*this* tile's width via cqi (not the outer card's width). The hero
|
|
17725
|
+
and the smaller bottom tiles each scale to their own column. */
|
|
17726
|
+
container-type: inline-size;
|
|
17727
|
+
position: relative;
|
|
17728
|
+
overflow: hidden;
|
|
17729
|
+
padding: 1.3rem 1.5rem;
|
|
17730
|
+
border: 1px solid var(--pa-border-color);
|
|
17731
|
+
background: var(--pa-card-bg);
|
|
17732
|
+
display: grid;
|
|
17733
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
17734
|
+
grid-template-rows: auto 1fr auto;
|
|
17735
|
+
grid-template-areas: "label delta" ". . " "value value";
|
|
17736
|
+
gap: 0.4rem 1rem;
|
|
17737
|
+
/* Sparkline + delta sentiment cascade via currentColor. */
|
|
17738
|
+
--pa-kpi-accent: var(--pa-positive);
|
|
17739
|
+
}
|
|
17740
|
+
.pa-kpi-bento-tile--positive {
|
|
17741
|
+
--pa-kpi-accent: var(--pa-positive);
|
|
17742
|
+
}
|
|
17743
|
+
.pa-kpi-bento-tile--negative {
|
|
17744
|
+
--pa-kpi-accent: var(--pa-negative);
|
|
17745
|
+
}
|
|
17746
|
+
.pa-kpi-bento-tile--neutral {
|
|
17747
|
+
--pa-kpi-accent: var(--pa-neutral);
|
|
17748
|
+
}
|
|
17749
|
+
.pa-kpi-bento-tile--up-strong {
|
|
17750
|
+
--pa-kpi-accent: var(--pa-very-positive);
|
|
17751
|
+
}
|
|
17752
|
+
.pa-kpi-bento-tile--down-strong {
|
|
17753
|
+
--pa-kpi-accent: var(--pa-very-negative);
|
|
17754
|
+
}
|
|
17755
|
+
.pa-kpi-bento-tile--hero {
|
|
17756
|
+
padding: 1.6rem 1.8rem;
|
|
17757
|
+
}
|
|
17758
|
+
.pa-kpi-bento-tile--hero .pa-kpi-bento-tile__num {
|
|
17759
|
+
font-size: clamp(3.6rem, 22cqi, 7rem);
|
|
17760
|
+
}
|
|
17761
|
+
.pa-kpi-bento-tile--hero .pa-kpi-bento-tile__unit {
|
|
17762
|
+
font-size: clamp(1.6rem, 9cqi, 2.6rem);
|
|
17763
|
+
}
|
|
17764
|
+
.pa-kpi-bento-tile--hero .pa-kpi-bento-tile__label,
|
|
17765
|
+
.pa-kpi-bento-tile--hero .pa-kpi-bento-tile__delta {
|
|
17766
|
+
font-size: 1.4rem;
|
|
17767
|
+
}
|
|
17768
|
+
.pa-kpi-bento-tile--hero .pa-kpi-bento-tile__chart {
|
|
17769
|
+
height: 70%;
|
|
17770
|
+
}
|
|
17771
|
+
|
|
17772
|
+
/* ----- Top row: label + delta, both layered over the chart -------------- */
|
|
17773
|
+
.pa-kpi-bento-tile__label {
|
|
17774
|
+
grid-area: label;
|
|
17775
|
+
font-family: var(--base-font-family-mono);
|
|
17776
|
+
font-size: 1.3rem;
|
|
17777
|
+
font-weight: 700;
|
|
17778
|
+
letter-spacing: 0.1em;
|
|
17779
|
+
text-transform: uppercase;
|
|
17780
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 60%, transparent);
|
|
17781
|
+
z-index: 1;
|
|
17782
|
+
line-height: 1.2;
|
|
17783
|
+
}
|
|
17784
|
+
|
|
17785
|
+
.pa-kpi-bento-tile__delta {
|
|
17786
|
+
grid-area: delta;
|
|
17787
|
+
font-family: var(--base-font-family-mono);
|
|
17788
|
+
font-size: 1.3rem;
|
|
17789
|
+
font-weight: 700;
|
|
17790
|
+
color: var(--pa-kpi-accent);
|
|
17791
|
+
z-index: 1;
|
|
17792
|
+
align-self: start;
|
|
17793
|
+
line-height: 1.2;
|
|
17794
|
+
}
|
|
17795
|
+
|
|
17796
|
+
/* ----- Value (bottom of grid, layered over chart) ----------------------- */
|
|
17797
|
+
.pa-kpi-bento-tile__value {
|
|
17798
|
+
grid-area: value;
|
|
17799
|
+
align-self: end;
|
|
17800
|
+
position: relative;
|
|
17801
|
+
z-index: 1;
|
|
17802
|
+
font-family: var(--base-font-family-mono);
|
|
17803
|
+
display: inline-flex;
|
|
17804
|
+
align-items: baseline;
|
|
17805
|
+
line-height: 1;
|
|
17806
|
+
white-space: nowrap;
|
|
17807
|
+
}
|
|
17808
|
+
|
|
17809
|
+
.pa-kpi-bento-tile__num {
|
|
17810
|
+
font-size: clamp(2rem, 14cqi, 3.2rem);
|
|
17811
|
+
font-weight: 700;
|
|
17812
|
+
letter-spacing: -0.02em;
|
|
17813
|
+
color: var(--pa-text-color-1);
|
|
17814
|
+
}
|
|
17815
|
+
|
|
17816
|
+
.pa-kpi-bento-tile__unit {
|
|
17817
|
+
font-size: clamp(1.2rem, 7cqi, 1.6rem);
|
|
17818
|
+
font-weight: 500;
|
|
17819
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 50%, transparent);
|
|
17820
|
+
margin: 0 0.3rem;
|
|
17821
|
+
}
|
|
17822
|
+
|
|
17823
|
+
/* ----- Sparkline background ---------------------------------------------
|
|
17824
|
+
Absolutely positioned, fills the bottom 65% of the tile. The value sits
|
|
17825
|
+
over it (z-index: 1 above). The line/area read through behind the
|
|
17826
|
+
digits at lower opacity so the value remains the focal point. SVG is
|
|
17827
|
+
nested in a fixed-height wrapper so taller tiles don't distort the line
|
|
17828
|
+
shape (preserveAspectRatio="none" would otherwise stretch the Y axis). */
|
|
17829
|
+
.pa-kpi-bento-tile__chart {
|
|
17830
|
+
position: absolute;
|
|
17831
|
+
left: 0;
|
|
17832
|
+
right: 0;
|
|
17833
|
+
bottom: 0;
|
|
17834
|
+
height: 65%;
|
|
17835
|
+
pointer-events: none;
|
|
17836
|
+
color: var(--pa-kpi-accent);
|
|
17837
|
+
z-index: 0;
|
|
17838
|
+
display: flex;
|
|
17839
|
+
align-items: flex-end;
|
|
17840
|
+
}
|
|
17841
|
+
.pa-kpi-bento-tile__chart svg {
|
|
17842
|
+
display: block;
|
|
17843
|
+
width: 100%;
|
|
17844
|
+
height: 100%;
|
|
17845
|
+
overflow: visible;
|
|
17846
|
+
}
|
|
17847
|
+
.pa-kpi-bento-tile__chart polyline {
|
|
17848
|
+
fill: none;
|
|
17849
|
+
stroke: currentColor;
|
|
17850
|
+
stroke-opacity: 0.55;
|
|
17851
|
+
stroke-width: var(--pa-chart-trendline-stroke);
|
|
17852
|
+
stroke-linecap: round;
|
|
17853
|
+
stroke-linejoin: round;
|
|
17854
|
+
}
|
|
17855
|
+
.pa-kpi-bento-tile__chart polygon {
|
|
17856
|
+
fill: currentColor;
|
|
17857
|
+
fill-opacity: 0.1;
|
|
17858
|
+
stroke: none;
|
|
17859
|
+
}
|
|
17860
|
+
|
|
17861
|
+
.pa-kpi-bento-tile__chart-svg {
|
|
17862
|
+
position: relative;
|
|
17863
|
+
display: block;
|
|
17864
|
+
width: 100%;
|
|
17865
|
+
height: var(--pa-chart-trendline-height);
|
|
17866
|
+
}
|
|
17867
|
+
|
|
17868
|
+
/* ========================================
|
|
17869
|
+
KPI · Numeric strip (densest)
|
|
17870
|
+
Tabular "spreadsheet-style" table card with metric/now/prev/Δ%/vs target
|
|
17871
|
+
columns — most data per pixel, no chart chrome. Each row is its own
|
|
17872
|
+
grid sharing the same column template so cells align across rows
|
|
17873
|
+
without needing subgrid. Wide-only by design — no responsive collapse;
|
|
17874
|
+
narrow placements should use Comparison gauges instead.
|
|
17875
|
+
======================================== */
|
|
17876
|
+
.pa-kpi-strip__body {
|
|
17877
|
+
padding: 0;
|
|
17878
|
+
}
|
|
17879
|
+
|
|
17880
|
+
/* ----- Table layout ----------------------------------------------------- */
|
|
17881
|
+
.pa-kpi-strip__row,
|
|
17882
|
+
.pa-kpi-strip__head-row {
|
|
17883
|
+
display: grid;
|
|
17884
|
+
grid-template-columns: minmax(0, 2fr) minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.6fr); /* target (bar + pct stacked) */
|
|
17885
|
+
column-gap: 1.6rem;
|
|
17886
|
+
align-items: center;
|
|
17887
|
+
position: relative;
|
|
17888
|
+
padding: 1.1rem 1.6rem;
|
|
17889
|
+
}
|
|
17890
|
+
|
|
17891
|
+
/* Divider between data rows / between head and first row only. */
|
|
17892
|
+
.pa-kpi-strip__row + .pa-kpi-strip__row,
|
|
17893
|
+
.pa-kpi-strip__head-row + .pa-kpi-strip__row {
|
|
17894
|
+
border-top: 1px solid var(--pa-border-color);
|
|
17895
|
+
}
|
|
17896
|
+
|
|
17897
|
+
/* Hover host: subtle row highlight so the cursor-anchored popover has a
|
|
17898
|
+
clear "this row" anchor. */
|
|
17899
|
+
.pa-kpi-strip__row:hover {
|
|
17900
|
+
background: var(--pa-surface-hover);
|
|
17901
|
+
}
|
|
17902
|
+
|
|
17903
|
+
/* ----- Header cells (uppercase mono captions) --------------------------- */
|
|
17904
|
+
.pa-kpi-strip__head {
|
|
17905
|
+
font-family: var(--base-font-family-mono);
|
|
17906
|
+
font-size: 1.1rem;
|
|
17907
|
+
font-weight: 700;
|
|
17908
|
+
letter-spacing: 0.1em;
|
|
17909
|
+
text-transform: uppercase;
|
|
17910
|
+
color: var(--pa-text-tertiary);
|
|
17911
|
+
}
|
|
17912
|
+
.pa-kpi-strip__head--num {
|
|
17913
|
+
text-align: end;
|
|
17914
|
+
}
|
|
17915
|
+
|
|
17916
|
+
/* ----- Metric label ----------------------------------------------------- */
|
|
17917
|
+
.pa-kpi-strip__metric {
|
|
17918
|
+
font-family: var(--base-font-family-mono);
|
|
17919
|
+
font-size: 1.4rem;
|
|
17920
|
+
font-weight: 700;
|
|
17921
|
+
letter-spacing: 0.08em;
|
|
17922
|
+
text-transform: uppercase;
|
|
17923
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 78%, transparent);
|
|
17924
|
+
line-height: 1.2;
|
|
17925
|
+
}
|
|
17926
|
+
|
|
17927
|
+
/* ----- NOW (focal value) ------------------------------------------------ */
|
|
17928
|
+
.pa-kpi-strip__now {
|
|
17929
|
+
font-family: var(--base-font-family-mono);
|
|
17930
|
+
font-size: 1.8rem;
|
|
17931
|
+
font-weight: 700;
|
|
17932
|
+
text-align: end;
|
|
17933
|
+
display: flex;
|
|
17934
|
+
align-items: baseline;
|
|
17935
|
+
justify-content: flex-end;
|
|
17936
|
+
color: var(--pa-text-color-1);
|
|
17937
|
+
white-space: nowrap;
|
|
17938
|
+
line-height: 1;
|
|
17939
|
+
}
|
|
17940
|
+
.pa-kpi-strip__now .pa-kpi-strip__num {
|
|
17941
|
+
font-weight: 700;
|
|
17942
|
+
}
|
|
17943
|
+
.pa-kpi-strip__now .pa-kpi-strip__unit {
|
|
17944
|
+
font-size: 1.1rem;
|
|
17945
|
+
font-weight: 500;
|
|
17946
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 50%, transparent);
|
|
17947
|
+
margin: 0 0.2rem;
|
|
17948
|
+
}
|
|
17949
|
+
|
|
17950
|
+
/* ----- PREV (reference data, low contrast) ------------------------------ */
|
|
17951
|
+
.pa-kpi-strip__prev {
|
|
17952
|
+
font-family: var(--base-font-family-mono);
|
|
17953
|
+
font-size: 1.5rem;
|
|
17954
|
+
font-weight: 500;
|
|
17955
|
+
color: var(--pa-text-tertiary);
|
|
17956
|
+
text-align: end;
|
|
17957
|
+
white-space: nowrap;
|
|
17958
|
+
}
|
|
17959
|
+
|
|
17960
|
+
/* ----- Δ% (sentiment-coloured) ------------------------------------------ */
|
|
17961
|
+
.pa-kpi-strip__delta {
|
|
17962
|
+
font-family: var(--base-font-family-mono);
|
|
17963
|
+
font-size: 1.5rem;
|
|
17964
|
+
font-weight: 700;
|
|
17965
|
+
text-align: end;
|
|
17966
|
+
white-space: nowrap;
|
|
17967
|
+
color: var(--pa-positive);
|
|
17968
|
+
}
|
|
17969
|
+
.pa-kpi-strip__delta--positive {
|
|
17970
|
+
color: var(--pa-positive);
|
|
17971
|
+
}
|
|
17972
|
+
.pa-kpi-strip__delta--negative {
|
|
17973
|
+
color: var(--pa-negative);
|
|
17974
|
+
}
|
|
17975
|
+
.pa-kpi-strip__delta--neutral {
|
|
17976
|
+
color: var(--pa-neutral);
|
|
17977
|
+
}
|
|
17978
|
+
.pa-kpi-strip__delta--up-strong {
|
|
17979
|
+
color: var(--pa-very-positive);
|
|
17980
|
+
}
|
|
17981
|
+
.pa-kpi-strip__delta--down-strong {
|
|
17982
|
+
color: var(--pa-very-negative);
|
|
17983
|
+
}
|
|
17984
|
+
|
|
17985
|
+
/* ----- VS TARGET (bar + pct stacked, capped at 100% visual) -------------
|
|
17986
|
+
Theme-neutral grey fill — the pct value itself signals overshoot /
|
|
17987
|
+
undershoot ("97" vs "108" vs "54") so colour reinforcement isn't
|
|
17988
|
+
needed. The bar visually caps at 100% via overflow: hidden so an
|
|
17989
|
+
over-target metric reads as "fully filled" rather than overflowing. */
|
|
17990
|
+
.pa-kpi-strip__target {
|
|
17991
|
+
display: flex;
|
|
17992
|
+
flex-direction: column;
|
|
17993
|
+
gap: 0.35rem;
|
|
17994
|
+
}
|
|
17995
|
+
|
|
17996
|
+
.pa-kpi-strip__bar {
|
|
17997
|
+
position: relative;
|
|
17998
|
+
height: 0.5rem;
|
|
17999
|
+
background: var(--pa-surface-track);
|
|
18000
|
+
overflow: hidden;
|
|
18001
|
+
border-radius: 0.1rem;
|
|
18002
|
+
}
|
|
18003
|
+
|
|
18004
|
+
.pa-kpi-strip__fill {
|
|
18005
|
+
position: absolute;
|
|
18006
|
+
top: 0;
|
|
18007
|
+
left: 0;
|
|
18008
|
+
bottom: 0;
|
|
18009
|
+
background: color-mix(in srgb, var(--pa-text-color-1) 40%, transparent);
|
|
18010
|
+
}
|
|
18011
|
+
|
|
18012
|
+
.pa-kpi-strip__bar-pct {
|
|
18013
|
+
font-family: var(--base-font-family-mono);
|
|
18014
|
+
font-size: 1.05rem;
|
|
18015
|
+
font-weight: 600;
|
|
18016
|
+
color: var(--pa-text-secondary);
|
|
18017
|
+
align-self: flex-end;
|
|
18018
|
+
line-height: 1;
|
|
18019
|
+
}
|
|
18020
|
+
|
|
18021
|
+
/* ----- --no-prev: 4-col layout (metric / now / Δ% / target) -------------
|
|
18022
|
+
Useful for narrow placements; markup omits the prev cells. */
|
|
18023
|
+
.pa-kpi-strip--no-prev .pa-kpi-strip__row,
|
|
18024
|
+
.pa-kpi-strip--no-prev .pa-kpi-strip__head-row {
|
|
18025
|
+
grid-template-columns: minmax(0, 2fr) minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1.6fr);
|
|
18026
|
+
}
|
|
18027
|
+
|
|
18028
|
+
/* ========================================
|
|
18029
|
+
KPI · Editorial minimal
|
|
18030
|
+
Six KPIs in a 2×3 / 3×2 grid with hairline rules between cells,
|
|
18031
|
+
generous space, and an extra-light-weight number as the focal point per
|
|
18032
|
+
tile. No charts, no pills — the design's whole identity is the thin
|
|
18033
|
+
numeral. Renders as a table card (zero card-body padding) so hairlines
|
|
18034
|
+
go edge-to-edge.
|
|
18035
|
+
======================================== */
|
|
18036
|
+
.pa-kpi-edit__body {
|
|
18037
|
+
padding: 0;
|
|
18038
|
+
}
|
|
18039
|
+
|
|
18040
|
+
/* ----- Grid + hairline rules -------------------------------------------
|
|
18041
|
+
`gap: 1px` over `background: var(--pa-border-color)` with each tile
|
|
18042
|
+
painting `background: var(--pa-card-bg)` on top. Only the gap shows
|
|
18043
|
+
through, giving perfect single-pixel hairlines on every interior
|
|
18044
|
+
boundary (vertical and horizontal) for free, regardless of column
|
|
18045
|
+
count. The card's outer border supplies the perimeter. */
|
|
18046
|
+
.pa-kpi-edit__grid {
|
|
18047
|
+
display: grid;
|
|
18048
|
+
grid-template-columns: repeat(3, 1fr);
|
|
18049
|
+
gap: 1px;
|
|
18050
|
+
background: var(--pa-border-color);
|
|
18051
|
+
container-type: inline-size;
|
|
18052
|
+
}
|
|
18053
|
+
|
|
18054
|
+
@container (max-width: 640px) {
|
|
18055
|
+
.pa-kpi-edit__grid {
|
|
18056
|
+
grid-template-columns: repeat(2, 1fr);
|
|
18057
|
+
}
|
|
18058
|
+
}
|
|
18059
|
+
@container (max-width: 360px) {
|
|
18060
|
+
.pa-kpi-edit__grid {
|
|
18061
|
+
grid-template-columns: 1fr;
|
|
18062
|
+
}
|
|
18063
|
+
}
|
|
18064
|
+
/* Modifier: force 2-col regardless of card width. For placements wanting
|
|
18065
|
+
a deterministic 2×N layout (e.g. 4 tiles as clean 2×2) instead of
|
|
18066
|
+
relying on the container query to land in the right bucket. */
|
|
18067
|
+
.pa-kpi-edit__grid--2col {
|
|
18068
|
+
grid-template-columns: repeat(2, 1fr);
|
|
18069
|
+
}
|
|
18070
|
+
|
|
18071
|
+
/* ----- Tile (editorial spacing leans on the 2.4rem padding) ------------- */
|
|
18072
|
+
.pa-kpi-edit__tile {
|
|
18073
|
+
background: var(--pa-card-bg);
|
|
18074
|
+
padding: 2.4rem 2rem;
|
|
18075
|
+
display: flex;
|
|
18076
|
+
flex-direction: column;
|
|
18077
|
+
gap: 1.2rem;
|
|
18078
|
+
position: relative;
|
|
18079
|
+
min-width: 0;
|
|
18080
|
+
/* Hover host: faint wash so the cursor-anchored popover has a clear
|
|
18081
|
+
"this tile" anchor. */
|
|
18082
|
+
}
|
|
18083
|
+
.pa-kpi-edit__tile:hover {
|
|
18084
|
+
background: color-mix(in srgb, var(--pa-text-color-1) 4%, var(--pa-card-bg));
|
|
18085
|
+
}
|
|
18086
|
+
|
|
18087
|
+
/* ----- Label (uppercase mono caption) ----------------------------------- */
|
|
18088
|
+
.pa-kpi-edit__label {
|
|
18089
|
+
font-family: var(--base-font-family-mono);
|
|
18090
|
+
font-size: 1.2rem;
|
|
18091
|
+
font-weight: 600;
|
|
18092
|
+
letter-spacing: 0.12em;
|
|
18093
|
+
text-transform: uppercase;
|
|
18094
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 50%, transparent);
|
|
18095
|
+
line-height: 1.3;
|
|
18096
|
+
}
|
|
18097
|
+
|
|
18098
|
+
/* ----- Value (the editorial signature) ---------------------------------
|
|
18099
|
+
- NOT mono — mono fonts rarely have a true 200 weight; using the body
|
|
18100
|
+
sans gives proper thin glyphs that read as "editorial" rather than
|
|
18101
|
+
"monospace at low contrast".
|
|
18102
|
+
- font-weight: 200 (extra-light). 300 was tested first but didn't read
|
|
18103
|
+
distinctly enough as "light" against the body's 400 default.
|
|
18104
|
+
- clamp() lets the number shrink in narrow 25% page-grid cells without
|
|
18105
|
+
manual breakpoints. */
|
|
18106
|
+
.pa-kpi-edit__value {
|
|
18107
|
+
font-family: var(--base-font-family);
|
|
18108
|
+
font-size: clamp(3.2rem, 18cqi, 5.6rem);
|
|
18109
|
+
font-weight: 200;
|
|
18110
|
+
letter-spacing: -0.02em;
|
|
18111
|
+
line-height: 1;
|
|
18112
|
+
color: var(--pa-text-color-1);
|
|
18113
|
+
display: flex;
|
|
18114
|
+
align-items: baseline;
|
|
18115
|
+
gap: 0.2rem;
|
|
18116
|
+
flex-wrap: wrap;
|
|
18117
|
+
}
|
|
18118
|
+
|
|
18119
|
+
.pa-kpi-edit__num {
|
|
18120
|
+
font-weight: 200;
|
|
18121
|
+
font-variant-numeric: tabular-nums;
|
|
18122
|
+
}
|
|
18123
|
+
|
|
18124
|
+
.pa-kpi-edit__unit {
|
|
18125
|
+
font-size: 0.4em;
|
|
18126
|
+
font-weight: 300;
|
|
18127
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 50%, transparent);
|
|
18128
|
+
letter-spacing: 0;
|
|
18129
|
+
}
|
|
18130
|
+
|
|
18131
|
+
/* ----- Meta row (delta + tgt) ------------------------------------------ */
|
|
18132
|
+
.pa-kpi-edit__meta {
|
|
18133
|
+
display: flex;
|
|
18134
|
+
align-items: baseline;
|
|
18135
|
+
gap: 1.4rem;
|
|
18136
|
+
font-family: var(--base-font-family-mono);
|
|
18137
|
+
font-size: 1.3rem;
|
|
18138
|
+
line-height: 1.3;
|
|
18139
|
+
flex-wrap: wrap;
|
|
18140
|
+
}
|
|
18141
|
+
|
|
18142
|
+
.pa-kpi-edit__delta {
|
|
18143
|
+
font-weight: 700;
|
|
18144
|
+
white-space: nowrap;
|
|
18145
|
+
color: var(--pa-positive);
|
|
18146
|
+
}
|
|
18147
|
+
.pa-kpi-edit__delta--positive {
|
|
18148
|
+
color: var(--pa-positive);
|
|
18149
|
+
}
|
|
18150
|
+
.pa-kpi-edit__delta--negative {
|
|
18151
|
+
color: var(--pa-negative);
|
|
18152
|
+
}
|
|
18153
|
+
.pa-kpi-edit__delta--neutral {
|
|
18154
|
+
color: var(--pa-neutral);
|
|
18155
|
+
}
|
|
18156
|
+
.pa-kpi-edit__delta--up-strong {
|
|
18157
|
+
color: var(--pa-very-positive);
|
|
18158
|
+
}
|
|
18159
|
+
.pa-kpi-edit__delta--down-strong {
|
|
18160
|
+
color: var(--pa-very-negative);
|
|
18161
|
+
}
|
|
18162
|
+
|
|
18163
|
+
.pa-kpi-edit__target {
|
|
18164
|
+
font-weight: 500;
|
|
18165
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 50%, transparent);
|
|
18166
|
+
white-space: nowrap;
|
|
18167
|
+
}
|
|
18168
|
+
.pa-kpi-edit__target em {
|
|
18169
|
+
font-style: normal;
|
|
18170
|
+
color: color-mix(in srgb, var(--pa-text-color-1) 38%, transparent);
|
|
18171
|
+
margin-right: 0.5rem;
|
|
18172
|
+
}
|
|
18173
|
+
|
|
16654
18174
|
/* ========================================
|
|
16655
18175
|
Utility Components
|
|
16656
18176
|
Font utilities, compact mode, component showcase
|