updates on the design on the kpi cards

This commit is contained in:
2026-08-20 16:53:34 +05:30
parent ce32465a6f
commit 1bf89adb6a
10 changed files with 973 additions and 274 deletions

View File

@@ -1,9 +1,15 @@
/* Global visual polish that used to come from MUI's <CssBaseline>/<GlobalStyles>
in themes/index.js (ThemeCustomization). Kept as plain CSS now that every
page runs on Astryx — see root CLAUDE.md §6.6. Astryx's own reset
page runs on Astryx — see root CLAUDE.md §6. Astryx's own reset
(@astryxdesign/core/reset.css, imported in index.js) covers the base
element resets; this file only carries the two enterprise-polish touches
that reset doesn't: crisp font rendering and a thin, unobtrusive scrollbar. */
element resets; this file carries the handful of things a design token
cannot express: font rendering, scrollbar pseudo-elements, keyframes, the
focus treatment, and the global reduced-motion rule.
NOTE ON COLOUR: nothing here introduces a colour. The console keeps its own
palette (themes/dt/tokens.js) — the KROW work adopted KROW's geometry and
type treatment only. Where a rule below needs an accent it reads
`var(--color-accent)` rather than naming one. */
body {
/* Astryx sets --font-family-body on :root (from themes/astryx.js's
@@ -19,11 +25,58 @@ body {
text-rendering: optimizeLegibility;
}
/* Scrollbars are chrome, not content — they should recede until used.
The thumb was rgba(0,0,0,0.26) at 10px, which drew a solid dark bar down the
right edge of every scrollable table and read as a heavy border rather than
as a scrollbar. Lightened and narrowed; it still darkens on hover so it stays
findable. */
/* --------------------------------------------------------------------------
Motion vocabulary.
One set of durations and one easing curve for the whole app, so a hover, a
row highlight and a card entrance all feel like the same product. Three
steps only: `fast` for colour-only changes (anything slower feels laggy
under a moving cursor), `base` for the default, `slow` for layout and
entrances.
Prefixed --dt-* deliberately. These live on :root, and Dispatch.css ALSO
writes :root from a lazy-loaded chunk — an unprefixed name there would win
or lose purely on bundle order rather than on intent.
-------------------------------------------------------------------------- */
:root {
--dt-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--dt-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
--dt-duration-fast: 120ms;
--dt-duration-base: 200ms;
--dt-duration-slow: 320ms;
}
/* --------------------------------------------------------------------------
Focus.
Focus is never the browser default. One ring, one width, everywhere. The
colour is the app's own accent token, not a value chosen here, so the ring
follows the brand automatically.
:focus-visible, not :focus — a mouse click on a button should not leave a
ring behind it.
-------------------------------------------------------------------------- */
.dt-focus-ring:focus-visible {
outline: none;
box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px var(--color-accent);
}
/* The inset variant, for a control flush inside a row or table cell where an
offset ring would be clipped by the overflow container. */
.dt-focus-ring-inset:focus-visible {
outline: none;
box-shadow: inset 0 0 0 2px var(--color-accent);
}
/* --------------------------------------------------------------------------
Scrollbars.
Chrome, not content — they should recede until used. The thumb was
rgba(0,0,0,0.26) at 10px, which drew a solid dark bar down the right edge of
every scrollable table and read as a heavy border rather than as a
scrollbar. Lightened and narrowed; it still darkens on hover so it stays
findable.
-------------------------------------------------------------------------- */
* {
scrollbar-width: thin; /* Firefox */
scrollbar-color: rgba(0, 0, 0, 0.16) transparent;
@@ -40,7 +93,7 @@ body {
*::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.16);
border-radius: 5px;
border-radius: 999px;
border: 2px solid transparent;
background-clip: padding-box;
}
@@ -53,21 +106,104 @@ body {
background-color: transparent;
}
/* KPI / StatCard sleek interactions & polish */
/* --------------------------------------------------------------------------
Keyframes.
A skeleton SHIMMERS, it does not pulse: a pulsing block reads as a
rendering glitch, while a travelling highlight reads as progress. Astryx's
own <Skeleton> keeps its built-in treatment; this is for the hand-rolled
placeholders.
-------------------------------------------------------------------------- */
@keyframes dt-shimmer {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
.dt-shimmer {
background-image: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.65) 50%, transparent 100%);
background-size: 200% 100%;
animation: dt-shimmer 1.6s var(--dt-ease-in-out) infinite;
}
@keyframes dt-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes dt-slide-up {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.dt-fade-in {
animation: dt-fade-in var(--dt-duration-base) var(--dt-ease-out);
}
.dt-slide-up {
animation: dt-slide-up var(--dt-duration-slow) var(--dt-ease-out);
}
/* --------------------------------------------------------------------------
KPI / StatCard (Compact Enterprise Metric Strip).
Static tiles stay quiet and static. Clickable/interactive tiles (e.g. on
Tenants page) get a subtle 150ms hover lift and border emphasis.
-------------------------------------------------------------------------- */
.dt-stat-card {
transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.18s ease !important;
transition: box-shadow 150ms ease, border-color 150ms ease, transform 150ms ease !important;
}
.dt-stat-card:hover {
/* Interactive hover state ONLY when clickable or wrapped in button role */
.dt-stat-card.dt-stat-card-clickable:hover,
.dt-stat-card[data-clickable='true']:hover,
[role='button'] .dt-stat-card:hover,
[role='button'] > .dt-stat-card:hover,
button .dt-stat-card:hover {
border-color: var(--color-border-emphasized, #cbd5e1) !important;
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.08) !important;
transform: translateY(-1px);
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08), 0 1px 3px rgba(15, 23, 42, 0.04) !important;
}
.dt-stat-card .dt-stat-icon {
transition: transform 0.18s ease;
.dt-stat-card.dt-stat-card-clickable:active,
.dt-stat-card[data-clickable='true']:active,
[role='button'] .dt-stat-card:active {
transform: translateY(0);
}
.dt-stat-card:hover .dt-stat-icon {
transform: scale(1.06);
/* Standardized 14px icon size inside the 26px chip across all call sites */
.dt-stat-card .dt-stat-icon svg {
width: 14px !important;
height: 14px !important;
font-size: 14px !important;
}
/* --------------------------------------------------------------------------
Reduced motion.
Handled ONCE, globally, rather than per component — a per-component opt-out
is a rule that only covers the components somebody remembered.
-------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}