MedASR-Bench / src /app /globals.css
ngoan
MedASR Bench: full platform + Hugging Face Docker Space packaging
d70f132
Raw
History Blame Contribute Delete
22.7 kB
@import "tailwindcss";
/* ------------------------------------------------------------------ */
/* MedASR Bench — "Clinical Instrument" token system */
/* ------------------------------------------------------------------ */
:root {
color-scheme: light;
/* Palette — light "precision instrument": cool paper-white surfaces, ink
text, deep violet accent (user-picked hue; deepened for light-mode
contrast: oklch(0.50 0.17 290) = 6.1:1 on --bg). Built in OKLCH; all
small-text pairings clear WCAG 4.5:1. Saturated hues are reserved for
meaning (accent/warn/crit). NO green — repeatedly rejected by the user. */
--bg: #f9f9fb;
--surface: #ffffff;
--surface-2: #eeeef2;
--line: rgba(36, 36, 60, 0.13);
--text: #24242f;
--muted: #62626f;
--accent: #654abb; /* deep violet — sparingly */
--warn: #a15e00; /* contamination / caution only */
--crit: #c53637; /* critical / error only */
/* Derived tints — single-source: everything mixes from the tokens above */
--accent-dim: color-mix(in srgb, var(--accent) 12%, transparent);
--warn-dim: color-mix(in srgb, var(--warn) 12%, transparent);
--crit-dim: color-mix(in srgb, var(--crit) 10%, transparent);
--grid-ink: rgba(36, 36, 80, 0.045);
--grid-ink-major: rgba(36, 36, 80, 0.065);
}
@theme inline {
/* Colors → Tailwind utilities (bg-bg, text-muted, border-line, …) */
--color-bg: var(--bg);
--color-surface: var(--surface);
--color-surface-2: var(--surface-2);
--color-line: var(--line);
--color-text: var(--text);
--color-muted: var(--muted);
--color-accent: var(--accent);
--color-warn: var(--warn);
--color-crit: var(--crit);
--color-accent-dim: var(--accent-dim);
--color-warn-dim: var(--warn-dim);
--color-crit-dim: var(--crit-dim);
/* Fonts → font-display / font-body / font-mono utilities.
The var() chain resolves to next/font variables set on <html>. */
--font-display: var(--font-display), "Instrument Serif", Georgia, serif;
--font-body: var(--font-body), "Be Vietnam Pro", system-ui, sans-serif;
--font-sans: var(--font-body), "Be Vietnam Pro", system-ui, sans-serif;
--font-mono: var(--font-mono), "IBM Plex Mono", ui-monospace, SFMono-Regular,
monospace;
}
/* ------------------------------------------------------------------ */
/* Base + atmosphere: graph-paper micro-grid + scanline layer */
/* ------------------------------------------------------------------ */
html {
background-color: var(--bg);
}
body {
/* solid color lives on <html>; body stays transparent so the fixed
negative-z ambient glow layers (AmbientEffects) shine through the grid */
background-color: transparent;
color: var(--text);
font-family: var(--font-body), "Be Vietnam Pro", system-ui, sans-serif;
/* graph-paper grid: 140px major rhythm over the 28px minor micro-grid */
background-image: linear-gradient(var(--grid-ink-major) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-ink-major) 1px, transparent 1px),
linear-gradient(var(--grid-ink) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-ink) 1px, transparent 1px);
background-size:
140px 140px,
140px 140px,
28px 28px,
28px 28px;
-webkit-font-smoothing: antialiased;
}
/* ------------------------------------------------------------------ */
/* Grain texture — subtle film noise for tactile depth */
/* ------------------------------------------------------------------ */
body::before {
content: "";
position: fixed;
inset: 0;
z-index: 29;
pointer-events: none;
opacity: 0.02;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* scanline veil — fixed, non-interactive, layered above grain */
body::after {
content: "";
position: fixed;
inset: 0;
z-index: 30;
pointer-events: none;
background: repeating-linear-gradient(
to bottom,
color-mix(in srgb, var(--text) 1.2%, transparent) 0px,
color-mix(in srgb, var(--text) 1.2%, transparent) 1px,
transparent 1px,
transparent 3px
);
}
::selection {
background: var(--accent-dim);
color: var(--text);
}
/* ------------------------------------------------------------------ */
/* Ambient light — fixed phosphor glow washes behind all content */
/* (rendered by components/ui/AmbientEffects; GPU-cheap transform drift) */
/* ------------------------------------------------------------------ */
@keyframes ambient-drift-a {
0%,
100% {
transform: translate3d(0, 0, 0) scale(1);
}
50% {
transform: translate3d(4%, 3%, 0) scale(1.08);
}
}
@keyframes ambient-drift-b {
0%,
100% {
transform: translate3d(0, 0, 0) scale(1);
}
50% {
transform: translate3d(-3%, -4%, 0) scale(1.06);
}
}
.ambient-glow {
position: absolute;
pointer-events: none;
will-change: transform;
}
/* top-center wash — the room's key light */
.ambient-glow-top {
top: -32vh;
left: -12vw;
right: -12vw;
height: 78vh;
background: radial-gradient(
ellipse 55% 55% at 50% 45%,
color-mix(in srgb, var(--accent) 9%, transparent),
transparent 70%
);
animation: ambient-drift-a 70s ease-in-out infinite;
}
/* lower-right fill — faint counter-glow */
.ambient-glow-corner {
right: -22vw;
bottom: -30vh;
width: 72vw;
height: 75vh;
background: radial-gradient(
ellipse 50% 50% at 55% 55%,
color-mix(in srgb, var(--accent) 5.5%, transparent),
transparent 70%
);
animation: ambient-drift-b 90s ease-in-out infinite;
}
/* ------------------------------------------------------------------ */
/* Glass morphism — translucent surfaces tuned to the lifted palette */
/* ------------------------------------------------------------------ */
/* layered as components so Tailwind utilities (bg-surface/55 …) can
override the surface opacity per-instance */
@layer components {
/* veil only: translucent surface + blur, no border (compose freely) */
.glass-veil {
background: color-mix(in srgb, var(--surface) 66%, transparent);
-webkit-backdrop-filter: blur(16px) saturate(1.2);
backdrop-filter: blur(16px) saturate(1.2);
}
/* full glass panel: veil + hairline + machined top-edge relief */
.glass {
background: color-mix(in srgb, var(--surface) 72%, transparent);
-webkit-backdrop-filter: blur(14px) saturate(1.2);
backdrop-filter: blur(14px) saturate(1.2);
border: 1px solid var(--line);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 6%, transparent);
}
}
/* ------------------------------------------------------------------ */
/* Hairline utilities (1px --line rules, the only "shadows" we use) */
/* ------------------------------------------------------------------ */
.hairline {
border: 1px solid var(--line);
/* machined top-edge relief — the only "shadow" beyond hairlines */
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 4%, transparent);
}
.hairline-t {
border-top: 1px solid var(--line);
}
.hairline-b {
border-bottom: 1px solid var(--line);
}
.hairline-l {
border-left: 1px solid var(--line);
}
.hairline-r {
border-right: 1px solid var(--line);
}
/* ------------------------------------------------------------------ */
/* Spring animations — physics-based motion */
/* ------------------------------------------------------------------ */
@keyframes spring-in {
from {
opacity: 0;
transform: scale(0.95) translateY(12px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
@keyframes spring-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes soft-appear {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Spring-based entrance animations */
.spring-in {
animation: spring-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.spring-up {
animation: spring-up 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.soft-appear {
animation: soft-appear 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* Improved stagger with spring feel */
.stagger-spring > * {
animation: spring-up 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.stagger-spring > :nth-child(1) { animation-delay: 0ms; }
.stagger-spring > :nth-child(2) { animation-delay: 60ms; }
.stagger-spring > :nth-child(3) { animation-delay: 120ms; }
.stagger-spring > :nth-child(4) { animation-delay: 180ms; }
.stagger-spring > :nth-child(5) { animation-delay: 240ms; }
.stagger-spring > :nth-child(6) { animation-delay: 300ms; }
.stagger-spring > :nth-child(7) { animation-delay: 360ms; }
.stagger-spring > :nth-child(8) { animation-delay: 420ms; }
/* ------------------------------------------------------------------ */
/* Spotlight border effect — card illumination on hover */
/* ------------------------------------------------------------------ */
.spotlight-card {
position: relative;
isolation: isolate;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.spotlight-card::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
background: radial-gradient(
500px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
color-mix(in srgb, var(--accent) 12%, transparent),
transparent 40%
);
opacity: 0;
transition: opacity 0.4s ease;
z-index: -1;
pointer-events: none;
}
.spotlight-card:hover {
border-color: color-mix(in srgb, var(--accent) 25%, transparent);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--accent) 8%, transparent);
}
.spotlight-card:hover::before {
opacity: 1;
}
/* Spotlight row for tables.
IMPORTANT: no ::before/::after on this class — it sits on <tr>, and a
generated box on a table row gets wrapped in an ANONYMOUS CELL, silently
shifting every real cell one column right of the headers. The hover
sweep is painted as the row's own background instead. */
.spotlight-row {
transition: background-color 0.2s ease;
}
.spotlight-row:hover {
background-color: var(--surface-2);
background-image: linear-gradient(
90deg,
transparent 0%,
color-mix(in srgb, var(--accent) 4%, transparent) 50%,
transparent 100%
);
}
/* ------------------------------------------------------------------ */
/* Tactile button states */
/* ------------------------------------------------------------------ */
.tactile {
transition: transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1),
background-color 0.2s ease,
border-color 0.2s ease;
}
.tactile:active {
transform: scale(0.975) translateY(1px);
}
.tactile:hover:not(:disabled) {
background-color: var(--surface-2);
}
/* Interactive elements with subtle lift */
.hover-lift {
transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1),
box-shadow 0.2s ease;
}
.hover-lift:hover {
transform: translateY(-2px);
box-shadow:
0 4px 14px rgba(20, 20, 45, 0.1),
inset 0 1px 0 color-mix(in srgb, var(--text) 4%, transparent);
}
/* ------------------------------------------------------------------ */
/* Accent glow effects */
/* ------------------------------------------------------------------ */
.glow-accent-subtle {
box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 10%, transparent);
}
/* ------------------------------------------------------------------ */
/* Edge accent bar — vertical phosphor line */
/* ------------------------------------------------------------------ */
.edge-accent {
position: relative;
}
.edge-accent::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 2px;
background: linear-gradient(
to bottom,
transparent,
var(--accent) 20%,
var(--accent) 80%,
transparent
);
opacity: 0.6;
}
/* Mono numerals everywhere data lives */
.num {
font-family: var(--font-mono), "IBM Plex Mono", ui-monospace, monospace;
font-variant-numeric: tabular-nums;
}
.tabular {
font-variant-numeric: tabular-nums;
}
/* ------------------------------------------------------------------ */
/* Keyframes */
/* ------------------------------------------------------------------ */
@keyframes rise {
from {
opacity: 0;
transform: translateY(14px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* pair with pathLength={1} + stroke-dasharray: 1 on an SVG path */
@keyframes drawLine {
from {
stroke-dashoffset: 1;
}
to {
stroke-dashoffset: 0;
}
}
/* ambient ECG sweep: a short bright tracer cycling over the dim base path */
@keyframes sweep {
from {
stroke-dashoffset: 1;
}
to {
stroke-dashoffset: 0;
}
}
@keyframes shimmer {
from {
background-position: -200% 0;
}
to {
background-position: 200% 0;
}
}
@keyframes pulseDot {
0%,
100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.35;
transform: scale(0.78);
}
}
@keyframes scaleInX {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
/* ------------------------------------------------------------------ */
/* Motion helpers — one orchestrated load per route */
/* ------------------------------------------------------------------ */
/* stagger container: children rise with 55ms steps */
.stagger > * {
animation: rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.stagger > :nth-child(1) {
animation-delay: 0ms;
}
.stagger > :nth-child(2) {
animation-delay: 55ms;
}
.stagger > :nth-child(3) {
animation-delay: 110ms;
}
.stagger > :nth-child(4) {
animation-delay: 165ms;
}
.stagger > :nth-child(5) {
animation-delay: 220ms;
}
.stagger > :nth-child(6) {
animation-delay: 275ms;
}
.stagger > :nth-child(7) {
animation-delay: 330ms;
}
.stagger > :nth-child(8) {
animation-delay: 385ms;
}
.stagger > :nth-child(9) {
animation-delay: 440ms;
}
.stagger > :nth-child(10) {
animation-delay: 495ms;
}
.stagger > :nth-child(11) {
animation-delay: 550ms;
}
.stagger > :nth-child(12) {
animation-delay: 605ms;
}
/* manual stagger steps for non-sibling layouts */
.delay-1 {
animation-delay: 55ms;
}
.delay-2 {
animation-delay: 110ms;
}
.delay-3 {
animation-delay: 165ms;
}
.delay-4 {
animation-delay: 220ms;
}
/* skeleton block: surface placeholder swept by the shimmer keyframes */
.skeleton {
position: relative;
overflow: hidden;
border-radius: 2px;
background-color: var(--surface-2);
background-image: linear-gradient(
100deg,
transparent 40%,
color-mix(in srgb, var(--text) 7%, transparent) 50%,
transparent 60%
);
background-size: 200% 100%;
animation: shimmer 1.8s linear infinite;
}
/* shimmering surface for status=running chips */
.chip-shimmer {
background-image: linear-gradient(
100deg,
color-mix(in srgb, var(--accent) 7%, transparent) 40%,
color-mix(in srgb, var(--accent) 22%, transparent) 50%,
color-mix(in srgb, var(--accent) 7%, transparent) 60%
);
background-size: 200% 100%;
animation: shimmer 2.4s linear infinite;
}
.pulse-dot {
animation: pulseDot 1.4s ease-in-out infinite;
}
.draw-line {
stroke-dasharray: 1;
animation: drawLine 1.4s cubic-bezier(0.4, 0, 0.2, 1) 0.15s both;
}
/* pair with pathLength={1}: 6%-long phosphor tracer, ~7s per pass */
.pulse-sweep {
stroke-dasharray: 0.06 0.94;
animation: sweep 7s linear infinite;
}
/* CI whisker draw-in: the micro-bar sweeps open left → right once */
.ci-draw {
transform-origin: left center;
animation: scaleInX 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* NOTE: scroll-driven entrances (animation-timeline: view()) were tried
and removed — with fill-mode both, content whose timeline binds to the
wrong scroll container (e.g. rows inside overflow-x-auto) can be stuck
at opacity 0 forever. Entrances are load-orchestrated only. */
/* ------------------------------------------------------------------ */
/* Scroll-triggered animations (Intersection Observer based) */
/* ------------------------------------------------------------------ */
/* Base scroll animation classes */
.scroll-animate {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.scroll-animate.in-view {
opacity: 1;
transform: translateY(0);
}
/* Scroll scale animation */
.scroll-scale {
opacity: 0;
transform: scale(0.95);
transition: opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.scroll-scale.in-view {
opacity: 1;
transform: scale(1);
}
/* Scroll slide animations */
.scroll-slide-left {
opacity: 0;
transform: translateX(-24px);
transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.scroll-slide-left.in-view {
opacity: 1;
transform: translateX(0);
}
.scroll-slide-right {
opacity: 0;
transform: translateX(24px);
transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.scroll-slide-right.in-view {
opacity: 1;
transform: translateX(0);
}
.scroll-slide-down {
opacity: 0;
transform: translateY(-24px);
transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1),
transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.scroll-slide-down.in-view {
opacity: 1;
transform: translateY(0);
}
/* Scroll fade animation */
.scroll-fade {
opacity: 0;
transition: opacity 0.4s ease-out;
}
.scroll-fade.in-view {
opacity: 1;
}
/* Stagger children on scroll */
.scroll-stagger > * {
opacity: 0;
transform: translateY(16px);
transition: opacity 0.4s ease-out,
transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.scroll-stagger.in-view > *:nth-child(1) { opacity: 1; transform: translateY(0); transition-delay: 0ms; }
.scroll-stagger.in-view > *:nth-child(2) { opacity: 1; transform: translateY(0); transition-delay: 60ms; }
.scroll-stagger.in-view > *:nth-child(3) { opacity: 1; transform: translateY(0); transition-delay: 120ms; }
.scroll-stagger.in-view > *:nth-child(4) { opacity: 1; transform: translateY(0); transition-delay: 180ms; }
.scroll-stagger.in-view > *:nth-child(5) { opacity: 1; transform: translateY(0); transition-delay: 240ms; }
.scroll-stagger.in-view > *:nth-child(6) { opacity: 1; transform: translateY(0); transition-delay: 300ms; }
.scroll-stagger.in-view > *:nth-child(7) { opacity: 1; transform: translateY(0); transition-delay: 360ms; }
.scroll-stagger.in-view > *:nth-child(8) { opacity: 1; transform: translateY(0); transition-delay: 420ms; }
/* ------------------------------------------------------------------ */
/* Micro-interactions */
/* ------------------------------------------------------------------ */
/* ------------------------------------------------------------------ */
/* Card depth variations */
/* ------------------------------------------------------------------ */
.depth-1 {
box-shadow: 0 1px 3px rgba(20, 20, 45, 0.06);
}
.depth-2 {
box-shadow: 0 2px 10px rgba(20, 20, 45, 0.07);
}
.depth-3 {
box-shadow:
0 8px 28px rgba(20, 20, 45, 0.09),
0 2px 6px rgba(20, 20, 45, 0.05);
}
/* ------------------------------------------------------------------ */
/* Full-bleed breakout — a block wider than the page container, */
/* centered on the viewport (parent must be a centered max-w column) */
/* ------------------------------------------------------------------ */
@media (min-width: 80rem) {
.breakout-wide {
--breakout-w: min(100vw - 5rem, 85rem);
width: var(--breakout-w);
margin-left: calc(50% - var(--breakout-w) / 2);
}
}
/* ------------------------------------------------------------------ */
/* Nav sweep — a phosphor tracer riding the sticky nav's bottom */
/* hairline; the instrument is always on */
/* ------------------------------------------------------------------ */
.nav-sweep {
position: absolute;
inset-inline: 0;
bottom: -1px;
height: 1px;
overflow: hidden;
pointer-events: none;
}
.nav-sweep::before {
content: "";
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 140px;
background: linear-gradient(
90deg,
transparent,
color-mix(in srgb, var(--accent) 55%, transparent),
transparent
);
animation: nav-sweep 9s linear infinite;
}
@keyframes nav-sweep {
from {
transform: translateX(-140px);
}
to {
transform: translateX(100vw);
}
}
/* ------------------------------------------------------------------ */
/* Reduced motion: everything settles instantly */
/* ------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
animation-delay: 0ms !important;
animation-iteration-count: 1 !important;
animation-timeline: auto !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
/* ambient effects are pure ambience — remove them when motion is reduced */
.pulse-sweep {
visibility: hidden;
}
.nav-sweep {
display: none;
}
/* ambient glow drift stops; the static light wash may remain */
.ambient-glow {
animation: none;
will-change: auto;
}
/* skeletons settle to a static placeholder */
.skeleton {
animation: none;
background-image: none;
}
/* grain and scanline remain as they don't animate */
body::before,
body::after {
display: none;
}
/* spotlight effects collapse to static */
.spotlight-card::before {
display: none;
}
/* hover lifts settle */
.hover-lift:hover {
transform: none;
}
/* glows collapse */
.glow-accent-subtle {
box-shadow: none;
}
/* scroll animations resolve immediately */
.scroll-animate,
.scroll-scale,
.scroll-slide-left,
.scroll-slide-right,
.scroll-slide-down,
.scroll-fade {
opacity: 1;
transform: none;
}
.scroll-stagger > * {
opacity: 1;
transform: none;
}
}