northlake-health/src/styles.css
Yashas e775fb0e88 feat: the claims tile counts the lakehouse rows the link opens; live trace fills the screen
Claims denied showed Ava's affected_claims (225) while "See the claims"
opened 237 rows — her quantify query and the link's filters are two
different queries. The tile now asks the record view for the link's own
filter set (limit 1, pagination.total_count) and shows that; her figure
appears underneath only when it disagrees. The URL→filter mapping moves
to lib/claimsLink so the table and the tile share one definition.

While a review runs the trace is the page: the layout widens to the
screen, the list takes the viewport height, follows the newest step
unless the viewer scrolled up, and shows a working row with a spinner
and an indeterminate strip under the header. Reduced motion honoured.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 13:14:00 +05:30

276 lines
9.0 KiB
CSS

@import 'tailwindcss';
/* Northlake Health — Denials Desk. Light and dark.
=====================================================================
HOW THEMING WORKS HERE
`@theme` below defines the LIGHT theme, and light is also the fallback:
every token has a value here, so a document with no `data-theme` renders
correctly rather than unstyled. The dark theme is the
`:root[data-theme='dark']` block further down, which redefines the SAME
token names. Tailwind v4 compiles `bg-panel` to
`background-color: var(--color-panel)`, so overriding the variable swaps the
entire app — including opacity modifiers like `bg-brand/10`, which compile to
a `color-mix()` over the same var.
Consequently: NEVER put a literal colour in a component. A hex in a className
is invisible to the toggle and will be wrong in one of the two themes.
THE ONE RULE THAT CARRIES THIS APP'S MEANING
**Violet is the AI, and nothing else is violet.** Every number, sentence and
panel that Ava produced is tinted with it; everything a person or a rule
produced is not. On a screen whose whole claim is "an agent did this work and
you can check it", the reader has to be able to tell the two apart without
reading a label. Red is reserved for a case that needs a human and for a
reject — so when red appears in the queue it means something.
Every colour used for text is checked at WCAG AA against the surfaces it
actually appears on, in both themes. */
@theme {
/* --- Structural ---------------------------------------------------- */
--color-ink: #0f2233; /* primary text */
--color-muted: #4a6076; /* secondary text */
--color-faint: #5a7089; /* labels, placeholders, dashes */
--color-bg: #f2f7f8; /* page canvas — a cool clinical tint */
--color-panel: #ffffff; /* card face */
--color-panel2: #f1f6f8; /* input fill, row hover */
--color-panel3: #e3eef1; /* pressed / hover on panel2 */
--color-line: #d5e4e8; /* borders */
/* Brand accent — a clinical teal. Used BOTH as a fill and as text, so it
carries a companion for whatever sits on top of it. */
--color-brand: #0e7c86;
--color-brand-fg: #ffffff;
--color-brand-hover: #0b636b;
/* Fixed in both themes: the mark's own colours. */
--color-navy: #0e7c86;
--color-signal: #c2333a; /* needs-a-human and reject */
--color-signal-hover: #9f262c;
/* --- Semantic tones ------------------------------------------------
Six meanings, three roles each: `<tone>` is text, `<tone>-soft` is the chip
wash, `<tone>-edge` is the ring. Every `<tone>` passes AA on its own wash
AND on the page and panel, because these are used both inside a badge and
as bare text (a stat value, a rate). */
--color-idle: #55504a;
--color-idle-soft: #f2f0ed;
--color-idle-edge: #dad4cc;
/* THE most important tone in this app. Amber is Awaiting Review — the pile a
human owns — and it is deliberately the only amber in the pipeline, so it
reads as "needs you" without reading as an error. Findings waiting for a
decision are not a problem; they are the product. */
--color-warn: #8a5a00;
--color-warn-soft: #fff8e8;
--color-warn-edge: #f0c368;
--color-info: #0f5c78;
--color-info-soft: #e7f2f6;
--color-info-edge: #a4cadb;
--color-good: #00713d;
--color-good-soft: #e4f6ec;
--color-good-edge: #93d3b0;
--color-bad: #b31e23;
--color-bad-soft: #fdeced;
--color-bad-edge: #eda9ac;
/* The AI's own colour — see the rule at the top. */
--color-ai: #5b2ca0;
--color-ai-soft: #f5f1fd;
--color-ai-edge: #c3adec;
--color-scrim: rgb(6 28 40 / 0.45);
/* Inter: a screen typeface for dense tabular work, self-hosted through
@fontsource-variable/inter (imported in main.tsx) rather than a CDN — this
build is promoted between environments and dropped behind hospital
proxies, and a font fetched from fonts.googleapis.com is one that
sometimes does not arrive. */
--font-sans:
'Inter Variable', Inter, system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
--font-mono:
ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
}
/* Non-Tailwind vars: consumed by the hand-rolled rules at the bottom rather
than by generated utilities, so they live outside `@theme`. */
:root {
/* Tinted with navy rather than black, so the lift reads as part of the
palette. In dark it goes near-black and deeper — a navy shadow on a
navy canvas is invisible, so dark leans on the border instead. */
--lift: 0 1px 2px rgb(6 40 52 / 0.07), 0 1px 1px rgb(6 40 52 / 0.04);
--lift-lg: 0 12px 32px rgb(6 40 52 / 0.16), 0 2px 8px rgb(6 40 52 / 0.08);
--sb-thumb: #c4d8dd;
--sb-thumb-hover: #a6c2c9;
/* Makes the browser render native widgets — date picker, select dropdown,
scrollbar gutter — to match. Without it a dark console opens a blinding
white calendar. */
color-scheme: light;
}
/* =====================================================================
DARK — the navy-led palette. Only tokens are redefined; no utility,
component or layout rule is duplicated.
===================================================================== */
:root[data-theme='dark'] {
--color-ink: #e7f1f5;
--color-muted: #a3c0cc;
--color-faint: #93b2c0;
--color-bg: #07161f;
--color-panel: #10233a;
--color-panel2: #17304a;
--color-panel3: #1f3d59;
--color-line: #22405c;
/* The accent lightens and the text on it darkens — the inverse of light. A
#0E7C86 fill would sink into the canvas, and #0E7C86 text on it is
unreadable. */
--color-brand: #4fc3cd;
--color-brand-fg: #06202a;
--color-brand-hover: #6fd2da;
/* The signal red is unchanged: white on it clears AA either way, and it
still clears 3:1 against the dark canvas as a large component. */
--color-signal-hover: #e8686e;
--color-idle: #d6cdbf;
--color-idle-soft: #2a2724;
--color-idle-edge: #4b453b;
--color-warn: #f7cd7a;
--color-warn-soft: #3a2a06;
--color-warn-edge: #8a681f;
--color-info: #9fd0e2;
--color-info-soft: #0d3a4c;
--color-info-edge: #3f7f99;
--color-good: #5fd694;
--color-good-soft: #052a18;
--color-good-edge: #10683b;
--color-bad: #f4a3a6;
--color-bad-soft: #3c1416;
--color-bad-edge: #8c3a3d;
--color-ai: #c9b3f2;
--color-ai-soft: #221542;
--color-ai-edge: #5a3fa2;
--color-scrim: rgb(2 10 14 / 0.66);
--lift: 0 1px 2px rgb(0 0 0 / 0.4);
--lift-lg: 0 16px 40px rgb(0 0 0 / 0.55), 0 2px 8px rgb(0 0 0 / 0.4);
--sb-thumb: #1e4a5e;
--sb-thumb-hover: #2a6376;
color-scheme: dark;
}
html,
body,
#root {
height: 100%;
}
body {
margin: 0;
background: var(--color-bg);
color: var(--color-ink);
font-family: var(--font-sans);
font-size: 15px;
-webkit-font-smoothing: antialiased;
}
/* Tabular figures everywhere numbers line up in a column — amounts,
ratios, file numbers. Proportional digits make a money table look
ragged, and this app is mostly money. */
.tnum {
font-variant-numeric: tabular-nums;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--sb-thumb);
border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--sb-thumb-hover);
}
@keyframes nl-pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.35;
}
}
.live-dot {
animation: nl-pulse 1.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
.live-dot {
animation: none;
}
}
.lift {
box-shadow: var(--lift);
}
.lift-lg {
box-shadow: var(--lift-lg);
}
/* A SQL statement, as Ava sent it. Monospace, wrapped rather than scrolled —
these are read, not edited, and a horizontal scrollbar inside a timeline row
hides the end of the query, which is usually the interesting part. */
.sql {
font-family: var(--font-mono);
font-size: 11.5px;
line-height: 1.55;
white-space: pre-wrap;
word-break: break-word;
}
/* Review in progress: an indeterminate strip under the trace header, and
three breathing dots on the "working" row. Both honour reduced motion. */
@keyframes nl-slide {
0% { transform: translateX(-100%); }
100% { transform: translateX(300%); }
}
.progress-strip {
position: relative;
height: 3px;
overflow: hidden;
background: color-mix(in srgb, var(--color-ai) 18%, transparent);
}
.progress-strip::after {
content: '';
position: absolute;
inset: 0 auto 0 0;
width: 33%;
background: var(--color-ai);
animation: nl-slide 1.8s ease-in-out infinite;
}
.working-dots { display: inline-flex; gap: 4px; align-items: center; }
.working-dots i {
width: 6px; height: 6px; border-radius: 9999px;
background: var(--color-ai);
animation: nl-pulse 1.2s ease-in-out infinite;
}
.working-dots i:nth-child(2) { animation-delay: 0.2s; }
.working-dots i:nth-child(3) { animation-delay: 0.4s; }
@media (prefers-reduced-motion: reduce) {
.progress-strip::after, .working-dots i { animation: none; }
}