@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: `` is text, `-soft` is the chip wash, `-edge` is the ring. Every `` 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; }