Signal/docs/tailwind-theme-v1.md
2026-05-12 05:10:00 -04:00

361 lines
10 KiB
Markdown

# STTIL Brand — Tailwind Theme v1
**Date:** April 2026
**Source tokens:** `design-tokens-v1.json`
**Accent family:** Tangerine (replaces copper)
---
## 1. CSS Custom Properties
Add to your global CSS (e.g., `globals.css`, `base.css`, or `<style>` in `_document`):
```css
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@600;700&family=Inter:wght@400;500&family=JetBrains+Mono:wght@400;500&display=swap');
:root {
/* ── Teal scale ── */
--teal-50: #EEF8F8;
--teal-100: #CBE9E9;
--teal-200: #97D3D3;
--teal-300: #5BBBBB;
--teal-400: #2EA3A3;
--teal-500: #1A8A8A;
--teal-600: #147A7A;
--teal-700: #0F5E5E;
--teal-800: #0A4444;
--teal-900: #072E2E;
--teal-950: #041A1A;
/* ── Tangerine scale ── */
--tng-50: #FFF4EE;
--tng-100: #FFE4CC;
--tng-200: #FFC090;
--tng-300: #FFB070;
--tng-400: #F07840;
--tng-500: #E06028;
--tng-600: #C04E1C;
--tng-700: #903A14;
--tng-800: #6A2A0C;
--tng-900: #3E1808;
/* ── Neutral scale ── */
--n-0: #FFFFFF;
--n-50: #F4F9F9;
--n-100: #E5EEEE;
--n-200: #C8D8D8;
--n-300: #A3BEBE;
--n-400: #7A9E9E;
--n-500: #5A7E7E;
--n-600: #426060;
--n-700: #2E4444;
--n-800: #1C2C2C;
--n-900: #111A1A;
/* ── Semantic ── */
--success-100: #C8EDD8;
--success-500: #1A7A4E;
--success-600: #146040;
--warning-100: #FDECD5;
--warning-400: #D97B35;
--warning-600: #A85A18;
--error-100: #F8CCCC;
--error-500: #C83030;
--error-600: #A02020;
--info-100: #C8E0EE;
--info-500: #1A6A9A;
--purple-100: #E2D8F0;
--purple-500: #7A5EA0;
/* ── Sparkle tokens ── */
--warm-white: #FFFAF6;
--tng-glow-dark: 0 0 24px rgba(240,120,64,0.30), 0 2px 10px rgba(4,26,26,0.70);
--tng-glow-light: 0 0 16px rgba(224,96,40,0.20), 0 2px 8px rgba(0,0,0,0.08);
--priority-row-dark: rgba(224,104,48,0.09);
--priority-row-light: rgba(224,96,40,0.05);
--tng-shimmer-border: 1px solid rgba(240,120,64,0.35);
/* ── Semantic UI (dark mode defaults) ── */
--bg-page: var(--teal-950);
--bg-card: var(--teal-900);
--bg-elevated: var(--teal-800);
--text-heading: var(--warm-white);
--text-primary: #F0F4F4;
--text-secondary: var(--teal-300);
--text-muted: #5A8080;
--border: var(--teal-700);
--brand: var(--teal-400);
--accent: var(--tng-400);
--accent-text: var(--tng-300);
--card-shadow: 0 2px 10px rgba(4,26,26,0.60);
}
/* ── Light mode overrides ── */
.light, [data-theme="light"] {
--bg-page: var(--n-50);
--bg-card: var(--n-0);
--bg-elevated: var(--n-100);
--text-heading: #0A3030;
--text-primary: #1C2E2E;
--text-secondary: var(--n-500);
--text-muted: var(--n-400);
--border: var(--n-200);
--brand: var(--teal-600);
--accent: var(--tng-500);
--accent-text: var(--tng-500);
--card-shadow: 0 2px 8px rgba(7,46,46,0.09);
}
```
---
## 2. Tailwind Config Extension
`tailwind.config.js` (or `tailwind.config.ts`):
```js
const { fontFamily } = require('tailwindcss/defaultTheme')
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx,html}'],
darkMode: 'class',
theme: {
extend: {
colors: {
teal: {
50: '#EEF8F8',
100: '#CBE9E9',
200: '#97D3D3',
300: '#5BBBBB',
400: '#2EA3A3',
500: '#1A8A8A',
600: '#147A7A',
700: '#0F5E5E',
800: '#0A4444',
900: '#072E2E',
950: '#041A1A',
},
tng: {
50: '#FFF4EE',
100: '#FFE4CC',
200: '#FFC090',
300: '#FFB070',
400: '#F07840',
500: '#E06028',
600: '#C04E1C',
700: '#903A14',
800: '#6A2A0C',
900: '#3E1808',
},
neutral: {
0: '#FFFFFF',
50: '#F4F9F9',
100: '#E5EEEE',
200: '#C8D8D8',
300: '#A3BEBE',
400: '#7A9E9E',
500: '#5A7E7E',
600: '#426060',
700: '#2E4444',
800: '#1C2C2C',
900: '#111A1A',
},
success: { 100: '#C8EDD8', 500: '#1A7A4E', 600: '#146040' },
warning: { 100: '#FDECD5', 400: '#D97B35', 600: '#A85A18' },
error: { 100: '#F8CCCC', 500: '#C83030', 600: '#A02020' },
info: { 100: '#C8E0EE', 500: '#1A6A9A' },
purple: { 100: '#E2D8F0', 500: '#7A5EA0' },
},
fontFamily: {
heading: ["'Plus Jakarta Sans'", ...fontFamily.sans],
body: ["'Inter'", ...fontFamily.sans],
mono: ["'JetBrains Mono'", ...fontFamily.mono],
},
fontSize: {
'data': ['0.875rem', { lineHeight: '1.4', fontWeight: '500' }],
},
boxShadow: {
'tng-glow': '0 0 24px rgba(240,120,64,0.30), 0 2px 10px rgba(4,26,26,0.70)',
'tng-glow-light': '0 0 16px rgba(224,96,40,0.20), 0 2px 8px rgba(0,0,0,0.08)',
'card-dark': '0 2px 10px rgba(4,26,26,0.60)',
'card-light': '0 2px 8px rgba(7,46,46,0.09)',
},
},
},
plugins: [],
}
```
---
## 3. Sample Component Classes
### Page backgrounds
```html
<!-- Dark mode default -->
<body class="bg-teal-950 text-white font-body">
<!-- Light mode -->
<body class="bg-neutral-50 text-[#1C2E2E] font-body light">
```
### Cards
```html
<!-- Standard card -->
<div class="bg-teal-900 border border-teal-700 rounded-xl p-5 shadow-card-dark">
<!-- Light mode card -->
<div class="bg-white border border-neutral-200 rounded-xl p-5 shadow-card-light">
<!-- Priority card (tangerine glow — one per view) -->
<div class="bg-teal-900 border border-tng-400 rounded-xl p-5 shadow-tng-glow">
```
### Buttons
```html
<!-- Primary -->
<button class="bg-teal-400 hover:bg-teal-500 text-[#FFFAF6] font-body font-medium
px-4 py-2 rounded-lg transition-colors">
Initiate Outreach
</button>
<!-- Tangerine high-urgency (one per view) -->
<button class="border border-tng-400 text-tng-300 hover:bg-tng-400/10
font-body font-medium px-4 py-2 rounded-lg transition-colors">
⚡ Initiate PA →
</button>
<!-- Ghost -->
<button class="border border-teal-700 text-teal-300 hover:border-teal-500
font-body px-4 py-2 rounded-lg transition-colors">
View
</button>
```
### Status badges
```html
<!-- Active -->
<span class="inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-medium
bg-success-100 text-success-600">
✓ Active
</span>
<!-- PA Required (tangerine) -->
<span class="inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-medium
bg-tng-100 text-tng-700 border border-tng-700/20">
⚡ PA Required
</span>
<!-- Denied -->
<span class="inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-medium
bg-error-100 text-error-600">
✕ Denied
</span>
```
### Worklist table
```html
<table class="w-full border-collapse">
<thead>
<tr class="bg-teal-800">
<th class="px-5 py-2.5 text-left text-[10.5px] font-semibold uppercase tracking-widest
text-[#5A8080]">Patient ID</th>
<!-- ... -->
</tr>
</thead>
<tbody>
<!-- Priority row -->
<tr class="border-b border-teal-700/40 bg-[rgba(224,104,48,0.09)]
hover:bg-[rgba(224,104,48,0.14)] transition-colors">
<td class="px-5 py-3 font-mono font-bold text-tng-300">PT-00142</td>
<!-- ... -->
</tr>
<!-- Standard row -->
<tr class="border-b border-teal-700/40 hover:bg-teal-400/5 transition-colors">
<td class="px-5 py-3 font-mono font-bold text-teal-300">PT-00387</td>
<!-- ... -->
</tr>
</tbody>
</table>
```
### Sidebar nav
```html
<aside class="w-60 bg-teal-900 border-r border-teal-700 flex flex-col min-h-screen">
<!-- Wordmark -->
<div class="px-5 py-6 border-b border-teal-700/50">
<p class="font-heading font-bold text-[17px] text-[#FFFAF6] tracking-[-0.01em]">
Signal CGM
</p>
<p class="text-[11px] text-teal-300 mt-1">by STTIL Solutions</p>
</div>
<!-- Active nav item -->
<a href="#" class="flex items-center gap-2.5 px-5 py-2.5 text-[13.5px] font-medium
text-[#FFFAF6] border-l-[3px] border-tng-400 bg-teal-800/50">
≡ All Patients
</a>
<!-- Inactive nav item -->
<a href="#" class="flex items-center gap-2.5 px-5 py-2.5 text-[13.5px] text-neutral-400
border-l-[3px] border-transparent
hover:text-teal-400 hover:bg-teal-400/5 transition-colors">
⚠ Expiring Soon
</a>
</aside>
```
### Charts (data series)
```html
<!-- Use teal-500 as primary series, tng-400 as the key comparison metric -->
<!-- Example: Chart.js dataset colors -->
<script>
datasets: [
{ label: 'Proactive Outreach', borderColor: '#1A8A8A', backgroundColor: 'rgba(26,138,138,0.12)' },
{ label: 'Appeals / Denials', borderColor: '#F07840', backgroundColor: 'rgba(240,120,64,0.12)' },
]
</script>
```
### Call-out boxes (docs / pitch decks)
```html
<!-- Tangerine call-out (one key insight per section) -->
<div class="bg-tng-100 border-l-4 border-tng-500 rounded-r-lg px-4 py-3">
<p class="font-semibold text-tng-700 text-sm mb-1">PA affirmation rate: 92%</p>
<p class="text-tng-700 text-sm">Suppliers above 90% qualify for PA exemption from June 1, 2026.</p>
</div>
```
---
## 4. Adding a New Payer Rule Status Color
1. Add semantic tokens to `design-tokens-v1.json` under `color.semantic`
2. Add to `tailwind.config.js` under `theme.extend.colors`
3. Add CSS custom properties in `globals.css`
4. Create badge variant in your Badge component following the `icon + label` pattern
5. Update `signal-cgm-brand-extension-v1.md` Section 5 (status table)
---
## 5. Light / Dark Mode Toggle
**React / Next.js:**
```jsx
// Toggle class on <html> element
document.documentElement.classList.toggle('light')
// Or use next-themes:
// <ThemeProvider attribute="class" defaultTheme="dark">
```
**Vanilla JS:**
```js
document.body.classList.toggle('light')
// or
document.documentElement.dataset.theme = 'light' // matches [data-theme="light"]
```
Dark mode is the operational default for Signal CGM. Light mode is for export, print, and presentation contexts.