Rebuilt the two screens for a person with ninety seconds, not an analyst. Every screen now answers, in order and at descending size: what happened (one sentence, 21px), how much (three numbers you can read across a table — claims denied, money at stake, still recoverable with its first deadline), and what she wants approved (the ranked list, with the decision buttons directly under it). The full analysis, her SQL and the live trace sit behind disclosures — one click for the reviewer who wants to check, zero clutter for the manager who does not. The queue opens on a briefing strip: "1 decision waiting for you — $1,091,000 recoverable". A manager who reads only that line has the day. Cards lead with the verdict sentence and the recoverable figure; a waiting case says "Needs your decision", not "Awaiting Review". Jargon translated where a business reader meets it: "data reconciled" became "Numbers checked against Finance"; "97% confident" became "Ava is 97% sure"; the trace steps read "Asked the data" and "Thought about it". Ava's SHOUTED recommendation headings are sentence-cased. While Ava is still working, the trace is the page — there is nothing else to show yet, and watching her query is the demo. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
244 lines
8.0 KiB
CSS
244 lines
8.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;
|
|
}
|