feat: complete drug-aware indication matching and cleanup app_v2

- Remove app_v2.py (consolidated into pathways_app.py), fix __init__ import
- Add DimSearchTerm.csv, drug_indication_clusters.csv, drug_snomed_mapping_enriched.csv
  as reference data for SNOMED-based indication matching
- Add snomed_indication_mapping_query.sql (source for embedded cluster mapping)
- Update DESIGN_SYSTEM.md, RALPH_PROMPT.md, ralph.ps1, uv.lock
This commit is contained in:
Andrew Charlwood
2026-02-06 00:33:29 +00:00
parent f3bba6dfab
commit a31907aa1f
11 changed files with 41902 additions and 2306 deletions
+151 -146
View File
@@ -1,189 +1,194 @@
# Design System - HCD Analysis v2
# Design System - HCD Analysis v2.1 (SaaS Redesign)
This document defines the visual design language for the UI redesign. All components should reference these tokens for consistency.
This document defines the visual design language for the UI redesign. The goal is a **modern SaaS aesthetic** - think Stripe, Linear, Vercel - while staying thematically aligned with the blue color palette.
**Design Philosophy**:
- The chart is the hero; everything else supports it
- Minimal chrome, maximum data visibility
- Clean, confident, spacious - not clinical or governmental
- Every pixel of vertical space matters
## Color Palette
### Primary Blues (NHS-inspired, modernized)
### Primary Blues (kept from original, used sparingly)
| Name | Hex | Usage |
|------|-----|-------|
| Heritage Blue | `#003087` | Deep headers, authoritative accents |
| Primary Blue | `#0066CC` | Main actions, links, focus states |
| Vibrant Blue | `#1E88E5` | Highlights, hover states, chart primary |
| Sky Blue | `#4FC3F7` | Accents, progress bars, secondary elements |
| Pale Blue | `#E3F2FD` | Subtle backgrounds, card tints |
| Heritage Blue | `#003087` | Top bar background, strong accents |
| Primary Blue | `#0066CC` | Interactive elements, links, focus |
| Vibrant Blue | `#1E88E5` | Hover states, active elements |
| Sky Blue | `#4FC3F7` | Subtle accents, progress indicators |
| Pale Blue | `#E3F2FD` | Selected states, subtle backgrounds |
### Neutrals (warm-tinted for clinical warmth)
### Neutrals (refined for modern feel)
| Name | Hex | Usage |
|------|-----|-------|
| Slate 900 | `#1E293B` | Primary text |
| Slate 900 | `#0F172A` | Primary text (slightly darker) |
| Slate 700 | `#334155` | Secondary text |
| Slate 500 | `#64748B` | Muted text, placeholders |
| Slate 300 | `#CBD5E1` | Borders, dividers |
| Slate 100 | `#F1F5F9` | Card backgrounds, hover states |
| White | `#FFFFFF` | Page background |
| Slate 100 | `#F8FAFC` | Backgrounds (slightly lighter) |
| White | `#FFFFFF` | Card/modal backgrounds |
### Semantic Colors
| Name | Hex | Usage |
|------|-----|-------|
| Success | `#059669` | Positive states, confirmations |
| Warning | `#D97706` | Caution states, alerts |
| Error | `#DC2626` | Error states, destructive actions |
| Info | `#0284C7` | Informational (matches primary family) |
### Chart Palette
```
Primary series: #003087, #0066CC, #1E88E5, #4FC3F7, #90CAF9
Categorical: #0066CC, #059669, #D97706, #8B5CF6, #EC4899
```
| Success | `#10B981` | Positive (modern green) |
| Warning | `#F59E0B` | Caution |
| Error | `#EF4444` | Errors |
| Info | `#3B82F6` | Informational |
## Typography
**Font Family:** Inter (primary), system-ui (fallback)
| Style | Size | Weight | Tracking | Line Height | Usage |
|-------|------|--------|----------|-------------|-------|
| Display | 32px | 700 | -0.02em | 1.2 | Page titles |
| Heading 1 | 24px | 600 | -0.01em | 1.3 | Section headers |
| Heading 2 | 20px | 600 | normal | 1.4 | Card titles |
| Heading 3 | 16px | 600 | normal | 1.4 | Subsections |
| Body | 14px | 400 | normal | 1.5 | Default text |
| Body Small | 13px | 400 | normal | 1.5 | Secondary info |
| Caption | 12px | 500 | normal | 1.4 | Labels, metadata |
| Mono | 13px | 400 | normal | 1.5 | Data values, codes (JetBrains Mono) |
| Style | Size | Weight | Usage |
|-------|------|--------|-------|
| Display | 28px | 600 | Page titles (reduced from 32px) |
| Heading 1 | 18px | 600 | Section headers (reduced from 24px) |
| Heading 2 | 16px | 600 | Card titles (reduced from 20px) |
| Heading 3 | 14px | 600 | Subsections |
| Body | 14px | 400 | Default text |
| Body Small | 13px | 400 | Secondary info |
| Caption | 11px | 500 | Labels, metadata (reduced from 12px) |
| Mono | 13px | 500 | Data values (JetBrains Mono) |
## Spacing Scale
## Spacing Scale (Tighter)
| Token | Value | Usage |
|-------|-------|-------|
| xs | 4px | Tight internal padding |
| sm | 8px | Between related elements |
| md | 12px | Standard gaps |
| lg | 16px | Section padding |
| xl | 24px | Card padding |
| 2xl | 32px | Major section gaps |
| 3xl | 48px | Page margins |
| xs | 4px | Tight gaps |
| sm | 6px | Between related elements (was 8px) |
| md | 8px | Standard gaps (was 12px) |
| lg | 12px | Section padding (was 16px) |
| xl | 16px | Card padding (was 24px) |
| 2xl | 24px | Major gaps (was 32px) |
| 3xl | 32px | Page margins (was 48px) |
## Border Radius
## Layout Specifications
| Token | Value | Usage |
|-------|-------|-------|
| sm | 4px | Small elements, inputs |
| md | 8px | Buttons, small cards |
| lg | 12px | Cards, modals |
| xl | 16px | Large containers |
| full | 9999px | Pills, avatars |
### Page Structure (Target)
```
┌─────────────────────────────────────────────────────────────────┐
│ Logo │ Tabs │ Freshness │ 48px
├─────────────────────────────────────────────────────────────────┤
│ [Initiated▾] [LastSeen▾] │ [Drugs▾] [Ind▾] [Dir▾] │ KPI badges │ 48px
├─────────────────────────────────────────────────────────────────┤
│ │
│ I C I C L E C H A R T │ flex
│ (full viewport width) │
│ │
└─────────────────────────────────────────────────────────────────┘
```
### Top Bar
- **Height**: 48px (reduced from 64px)
- **Background**: Heritage Blue
- **Logo**: 28px height (reduced from 36px)
- **Tabs**: Small pills, 28px height
### Filter Strip
- **Height**: 48px (single row)
- **Layout**: Horizontal flex, all filters inline
- **Dropdown triggers**: 32px height, 8px padding
- **No section header** - labels are in dropdown triggers
- **Background**: Slate 100 or transparent
### KPI Section (Options)
**Option A: Inline badges** (preferred - zero extra height)
```
Filters row: [Initiated▾] [LastSeen▾] | [Drugs▾] ... | 12,345 patients • £45.2M • 89 drugs
```
**Option B: Compact strip** (48px max)
```
┌─────┬─────┬─────┬─────┐
│12.3K│£45M │ 89 │ 7 │ 28px value
│pts │cost │drugs│trust│ 14px label
└─────┴─────┴─────┴─────┘
```
### Chart Container
- **Width**: Full viewport minus 32px (16px padding each side)
- **Height**: Fill remaining space (min 500px)
- **No max-width constraint**
- **Margins**: Minimal (t:40, l:8, r:8, b:24)
## Component Specifications
### Compact Dropdown Trigger
- Height: 32px
- Padding: 8px 12px
- Border: 1px Slate 300
- Border radius: 6px
- Font: 13px
- Chevron: 14px icon
### Compact KPI Badge
- Padding: 4px 12px
- Border radius: 16px (pill)
- Background: Slate 100
- Value: 14px mono, weight 600
- Label: 11px, Slate 500
### Searchable Dropdown Panel
- Max height: 200px (items area)
- Item padding: 6px 8px
- Search input height: 28px
- Width: 240px min
## Shadows
| Token | Value | Usage |
|-------|-------|-------|
| sm | `0 1px 2px rgba(0,0,0,0.05)` | Subtle elevation |
| md | `0 1px 3px rgba(0,0,0,0.08)` | Cards at rest |
| lg | `0 4px 6px rgba(0,0,0,0.1)` | Cards on hover, dropdowns |
| xl | `0 10px 15px rgba(0,0,0,0.1)` | Modals, popovers |
| sm | `0 1px 2px rgba(0,0,0,0.04)` | Subtle (lighter) |
| md | `0 1px 3px rgba(0,0,0,0.06)` | Cards at rest |
| lg | `0 4px 8px rgba(0,0,0,0.08)` | Dropdowns, hover |
## Component Specifications
## Border Radius
### Cards
- Background: White
- Border: 1px Slate 300 (optional, or use shadow only)
- Border radius: lg (12px)
- Padding: xl (24px)
- Shadow: md at rest, lg on hover
- Hover: translateY(-2px) transition
### Buttons
**Primary:**
- Background: Primary Blue
- Text: White
- Border radius: md (8px)
- Padding: 10px 20px
- Hover: Vibrant Blue background, slight scale (1.02)
**Secondary:**
- Background: White
- Border: 1px Primary Blue
- Text: Primary Blue
- Hover: Pale Blue background
**Ghost:**
- Background: transparent
- Text: Primary Blue
- Hover: Pale Blue background
### Form Controls
- Height: 40px (inputs, selects)
- Border: 1px Slate 300
- Border radius: md (8px)
- Focus: 2px Primary Blue ring
- Placeholder: Slate 500
### Data Cards (KPIs)
- Large mono number: 32-48px, Slate 900
- Label: Caption size, Slate 500
- Background: White or Pale Blue tint
- Optional trend indicator or sparkline
## Layout
### Page Structure
```
┌─────────────────────────────────────────────────────────────────┐
│ Logo + App Name [Chart Tabs] Data Freshness │ ← Top Bar (64px height)
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─ Filters ─────────────────────────────────────────────────┐ │ ← Filter Section
│ │ Date ranges, dropdowns, filter controls │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ KPIs ────────────────────────────────────────────────────┐ │ ← KPI Row
│ │ [ Metric 1 ] [ Metric 2 ] [ Metric 3 ] [ Metric 4 ] │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Chart ───────────────────────────────────────────────────┐ │ ← Main Chart (fills remaining)
│ │ │ │
│ │ [ Interactive Visualization ] │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
### Responsive Breakpoints
- Mobile: < 640px
- Tablet: 640px - 1024px
- Desktop: > 1024px
| Token | Value | Usage |
|-------|-------|-------|
| sm | 4px | Small elements |
| md | 6px | Inputs, buttons |
| lg | 8px | Cards |
| full | 9999px | Pills, badges |
## Transitions
| Property | Duration | Easing |
|----------|----------|--------|
| Color, background | 150ms | ease-out |
| Transform | 200ms | ease-out |
| Shadow | 200ms | ease-out |
| Opacity | 200ms | ease-in-out |
All transitions: 150ms ease-out (faster than before)
## Reflex Implementation Notes
## Implementation Notes
### Using Design Tokens
Create a `styles.py` module with these values as Python constants. Import throughout the app:
### Key Changes from v2.0
1. **Vertical space reduction**: ~210px saved (364px → ~156px overhead)
2. **Full-width chart**: Remove PAGE_MAX_WIDTH for chart
3. **Inline KPIs**: Either badges in filter row or minimal strip
4. **Smaller fonts**: Headlines and captions reduced
5. **Tighter spacing**: All spacing tokens reduced by ~25%
```python
# Example structure
class Colors:
PRIMARY = "#0066CC"
PRIMARY_DARK = "#003087"
# etc.
### CSS Patterns
```css
/* Full-height chart container */
.chart-container {
height: calc(100vh - 96px); /* viewport minus top bar + filter strip */
min-height: 500px;
width: calc(100vw - 32px);
margin: 0 16px;
}
class Spacing:
XS = "4px"
SM = "8px"
# etc.
/* Filter strip */
.filter-strip {
display: flex;
align-items: center;
height: 48px;
gap: 12px;
padding: 0 16px;
}
```
### rx.theme Configuration
Configure Reflex's theme provider with the color palette for consistent component styling.
### Custom CSS
For styles not achievable via Reflex props, use `rx.style` or a custom CSS file.
### Reflex Implementation
- Use `height="calc(100vh - 96px)"` for chart container
- Use `width="100%"` with `padding_x="16px"` for full-width
- Use `flex="1"` to let chart grow
- Keep `min_height="500px"` as fallback