178 lines
4.7 KiB
CSS
178 lines
4.7 KiB
CSS
@import "tailwindcss";
|
|
|
|
/* Scan Blade templates for utility classes */
|
|
@source "../views";
|
|
|
|
/* --- Theme tokens ------------------------------------------------------ */
|
|
/* Semantic brand colors. Defaults are the stock blues; a customized theme
|
|
overrides these :root variables via an inline <style> in the layout head
|
|
(values come from the site_themes table), so no CSS rebuild is needed.
|
|
Must stay in sync with Theme::DEFAULTS. */
|
|
@theme {
|
|
--color-primary: #2563eb; /* blue-600 */
|
|
--color-primary-hover: #1d4ed8; /* blue-700 */
|
|
--color-secondary: #3b82f6; /* blue-500 */
|
|
--color-tertiary: #1d4ed8; /* blue-700 */
|
|
--color-nav-link: #2563eb;
|
|
--color-nav-text: #111827; /* gray-900 */
|
|
--color-nav-muted: #6b7280; /* gray-500 */
|
|
}
|
|
|
|
:root {
|
|
--theme-nav-bg: #ffffff;
|
|
--theme-chart-line: #2a78d6;
|
|
}
|
|
|
|
.site-nav {
|
|
background: var(--theme-nav-bg);
|
|
}
|
|
|
|
/* --- Destructive-action confirm modal ---------------------------------- */
|
|
#confirm-delete-modal::backdrop {
|
|
background: rgba(17, 24, 39, 0.5);
|
|
}
|
|
|
|
/* --- Bowler chart expand/collapse ------------------------------------- */
|
|
/* The detail <tr> itself can't animate height; the inner grid wrapper
|
|
animates 0fr -> 1fr (no magic max-heights). Entrances are gentle,
|
|
exits are quicker, and the KPI line "draws" itself as the hero moment. */
|
|
|
|
.detail-outer {
|
|
display: grid;
|
|
grid-template-rows: 0fr;
|
|
transition: grid-template-rows 180ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.detail-inner {
|
|
overflow: hidden;
|
|
min-height: 0;
|
|
opacity: 0;
|
|
transform: translateY(-4px);
|
|
transition: opacity 120ms ease-in, transform 120ms ease-in;
|
|
}
|
|
|
|
.js-detail-row.is-open .detail-outer {
|
|
grid-template-rows: 1fr;
|
|
transition-duration: 250ms;
|
|
}
|
|
|
|
.js-detail-row.is-open .detail-inner {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
transition: opacity 200ms ease-out 80ms, transform 200ms ease-out 80ms;
|
|
}
|
|
|
|
/* KPI chart: the value line draws in; points/markers pop with a stagger. */
|
|
@keyframes kpi-draw {
|
|
from { stroke-dashoffset: 1; }
|
|
to { stroke-dashoffset: 0; }
|
|
}
|
|
|
|
@keyframes kpi-pop {
|
|
from { opacity: 0; transform: scale(0.4); }
|
|
to { opacity: 1; transform: scale(1); }
|
|
}
|
|
|
|
.is-open .kpi-line {
|
|
stroke-dasharray: 1;
|
|
animation: kpi-draw 600ms cubic-bezier(0.25, 0.1, 0.25, 1) 150ms backwards;
|
|
}
|
|
|
|
.is-open .kpi-pop {
|
|
transform-box: fill-box;
|
|
transform-origin: center;
|
|
animation: kpi-pop 220ms cubic-bezier(0.34, 1.4, 0.64, 1) backwards;
|
|
animation-delay: calc(250ms + var(--i, 0) * 40ms);
|
|
}
|
|
|
|
/* --- Noted chart points + floating note tooltip ------------------------ */
|
|
/* Points whose entry carries a note get a theme-colored halo that gently
|
|
pulses (identity marker, not state — RAG fills stay untouched). Hovering
|
|
with intent draws a leader line to a fixed-position floating panel. */
|
|
|
|
.kpi-note-ring {
|
|
fill: none;
|
|
stroke: var(--color-primary);
|
|
stroke-width: 1.5;
|
|
transform-box: fill-box;
|
|
transform-origin: center;
|
|
}
|
|
|
|
@keyframes kpi-note-pulse {
|
|
0%, 100% { stroke-opacity: 0.85; transform: scale(1); }
|
|
50% { stroke-opacity: 0.35; transform: scale(1.35); }
|
|
}
|
|
|
|
.is-open .kpi-note-ring {
|
|
/* Starts after the pop-in stagger settles. */
|
|
animation: kpi-note-pulse 2.2s ease-in-out 900ms infinite;
|
|
}
|
|
|
|
.js-note-point { cursor: pointer; }
|
|
|
|
/* Fixed positioning escapes .detail-inner's overflow: hidden and the
|
|
table's overflow-x-auto wrapper. */
|
|
.kpi-note-tooltip {
|
|
position: fixed;
|
|
z-index: 50;
|
|
max-width: 400px;
|
|
opacity: 0;
|
|
transform: scale(0.96);
|
|
pointer-events: none;
|
|
transition: opacity 160ms ease-out, transform 160ms cubic-bezier(0.34, 1.4, 0.64, 1);
|
|
}
|
|
|
|
.kpi-note-tooltip.is-visible {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
pointer-events: auto; /* lets users move in and scroll long notes */
|
|
}
|
|
|
|
/* Full-viewport overlay carrying the point-to-panel leader line. */
|
|
.kpi-note-leader {
|
|
position: fixed;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 49;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.kpi-note-leader line {
|
|
stroke: var(--color-primary);
|
|
stroke-width: 1.5;
|
|
stroke-dasharray: 1; /* pathLength="1" in markup */
|
|
stroke-dashoffset: 1;
|
|
}
|
|
|
|
.kpi-note-leader.is-visible line {
|
|
animation: kpi-draw 220ms ease-out forwards;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.detail-outer,
|
|
.detail-inner,
|
|
.js-detail-row.is-open .detail-outer,
|
|
.js-detail-row.is-open .detail-inner {
|
|
transition: none;
|
|
}
|
|
|
|
.is-open .kpi-line,
|
|
.is-open .kpi-pop {
|
|
animation: none;
|
|
}
|
|
|
|
.is-open .kpi-note-ring {
|
|
animation: none; /* halo stays as a static marker */
|
|
}
|
|
|
|
.kpi-note-tooltip {
|
|
transition: none;
|
|
}
|
|
|
|
.kpi-note-leader.is-visible line {
|
|
animation: none;
|
|
stroke-dashoffset: 0;
|
|
}
|
|
}
|