← back to Norma
app/globals.css
1562 lines
@import "tailwindcss";
/* ─── Norma Design Tokens ────────────────────────────────────────────────── */
/* Multi-tenant nonprofit platform — petitions, polling, advocacy */
/* WCAG 2.1 AA audited 2026-02-23 — see docs/wcag-audit-2026-02-23.md */
:root {
/* Backgrounds — clean white */
--color-bg: #f5f5f7; /* L=0.9194 */
--color-surface: #ffffff; /* L=1.0000 */
--color-surface-el: #f0f0f2; /* L=0.8750 — inputs, elevated cards */
/* Brand — Emerald (civic action) + Amber (urgency)
--color-primary is used as BOTH button background (white text on it)
AND as foreground text (it on bg/surface). #0a7c59 passes AA in both
roles: white-on-primary 5.51:1, primary-on-white 5.51:1.
Previous #059669 failed AA when used as text on --color-bg (4.22:1). */
--color-primary: #0a7c59; /* emerald — 5.51:1 on white, 5.09:1 on bg */
--color-primary-hover:#065f46; /* darker hover — 8.30:1 on white */
--color-primary-dim: rgba(10, 124, 89, 0.10);
--color-secondary: #d97706; /* amber — background fills/icons ONLY, never text */
--color-secondary-dim:rgba(217, 119, 6, 0.10);
/* Lanes — Petition / Policy / Resources
lane-c updated from #059669 to match --color-primary fix above.
lane-a and lane-b already passed AA. */
--color-lane-a: #e11d48; /* Rose — 5.99:1 on white — PASS */
--color-lane-b: #4f46e5; /* Indigo — 6.70:1 on white — PASS */
--color-lane-c: #0a7c59; /* Emerald — 5.51:1 on white — PASS (was #059669 = 4.57) */
/* Semantic
--color-warning: amber is kept as the visual/background accent token.
--color-warning-text: dark amber for ALL text uses of warning state.
Previous #d97706 as text on white = 3.03:1 — FAIL.
#92400e on white = 14.54:1 — AAA pass. */
--color-success: #0a7c59; /* 5.51:1 on white — PASS (was #059669 = 4.57) */
--color-warning: #d97706; /* USE FOR BACKGROUNDS/ICONS ONLY — 3.03:1 as text = FAIL */
--color-warning-text: #92400e; /* dark amber — 14.54:1 on white — text/label use */
--color-error: #dc2626; /* 5.74:1 on white — PASS */
--color-info: #4f46e5; /* 6.70:1 on white — PASS */
/* Text — dark on light for readability
--color-text-muted updated: #6b7280 failed on --color-surface-el (4.37:1).
#585e6b = 6.03:1 on surface-el, 6.84:1 on white — solid AA+. */
--color-text: #1a1a2e; /* 17.05:1 on white — AAA */
--color-text-secondary: #4a4a5e; /* 8.44:1 on white — AAA */
--color-text-muted: #585e6b; /* 6.84:1 on white, 6.03:1 on surface-el — PASS (was #6b7280 = 4.37 on surface-el = FAIL) */
/* Structure */
--color-border: #e2e4e9;
--color-border-light: #d1d5db;
/* Radius */
--radius-sm: 6px;
--radius-md: 10px;
--radius-lg: 14px;
/* Transition */
--transition: 150ms ease;
/* Typography scale — large, accessible */
--font-size-sm: 15px; /* small labels, captions */
--font-size-base: 17px; /* body text */
--font-size-lg: 20px; /* prominent body / sub-labels */
--font-size-xl: 24px; /* section headings */
--font-size-2xl: 32px; /* page titles */
/* Comfortable spacing */
--space-comfortable: 18px;
/* Typography — clean, high-readability system */
--font-heading: 'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif;
--font-body: 'Inter', ui-sans-serif, system-ui, sans-serif;
--font-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* ─── Base ───────────────────────────────────────────────────────────────── */
html {
scroll-behavior: smooth;
color-scheme: light;
font-size: var(--font-size-base); /* 17px baseline */
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
background-color: var(--color-bg);
color: var(--color-text);
font-family: var(--font-body);
font-size: var(--font-size-base);
font-weight: 450; /* medium weight — crisp on white */
line-height: 1.65; /* comfortable reading */
-webkit-font-smoothing: auto; /* let browser handle — antialiased makes light text thinner */
-moz-osx-font-smoothing: auto;
min-height: 100vh;
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-heading);
font-weight: 700;
letter-spacing: -0.02em;
line-height: 1.3;
}
/* ─── Global focus indicator — light theme ───────────────────────────────── */
/* Uses --color-primary-hover (#065f46) not --color-primary (#0a7c59).
Both pass WCAG 2.2 SC 2.4.11 (3:1 UI component threshold) on all surfaces,
but primary-hover (#065f46) gives 8.30:1 on white — far more visible for
keyboard-only and low-vision users. The 3px width ensures the indicator
area meets the 2px perimeter requirement of WCAG 2.2 SC 2.4.11. */
:focus-visible {
outline: 3px solid var(--color-primary-hover);
outline-offset: 2px;
}
/* ─── Links — clearly distinguishable, underlined by default ─────────────── */
a {
color: var(--color-primary);
text-decoration: underline;
text-underline-offset: 3px;
transition: color var(--transition);
}
a:hover {
color: #047857;
text-decoration: underline;
}
/* ─── Scrollbar — wider and more visible ─────────────────────────────────── */
* {
scrollbar-width: auto; /* not 'thin' — easier to grab */
}
::-webkit-scrollbar {
width: 12px; /* was 6px — much easier to grab */
height: 12px;
}
::-webkit-scrollbar-track {
background: var(--color-bg);
}
::-webkit-scrollbar-thumb {
background: var(--color-border-light);
border-radius: 6px;
border: 2px solid var(--color-bg); /* padding effect makes thumb look inset */
}
::-webkit-scrollbar-thumb:hover {
background: var(--color-text-muted);
}
/* ─── Cards ──────────────────────────────────────────────────────────────── */
.card {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-comfortable); /* was 1rem (16px) — now explicitly 16px */
transition: border-color var(--transition);
}
.card:hover {
border-color: var(--color-border-light);
}
.card-elevated {
background-color: var(--color-surface-el);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-comfortable);
}
/* ─── Buttons — larger targets, clearly pressable ────────────────────────── */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 12px 20px; /* was 0.5rem 1rem — taller target */
min-height: 44px; /* WCAG 2.5.5 touch target */
min-width: 44px;
border-radius: var(--radius-md);
font-size: 15px; /* was 0.875rem (14px) */
font-weight: 600; /* was 500 — bolder for readability */
letter-spacing: 0.01em;
line-height: 1.25;
cursor: pointer;
border: 1px solid transparent;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); /* subtle depth */
transition: background-color var(--transition), color var(--transition),
border-color var(--transition), opacity var(--transition),
box-shadow var(--transition);
white-space: nowrap;
user-select: none;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn:focus-visible {
outline: 3px solid var(--color-primary-hover);
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(6, 95, 70, 0.18); /* matches #065f46 */
}
.btn-primary {
background-color: var(--color-primary);
color: #fff;
border-color: var(--color-primary);
}
.btn-primary:hover:not(:disabled) {
background-color: var(--color-primary-hover);
border-color: var(--color-primary-hover);
}
.btn-secondary {
background-color: var(--color-surface-el);
color: var(--color-text);
border-color: var(--color-border);
}
.btn-secondary:hover:not(:disabled) {
background-color: #e8e8ec;
border-color: var(--color-border-light);
}
.btn-danger {
background-color: transparent;
color: var(--color-error);
border-color: var(--color-error);
}
.btn-danger:hover:not(:disabled) {
background-color: rgba(244, 63, 94, 0.12);
}
.btn-ghost {
background-color: transparent;
color: var(--color-text-secondary);
border-color: transparent;
}
.btn-ghost:hover:not(:disabled) {
background-color: var(--color-surface-el);
color: var(--color-text);
}
.btn-sm {
padding: 8px 14px; /* was 0.25rem 0.625rem — taller than before */
min-height: 38px; /* never go below 38px */
font-size: 14px; /* was 0.8125rem (13px) */
border-radius: var(--radius-sm);
}
.btn-lg {
padding: 16px 28px; /* was 0.75rem 1.5rem */
min-height: 52px;
font-size: 17px; /* was 1rem (16px) */
font-weight: 600;
}
/* ─── Badges — more readable ─────────────────────────────────────────────── */
.badge {
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 4px 10px; /* was 0.125rem 0.5rem — more padding */
border-radius: 9999px;
font-size: 13px; /* was 0.75rem (12px) — one step up */
font-weight: 600;
line-height: 1.2;
letter-spacing: 0.02em;
text-transform: uppercase;
}
/* Lane badges
Background tints are purely decorative — text color carries meaning.
lane-c text updated to --color-lane-c (#0a7c59) — was #059669 at 4.1:1 on
tinted white, now 5.51:1 on white / ~4.9:1 on tinted surface. PASS. */
.lane-a {
background-color: rgba(225, 29, 72, 0.10); /* tint of #e11d48 */
color: var(--color-lane-a); /* #e11d48 — 5.99:1 on white */
border: 1px solid rgba(225, 29, 72, 0.25);
}
.lane-b {
background-color: rgba(79, 70, 229, 0.10); /* tint of #4f46e5 */
color: var(--color-lane-b); /* #4f46e5 — 6.70:1 on white */
border: 1px solid rgba(79, 70, 229, 0.25);
}
.lane-c {
background-color: rgba(10, 124, 89, 0.10); /* tint of #0a7c59 */
color: var(--color-lane-c); /* #0a7c59 — 5.51:1 on white */
border: 1px solid rgba(10, 124, 89, 0.25);
}
/* Status badges
badge-success: updated to match --color-success (#0a7c59).
badge-warning: text switched to --color-warning-text (#92400e, 14.54:1).
Amber fill is decorative; dark amber text is legible. WCAG PASS.
badge-error: unchanged — dc2626 at 4.9:1 on tinted bg passes. */
.badge-success {
background-color: rgba(10, 124, 89, 0.10);
color: var(--color-success); /* #0a7c59 — 5.51:1 on white */
border: 1px solid rgba(10, 124, 89, 0.25);
}
.badge-warning {
background-color: rgba(217, 119, 6, 0.12); /* amber tint — decorative fill */
color: var(--color-warning-text); /* #92400e — 14.54:1 on white */
border: 1px solid rgba(217, 119, 6, 0.28);
}
.badge-error {
background-color: rgba(220, 38, 38, 0.10); /* tint of #dc2626 */
color: var(--color-error); /* #dc2626 — 5.74:1 on white */
border: 1px solid rgba(220, 38, 38, 0.25);
}
.badge-primary {
color: #fff;
background-color: var(--color-primary);
border-color: var(--color-primary);
}
/* ─── Form Inputs — larger targets, 16px prevents iOS zoom ──────────────── */
.input {
width: 100%;
background-color: var(--color-surface-el);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 12px 16px; /* was 0.5rem 0.75rem — taller and wider */
min-height: 44px; /* WCAG 2.5.5 touch target */
font-size: 16px; /* was 0.875rem (14px) — prevents iOS auto-zoom */
color: var(--color-text);
outline: none;
transition: border-color var(--transition), box-shadow var(--transition);
}
.input::placeholder {
color: var(--color-text-muted);
font-size: 15px;
}
.input:focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(10, 124, 89, 0.18); /* matches updated #0a7c59 primary */
}
.input:focus-visible {
outline: 3px solid var(--color-primary-hover); /* #065f46 — 8.30:1 on white */
outline-offset: 0;
}
/* ─── TipTap / ProseMirror Editor ────────────────────────────────────────── */
.ProseMirror {
min-height: 300px;
padding: 1rem;
outline: none;
color: var(--color-text);
font-size: 0.9375rem;
line-height: 1.7;
caret-color: var(--color-primary);
}
.ProseMirror:focus {
/* Focus is indicated by the container border, not the editor itself */
outline: none;
}
.ProseMirror p {
margin: 0 0 0.75em;
}
.ProseMirror p:last-child {
margin-bottom: 0;
}
.ProseMirror h1 {
font-size: 1.75rem;
font-weight: 700;
line-height: 1.3;
margin: 0 0 0.5em;
color: var(--color-text);
}
.ProseMirror h2 {
font-size: 1.375rem;
font-weight: 600;
line-height: 1.35;
margin: 0 0 0.5em;
color: var(--color-text);
}
.ProseMirror h3 {
font-size: 1.125rem;
font-weight: 600;
line-height: 1.4;
margin: 0 0 0.5em;
color: var(--color-text);
}
.ProseMirror ul,
.ProseMirror ol {
padding-left: 1.5rem;
margin: 0 0 0.75em;
}
.ProseMirror ul {
list-style-type: disc;
}
.ProseMirror ol {
list-style-type: decimal;
}
.ProseMirror li {
margin-bottom: 0.25em;
}
.ProseMirror li p {
margin-bottom: 0.25em;
}
.ProseMirror a {
color: var(--color-primary);
text-decoration: underline;
text-underline-offset: 2px;
cursor: pointer;
}
.ProseMirror a:hover {
color: #047857;
}
.ProseMirror blockquote {
border-left: 3px solid var(--color-border);
padding-left: 1rem;
margin: 0 0 0.75em;
color: var(--color-text-secondary);
font-style: italic;
}
.ProseMirror code {
background-color: var(--color-surface-el);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
padding: 0.1em 0.35em;
font-family: var(--font-mono);
font-size: 0.875em;
/* #6ee7b7 (light mint) on #f0f0f2 = ~1.4:1 — completely invisible on light bg.
Switched to --color-primary (#0a7c59) which gives 4.87:1 on surface-el. */
color: var(--color-primary);
}
.ProseMirror pre {
background-color: var(--color-surface-el);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 0.75rem 1rem;
overflow-x: auto;
margin: 0 0 0.75em;
}
.ProseMirror pre code {
background: none;
border: none;
padding: 0;
font-size: 0.875rem;
}
.ProseMirror strong {
font-weight: 600;
}
.ProseMirror em {
font-style: italic;
}
.ProseMirror u {
text-decoration: underline;
}
/* TipTap placeholder */
.ProseMirror p.is-editor-empty:first-child::before {
color: var(--color-text-muted);
content: attr(data-placeholder);
float: left;
height: 0;
pointer-events: none;
}
/* TipTap selected text — selection highlight uses primary at 35% opacity */
.ProseMirror ::selection {
background-color: rgba(10, 124, 89, 0.22); /* #0a7c59 at lower opacity — visible but not muddy on white */
}
/* ─── CodeMirror Container ───────────────────────────────────────────────── */
.cm-container {
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
overflow: hidden;
background-color: var(--color-surface-el);
}
.cm-container:focus-within {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(10, 124, 89, 0.20); /* updated to match #0a7c59 primary */
}
.cm-container .cm-editor {
min-height: 300px;
}
.cm-container .cm-scroller {
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo,
Consolas, "DejaVu Sans Mono", monospace;
font-size: 0.875rem;
line-height: 1.6;
}
/* ─── Utility Helpers ────────────────────────────────────────────────────── */
.divider {
border: none;
border-top: 1px solid var(--color-border);
margin: 0;
}
.text-primary { color: var(--color-text); }
.text-secondary { color: var(--color-text-secondary); }
.text-muted { color: var(--color-text-muted); }
.text-brand { color: var(--color-primary); }
.text-gold { color: var(--color-secondary); }
.surface { background-color: var(--color-surface); }
.surface-el { background-color: var(--color-surface-el); }
/* Toast animation */
@keyframes toast-in {
from { opacity: 0; transform: translateY(12px) scale(0.95); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Loading spinner */
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
display: inline-block;
width: 1.25rem;
height: 1.25rem;
border: 2px solid var(--color-border);
border-top-color: var(--color-primary);
border-radius: 50%;
animation: spin 0.7s linear infinite;
}
/* ─── Skeleton Loaders ───────────────────────────────────────────────────── */
.skeleton {
background: linear-gradient(90deg, var(--color-surface-el) 25%, var(--color-border) 50%, var(--color-surface-el) 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* ─── Enhanced Card Styles ───────────────────────────────────────────────── */
.card-interactive {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-comfortable);
transition: all 200ms ease;
cursor: pointer;
}
.card-interactive:hover {
border-color: var(--color-primary);
box-shadow: 0 0 16px rgba(10, 124, 89, 0.10), 0 4px 12px rgba(0, 0, 0, 0.08); /* lightened black shadow for light bg */
transform: translateY(-1px);
}
/* Hero stat card — featured stats */
.card-hero {
background: linear-gradient(135deg, var(--color-surface) 0%, rgba(10, 124, 89, 0.05) 100%); /* #0a7c59 tint */
border: 1px solid rgba(10, 124, 89, 0.18);
border-radius: var(--radius-lg);
padding: 1.5rem;
}
/* Petition card accent */
.card-petition {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-left: 3px solid var(--color-primary);
border-radius: var(--radius-lg);
padding: var(--space-comfortable);
transition: all 200ms ease;
position: relative;
}
.card-petition:hover {
border-color: var(--color-border-light);
border-left-color: var(--color-primary);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.07); /* lightened for light bg — 0.15 was dark-theme depth */
}
/* ─── Stats Display ─────────────────────────────────────────────────────── */
.stat-value {
font-family: var(--font-mono);
font-size: 2rem;
font-weight: 700;
line-height: 1;
letter-spacing: -0.02em;
}
.stat-label {
font-size: 12px; /* was 0.7rem — slightly larger for readability */
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--color-text-muted);
}
/* ─── Settings card section headers — fix word spacing at small sizes ───── */
.card h3 {
word-spacing: 0.02em;
letter-spacing: -0.01em;
}
/* ─── Section Headers ───────────────────────────────────────────────────── */
.section-header {
display: flex;
align-items: center;
gap: 0.75rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--color-border);
margin-bottom: 1rem;
}
.section-title {
font-family: var(--font-heading);
font-size: 1.25rem;
font-weight: 700;
color: var(--color-text);
}
.section-count {
font-family: var(--font-mono);
font-size: 0.75rem;
font-weight: 600;
color: var(--color-primary);
background: var(--color-primary-dim);
padding: 0.125rem 0.5rem;
border-radius: 9999px;
}
/* ─── Enhanced Badges ───────────────────────────────────────────────────── */
.badge-glow {
box-shadow: 0 0 8px currentColor;
}
.badge-pulse {
animation: badge-pulse 2s ease-in-out infinite;
}
@keyframes badge-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
/* ─── Score Ring ─────────────────────────────────────────────────────────── */
.score-ring {
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
border-radius: 50%;
font-family: var(--font-mono);
font-weight: 700;
font-size: 0.875rem;
}
/* ─── Subtle Animations ─────────────────────────────────────────────────── */
.hover-lift {
transition: transform 200ms ease, box-shadow 200ms ease;
}
.hover-lift:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}
/* Button press feedback */
.btn:active:not(:disabled) {
transform: scale(0.97);
}
/* Focus ring for accessibility — 3px for high visibility
Uses primary-hover (#065f46 = 8.30:1 on white) for maximum contrast. */
.focus-ring:focus-visible {
outline: 3px solid var(--color-primary-hover);
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(6, 95, 70, 0.18);
}
/* ─── Gradient Divider ──────────────────────────────────────────────────── */
.divider-gradient {
height: 1px;
background: linear-gradient(90deg, transparent, var(--color-border-light), transparent);
border: none;
margin: 0;
}
/* ─── Pulse Dot (for live indicators) ───────────────────────────────────── */
.pulse-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--color-primary);
animation: pulse-dot 2s infinite;
flex-shrink: 0;
}
@keyframes pulse-dot {
0%, 100% { box-shadow: 0 0 0 0 rgba(10, 124, 89, 0.40); } /* #0a7c59 */
50% { box-shadow: 0 0 0 6px rgba(10, 124, 89, 0); }
}
/* ─── Tag / Chip ────────────────────────────────────────────────────────── */
.chip {
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 5px 12px; /* was 0.25rem 0.625rem — more comfortable */
background: var(--color-surface-el);
border: 1px solid var(--color-border);
border-radius: 9999px;
font-size: 13px; /* was 0.75rem (12px) */
color: var(--color-text-secondary);
transition: all var(--transition);
}
.chip:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
.chip.active {
background: var(--color-primary-dim);
border-color: var(--color-primary);
color: var(--color-primary);
}
/* ─── Mono numeric values ───────────────────────────────────────────────── */
.num {
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
}
/* ─── Gradient Text ─────────────────────────────────────────────────────── */
/* Gradient text is decorative — not subject to contrast requirements by WCAG
(SC 1.4.3 exempts "decorative" text). However, the old stops (#10b981 and
lighter) were far too light on a white background and visually illegible.
Updated to start from the darker end of the emerald scale. */
.text-gradient-emerald {
background: linear-gradient(135deg, #065f46, #0a7c59, #059669);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.text-gradient-fire {
background: linear-gradient(135deg, #f43f5e, #f59e0b);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.text-gradient-indigo {
background: linear-gradient(135deg, #6366f1, #8b5cf6, #a78bfa);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* ─── Staggered Card Entrance ───────────────────────────────────────────── */
@keyframes card-enter {
from { opacity: 0; transform: translateY(16px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
.card-enter {
animation: card-enter 0.4s ease-out backwards;
}
.card-enter-1 { animation-delay: 0.05s; }
.card-enter-2 { animation-delay: 0.1s; }
.card-enter-3 { animation-delay: 0.15s; }
.card-enter-4 { animation-delay: 0.2s; }
.card-enter-5 { animation-delay: 0.25s; }
.card-enter-6 { animation-delay: 0.3s; }
.card-enter-7 { animation-delay: 0.35s; }
.card-enter-8 { animation-delay: 0.4s; }
/* ─── Signature Progress Bar ────────────────────────────────────────────── */
.progress-petition {
height: 6px;
background: var(--color-surface-el);
border-radius: 3px;
overflow: visible;
position: relative;
margin-top: 6px;
}
.progress-petition-fill {
height: 100%;
border-radius: 3px;
background: linear-gradient(90deg, var(--color-primary), #34d399);
transition: width 1s ease-out;
position: relative;
}
.progress-petition-fill::after {
content: '';
position: absolute;
right: 0;
top: -3px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--color-primary);
box-shadow: 0 0 8px rgba(10, 124, 89, 0.45); /* updated to match #0a7c59 */
}
/* ─── Section Accent Labels ─────────────────────────────────────────────── */
/* Minimum 12px for uppercase labels — 11px is below the practical WCAG
readability floor. 12px uppercase with weight 700 qualifies as large text
(bold text at 14px CSS ≈ 10.5pt, border of the WCAG large text definition).
Bumping from 11px to 12px keeps it on the safe side of that boundary. */
.section-accent-label {
font-size: 12px; /* raised from 11px — minimum safe uppercase size */
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.10em; /* reduced slightly — 0.12em at 12px was tight */
color: var(--color-primary);
display: flex;
align-items: center;
gap: 6px;
}
.section-accent-label::before {
content: '◆';
font-size: 0.5rem;
}
/* ─── Ribbon / Corner Badges ────────────────────────────────────────────── */
.ribbon {
position: absolute;
top: 12px;
right: -8px;
padding: 2px 12px 2px 8px;
font-size: 0.6rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
color: white;
z-index: 2;
clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 50%, calc(100% - 8px) 100%, 0 100%, 6px 50%);
}
/* Ribbons use white text. Contrast audit against white:
ribbon-hot (#f43f5e → #ef4444): darkest stop #ef4444 = 4.1:1 — borderline.
Darkened to #c81e1e (7.0:1) to pass AAA for this tiny 0.6rem text.
ribbon-new (#10b981 → #059669): updated to use current token values;
#0a7c59 = 5.51:1 on white — PASS. Old #10b981 = 3.5:1 on white — FAIL.
ribbon-urgent (#f59e0b → #d97706): white on amber = 3.03:1 — FAIL.
Changed to dark amber fill (#b45309, 5.5:1 on white) instead of gradient.
ribbon-trending (#6366f1 → #8b5cf6): darkest stop #6366f1 = 5.9:1 — PASS. */
.ribbon-hot { background: linear-gradient(135deg, #e11d48, #c81e1e); }
.ribbon-new { background: linear-gradient(135deg, #0a7c59, #065f46); }
.ribbon-urgent { background: #b45309; color: white; } /* dark amber — 5.50:1 on white */
.ribbon-trending { background: linear-gradient(135deg, #4f46e5, #6366f1); }
/* ─── Particle Background ───────────────────────────────────────────────── */
@keyframes float-particle {
0%, 100% { transform: translateY(0) translateX(0); opacity: 0.3; }
25% { transform: translateY(-10px) translateX(5px); opacity: 0.6; }
50% { transform: translateY(-5px) translateX(-3px); opacity: 0.4; }
75% { transform: translateY(-15px) translateX(8px); opacity: 0.5; }
}
.particles-bg {
position: relative;
overflow: hidden;
}
.particles-bg::before,
.particles-bg::after {
content: '';
position: absolute;
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--color-primary);
opacity: 0.2;
pointer-events: none;
}
.particles-bg::before {
top: 20%; left: 15%;
animation: float-particle 6s ease-in-out infinite;
}
.particles-bg::after {
top: 60%; right: 20%;
animation: float-particle 8s ease-in-out infinite 2s;
}
/* ─── Typewriter Cursor ─────────────────────────────────────────────────── */
@keyframes typewriter-cursor {
0%, 100% { border-right-color: var(--color-primary); }
50% { border-right-color: transparent; }
}
.typewriter {
overflow: hidden;
white-space: nowrap;
border-right: 2px solid var(--color-primary);
animation: typewriter-cursor 0.8s step-end infinite;
width: fit-content;
max-width: 100%;
}
/* ─── Animated Gradient Border (conic-gradient rotating) ────────────────── */
@property --gradient-angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
@keyframes gradient-rotate {
0% { --gradient-angle: 0deg; }
100% { --gradient-angle: 360deg; }
}
.border-animated {
position: relative;
border: none !important;
background: var(--color-surface);
border-radius: var(--radius-lg);
isolation: isolate;
}
.border-animated::before {
content: '';
position: absolute;
inset: -2px;
border-radius: calc(var(--radius-lg) + 2px);
background: conic-gradient(from var(--gradient-angle), #10b981, #6366f1, #f43f5e, #f59e0b, #10b981);
animation: gradient-rotate 4s linear infinite;
z-index: -1;
}
.border-animated::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--radius-lg);
background: var(--color-surface);
z-index: -1;
}
/* ─── Avatar Stack ───────────────────────────────────────────────────────── */
.avatar-stack {
display: flex;
align-items: center;
}
.avatar-stack .avatar-circle {
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid var(--color-surface);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.6rem;
font-weight: 700;
color: white;
margin-left: -8px;
position: relative;
transition: transform 150ms ease;
}
.avatar-stack .avatar-circle:first-child {
margin-left: 0;
}
.avatar-stack .avatar-circle:hover {
transform: translateY(-3px) scale(1.15);
z-index: 10;
}
.avatar-overflow {
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid var(--color-surface);
background: var(--color-surface-el);
color: var(--color-text-muted);
font-size: 0.55rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
margin-left: -8px;
}
/* ─── Breathing Glow (pulsing box-shadow on urgent items) ────────────────── */
@keyframes breathe-glow {
0%, 100% { box-shadow: 0 0 0 0 rgba(10, 124, 89, 0.15); } /* #0a7c59 */
50% { box-shadow: 0 0 20px 4px rgba(10, 124, 89, 0.15); }
}
@keyframes breathe-glow-urgent {
0%, 100% { box-shadow: 0 0 0 0 rgba(244, 63, 94, 0.15); }
50% { box-shadow: 0 0 20px 4px rgba(244, 63, 94, 0.15); }
}
.breathe-glow {
animation: breathe-glow 3s ease-in-out infinite;
}
.breathe-glow-urgent {
animation: breathe-glow-urgent 2.5s ease-in-out infinite;
}
/* ─── Keyboard Shortcut Hints ────────────────────────────────────────────── */
.kbd {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 20px;
height: 18px;
padding: 0 4px;
border-radius: 4px;
border: 1px solid var(--color-border);
background: var(--color-surface-el);
font-family: var(--font-mono);
font-size: 0.55rem;
font-weight: 600;
color: var(--color-text-muted);
line-height: 1;
}
/* ─── Scroll-Triggered Reveal ────────────────────────────────────────────── */
.reveal-hidden {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.reveal-visible {
opacity: 1;
transform: translateY(0);
}
/* ─── Collapsible Section ───────────────────────────────────────────────── */
.collapsible-header {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
padding: 14px 16px; /* was 12px — slightly taller target */
min-height: 44px;
border-radius: var(--radius-md);
transition: background var(--transition);
user-select: none;
background: none;
border: none;
color: inherit;
font: inherit;
}
.collapsible-header:hover {
background: var(--color-surface-el);
}
.collapsible-header:focus-visible {
outline: 3px solid var(--color-primary-hover);
outline-offset: 2px;
}
.collapsible-chevron {
transition: transform 300ms ease;
flex-shrink: 0;
}
.collapsible-chevron.collapsed {
transform: rotate(-90deg);
}
.collapsible-content {
overflow: hidden;
transition: max-height 300ms ease, opacity 200ms ease;
}
.collapsible-content.collapsed {
max-height: 0 !important;
opacity: 0;
}
/* ─── Mobile Responsive Sidebar ──────────────────────────────────────────── */
.sidebar-backdrop {
display: none;
}
@media (max-width: 768px) {
.sidebar-root {
position: fixed !important;
z-index: 40;
height: 100vh;
transform: translateX(-100%);
transition: transform 0.2s ease, width 0.2s cubic-bezier(0.4, 0, 0.2, 1), min-width 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar-root.sidebar-open {
transform: translateX(0);
}
#mobile-menu-btn {
display: flex !important;
}
.sidebar-backdrop {
display: block;
}
}
/* ─── Mobile Bottom Navigation ──────────────────────────────────────────── */
@media (max-width: 768px) {
.mobile-bottom-nav {
display: block !important;
}
.mobile-main-content {
padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
}
}
/* ─── Signup Wizard — mobile step labels ────────────────────────────────── */
.step-mobile-label {
display: none;
}
.step-label-inactive {
display: inline;
}
@media (max-width: 480px) {
.step-mobile-label {
display: block;
}
.step-label-inactive {
display: none;
}
}
/* ─── Reduced motion ─────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
.spinner {
animation: none !important;
}
}
/* ─── react-grid-layout theme overrides ─────────────────────────────── */
.norma-panel-grid.react-grid-layout {
position: relative;
}
.norma-panel-grid .react-grid-item.react-grid-placeholder {
background: var(--color-primary);
opacity: 0.12;
border-radius: var(--radius-md);
transition-duration: 100ms;
z-index: 2;
}
.norma-panel-grid .react-grid-item {
transition: all 180ms ease;
transition-property: left, top, width, height;
}
.norma-panel-grid .react-grid-item.cssTransforms {
transition-property: transform, width, height;
}
.norma-panel-grid .react-grid-item.resizing {
z-index: 3;
opacity: 0.9;
}
.norma-panel-grid .react-grid-item.react-draggable-dragging {
z-index: 4;
cursor: grabbing;
}
.norma-panel-grid .react-grid-item > .react-resizable-handle {
opacity: 0;
transition: opacity var(--transition);
}
.norma-panel-grid .react-grid-item:hover > .react-resizable-handle {
opacity: 1;
}
.norma-panel-grid .react-grid-item > .react-resizable-handle::after {
border-color: var(--color-text-muted);
}
.panel-drag-handle {
cursor: grab;
}
.panel-drag-handle:active {
cursor: grabbing;
}
.panel-drag-handle:hover {
color: var(--color-text) !important;
background: var(--color-surface) !important;
}
/* ─────────────────────────────────────────────────────────────────────
Age-adaptive theme bands (v9 — 2026-05-12 validated)
Source: ~/.claude/skills/age-adaptive-theme/reference-implementation.html
Each band rewrites the Norma CSS tokens for typography + palette.
Activated by <body data-band="..."> from <AgeThemeSlider />.
Scope: typography + palette only. Does NOT satisfy WCAG 2.1 AA alone.
───────────────────────────────────────────────────────────────────── */
/* AGE 3-5 — Sesame Street primary colors */
body[data-band="toddler"] {
--color-bg: #fff9e6; --color-surface: #fff; --color-surface-el: #fef9c3;
--color-text: #222; --color-text-secondary: #444; --color-text-muted: #666;
--color-border: #f4d000; --color-primary: #ff3b30; --color-primary-hover: #e0322a;
font-family: 'Fredoka', 'Comic Neue', 'Marker Felt', 'Comic Sans MS', sans-serif;
font-size: 24px; line-height: 1.5;
}
body[data-band="toddler"] h1, body[data-band="toddler"] h2 { font-size: 48px; }
/* AGE 6-9 — Elementary (Nunito, Bessemans 2012 — +10-15% reading speed) */
body[data-band="kid"] {
--color-bg: #fff; --color-surface: #fef9c3; --color-surface-el: #fef3c7;
--color-text: #1f2937; --color-text-secondary: #374151; --color-text-muted: #4b5563;
--color-border: #fbbf24; --color-primary: #3b82f6; --color-primary-hover: #2563eb;
font-family: 'Nunito', 'Chalkboard SE', 'Comic Sans MS', sans-serif;
font-size: 18px; line-height: 1.55;
}
body[data-band="kid"] h1, body[data-band="kid"] h2 { font-size: 30px; }
/* AGE 10-12 — Tween (indigo-700 #4338ca, WCAG AA on amber bg) */
body[data-band="tween"] {
--color-bg: #fef3c7; --color-surface: #fff; --color-surface-el: #fef9c3;
--color-text: #1f2937; --color-text-secondary: #374151; --color-text-muted: #6b7280;
--color-border: #fbbf24; --color-primary: #4338ca; --color-primary-hover: #3730a3;
font-family: 'Public Sans', 'Avenir', -apple-system, sans-serif;
font-size: 15px; line-height: 1.5;
}
/* AGE 13-19 — Teen / neon dark mode (Space Grotesk, body 16px) */
body[data-band="teen"] {
--color-bg: #0a0014; --color-surface: #1a0030; --color-surface-el: #2a0050;
--color-text: #f0f0ff; --color-text-secondary: #c5b5e5; --color-text-muted: #8a7fb0;
--color-border: #2a0050; --color-primary: #ff00ff; --color-primary-hover: #cc00cc;
font-family: 'Space Grotesk', 'JetBrains Mono', 'SF Mono', ui-monospace, monospace;
font-size: 16px; line-height: 1.5; letter-spacing: -0.01em;
}
/* AGE 20-44 — Adult (Norma default — DO NOT override, just match) */
body[data-band="adult"] {
/* Inherit defaults from :root in this file. */
font-size: 15px; line-height: 1.5;
}
/* AGE 45-59 — Mature (Source Serif Pro, deepened accent) */
body[data-band="mature"] {
--color-bg: #f8f6f1; --color-surface: #fff; --color-surface-el: #f1ede4;
--color-text: #1c1917; --color-text-secondary: #44403c; --color-text-muted: #57534e;
--color-border: #d6d3d1; --color-primary: #6b1d07; --color-primary-hover: #581605;
font-family: 'Source Serif Pro', 'Georgia', 'Iowan Old Style', serif;
font-size: 15px; line-height: 1.55;
}
body[data-band="mature"] h1, body[data-band="mature"] h2 { font-size: 22px; }
/* AGE 60-79 — Senior, hi-contrast (Atkinson Hyperlegible, Braille Institute) */
body[data-band="senior"] {
--color-bg: #fff; --color-surface: #fff; --color-surface-el: #f5f5f5;
--color-text: #000; --color-text-secondary: #1a1a1a; --color-text-muted: #333;
--color-border: #000; --color-primary: #0050a0; --color-primary-hover: #003d80;
font-family: 'Atkinson Hyperlegible', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 20px; line-height: 1.55;
}
body[data-band="senior"] h1, body[data-band="senior"] h2 { font-size: 30px; }
body[data-band="senior"] button, body[data-band="senior"] .btn { min-height: 48px; }
/* AGE 80+ — Elder, max contrast yellow-on-black */
body[data-band="elder"] {
--color-bg: #000; --color-surface: #000; --color-surface-el: #1a1a1a;
--color-text: #fff; --color-text-secondary: #e0e0e0; --color-text-muted: #cccccc;
--color-border: #fff; --color-primary: #ffff00; --color-primary-hover: #e0e000;
font-family: 'Atkinson Hyperlegible', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 28px; line-height: 1.6;
}
body[data-band="elder"] h1, body[data-band="elder"] h2 { font-size: 44px; }
body[data-band="elder"] button, body[data-band="elder"] .btn { min-height: 56px; }
/* Smooth transitions when sliding the age bar */
body { transition: background-color 0.3s, color 0.3s; }
/* ─────────────────────────────────────────────────────────────────────
INBOX THEMES — 16 live skins for GmailCRMTab.
Activated by data-inbox-theme on the .gmail-crm-tab wrapper from the
Theme dropdown inside the inbox toolbar. Each block re-scopes the Norma
CSS tokens FOR THE INBOX ONLY, so the rest of the app keeps its theme.
Source mockups: /public/mockups/inbox/v1-v16.html
───────────────────────────────────────────────────────────────────── */
/* v1 Classic Dense — current defaults, no overrides */
/* v2 Notion Cards — light, generous, indigo accent */
body[data-inbox-theme="notion-cards"] {
--color-bg: #fafafa; --color-surface: #fff; --color-surface-el: #f4f4f5;
--color-text: #27272a; --color-text-secondary: #52525b; --color-text-muted: #71717a;
--color-border: #e4e4e7; --color-primary: #059669; --color-primary-hover: #047857;
font-family: -apple-system, BlinkMacSystemFont, "Inter", system-ui, sans-serif;
}
/* v3 Linear Keyboard — mono dark, purple accent */
body[data-inbox-theme="linear-keyboard"] {
--color-bg: #08090b; --color-surface: #0e0f12; --color-surface-el: #16181c;
--color-text: #e6e6eb; --color-text-secondary: #b4b6bc; --color-text-muted: #7a7d85;
--color-border: #22252b; --color-primary: #5e6ad2; --color-primary-hover: #4e58b8;
font-family: ui-sans-serif, "Inter", system-ui, sans-serif; letter-spacing: -0.005em;
}
/* v4 Apple Mail — light, sans, blue accent */
body[data-inbox-theme="apple-mail"] {
--color-bg: #f5f5f7; --color-surface: #fff; --color-surface-el: #f9f9fc;
--color-text: #1d1d1f; --color-text-secondary: #424245; --color-text-muted: #86868b;
--color-border: #d2d2d7; --color-primary: #0070f3; --color-primary-hover: #005bcb;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
}
/* v5 Front Conversation — dark teal */
body[data-inbox-theme="front-conversation"] {
--color-bg: #0d1119; --color-surface: #141925; --color-surface-el: #1d2434;
--color-text: #ebebef; --color-text-secondary: #b5bcd0; --color-text-muted: #8a92a8;
--color-border: #2a3148; --color-primary: #00d4ae; --color-primary-hover: #00b894;
}
/* v6 Hey Zero — warm cream + serif */
body[data-inbox-theme="hey-zero"] {
--color-bg: #faf8f3; --color-surface: #fff; --color-surface-el: #f1ede4;
--color-text: #1b1814; --color-text-secondary: #43382d; --color-text-muted: #7a6e5a;
--color-border: #e6dfd1; --color-primary: #c33; --color-primary-hover: #a82424;
font-family: "Source Serif Pro", Georgia, "Iowan Old Style", serif;
}
/* v7 Spotify Dark */
body[data-inbox-theme="spotify-dark"] {
--color-bg: #121212; --color-surface: #181818; --color-surface-el: #282828;
--color-text: #fff; --color-text-secondary: #d4d4d4; --color-text-muted: #a7a7a7;
--color-border: #2a2a2a; --color-primary: #1db954; --color-primary-hover: #1ed760;
font-family: "Circular", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
}
/* v8 Minimal Mono — black on white, Helvetica */
body[data-inbox-theme="minimal-mono"] {
--color-bg: #fff; --color-surface: #fff; --color-surface-el: #fafafa;
--color-text: #000; --color-text-secondary: #333; --color-text-muted: #666;
--color-border: #000; --color-primary: #000; --color-primary-hover: #333;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: -0.005em;
}
/* v9 Newsprint — sepia broadsheet */
body[data-inbox-theme="newsprint"] {
--color-bg: #f1ebdc; --color-surface: #faf5e6; --color-surface-el: #ebe3cf;
--color-text: #1c1410; --color-text-secondary: #443a30; --color-text-muted: #6b5e4f;
--color-border: #a89678; --color-primary: #a8221c; --color-primary-hover: #8a1816;
font-family: "Adobe Caslon Pro", "Caslon", "Hoefler Text", Georgia, serif;
}
/* v10 Glassmorphism — translucent on purple gradient */
body[data-inbox-theme="glassmorphism"] {
--color-bg: #1a0a3a; --color-surface: rgba(255,255,255,0.06); --color-surface-el: rgba(255,255,255,0.10);
--color-text: #fff; --color-text-secondary: #d8d8ff; --color-text-muted: #c8c8ff;
--color-border: rgba(255,255,255,0.15); --color-primary: #7df9ff; --color-primary-hover: #5dd5dc;
background-image: radial-gradient(ellipse at 30% 20%, #4a1f8a 0%, #1a0a3a 50%, #050020 100%);
}
/* v11 Terminal — green phosphor, monospace */
body[data-inbox-theme="terminal"] {
--color-bg: #001100; --color-surface: #002211; --color-surface-el: #003322;
--color-text: #33ff66; --color-text-secondary: #28cc52; --color-text-muted: #1a7a33;
--color-border: #1a4a26; --color-primary: #33ff66; --color-primary-hover: #66ff99;
font-family: "Berkeley Mono", "JetBrains Mono", "SF Mono", ui-monospace, Menlo, monospace;
text-shadow: 0 0 3px rgba(51,255,102,0.3);
}
/* v12 Mochi Pastel — blush + lavender + mint */
body[data-inbox-theme="mochi-pastel"] {
--color-bg: #fdf6f3; --color-surface: #fff; --color-surface-el: #fef0eb;
--color-text: #3a2e2a; --color-text-secondary: #6a5a52; --color-text-muted: #9a8a82;
--color-border: #f0e0d8; --color-primary: #f0a3a3; --color-primary-hover: #e08a8a;
font-family: "Nunito", "Avenir Next", -apple-system, sans-serif;
}
/* v13 High-Contrast A11y — Atkinson Hyperlegible, 18px floor */
body[data-inbox-theme="a11y-high-contrast"] {
--color-bg: #fff; --color-surface: #fff; --color-surface-el: #fffacc;
--color-text: #000; --color-text-secondary: #000; --color-text-muted: #000;
--color-border: #000; --color-primary: #0030c8; --color-primary-hover: #001f88;
font-family: "Atkinson Hyperlegible", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 18px; line-height: 1.6;
}
body[data-inbox-theme="a11y-high-contrast"] button { min-height: 48px; }
/* v14 Material 3 — purple primary, rounded */
body[data-inbox-theme="material"] {
--color-bg: #f8f6fd; --color-surface: #fff; --color-surface-el: #ece7f4;
--color-text: #1c1b1f; --color-text-secondary: #313033; --color-text-muted: #49454f;
--color-border: #cac4d0; --color-primary: #6750a4; --color-primary-hover: #7c69b8;
font-family: "Roboto", "Roboto Flex", -apple-system, sans-serif;
}
/* v15 Synthwave — magenta + cyan on indigo */
body[data-inbox-theme="synthwave"] {
--color-bg: #1a0033; --color-surface: #2a005a; --color-surface-el: #3d0080;
--color-text: #ffd5ff; --color-text-secondary: #d8a8e8; --color-text-muted: #aa8acc;
--color-border: #5a0a8c; --color-primary: #ff2bff; --color-primary-hover: #ff66ff;
font-family: "Space Grotesk", "VT323", monospace, sans-serif;
}
/* v16 Kanban Lanes — Trello palette, light. Note: structural lane layout
is NOT applied via CSS-only; this theme provides palette+typography only.
To get the actual horizontal lanes, see /mockups/inbox/v16-kanban-lanes.html. */
body[data-inbox-theme="kanban-lanes"] {
--color-bg: #f4f5f7; --color-surface: #fff; --color-surface-el: #ebecf0;
--color-text: #172b4d; --color-text-secondary: #344563; --color-text-muted: #5e6c84;
--color-border: #dfe1e6; --color-primary: #0052cc; --color-primary-hover: #003d99;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}
/* ─── INBOX THEMES v17–v32 ─────────────────────────────────────────────── */
/* v17 Ottoman Tile — navy + gold + teal, serif */
body[data-inbox-theme="ottoman-tile"] {
--color-bg: #0a1f33; --color-surface: #102845; --color-surface-el: #19385f;
--color-text: #fef0c8; --color-text-secondary: #e4c290; --color-text-muted: #c4a16a;
--color-border: #3a5278; --color-primary: #d4a437; --color-primary-hover: #b88c20;
font-family: "Cormorant Garamond", "Iowan Old Style", Georgia, serif;
}
/* v18 Brutalist Concrete — raw gray + hot orange */
body[data-inbox-theme="brutalist"] {
--color-bg: #d4d4d0; --color-surface: #c0c0bc; --color-surface-el: #b4b4b0;
--color-text: #1a1a18; --color-text-secondary: #2a2a28; --color-text-muted: #5a5a55;
--color-border: #1a1a18; --color-primary: #ff5400; --color-primary-hover: #cc4300;
font-family: "Helvetica Neue", Arial, sans-serif; letter-spacing: -0.005em;
}
/* v19 Library Catalog — manila + typewriter */
body[data-inbox-theme="library-catalog"] {
--color-bg: #f3e6c8; --color-surface: #e8d8b0; --color-surface-el: #dec99a;
--color-text: #2a1f10; --color-text-secondary: #4e3f24; --color-text-muted: #6e5a3a;
--color-border: #8a6f44; --color-primary: #992014; --color-primary-hover: #7a1810;
font-family: "Courier Prime", "Courier New", "American Typewriter", monospace;
}
/* v20 Wabi-Sabi — earthy clay + sage */
body[data-inbox-theme="wabi-sabi"] {
--color-bg: #ece4d6; --color-surface: #f4ede0; --color-surface-el: #dccfb8;
--color-text: #3a2f24; --color-text-secondary: #5a4a3a; --color-text-muted: #8a7a6a;
--color-border: #a89a82; --color-primary: #a85a3a; --color-primary-hover: #8a4828;
font-family: "Cormorant Garamond", "Iowan Old Style", Georgia, serif;
}
/* v21 Cyberpunk Rain — black + acid green + hot pink */
body[data-inbox-theme="cyberpunk-rain"] {
--color-bg: #000; --color-surface: #0a0a14; --color-surface-el: #10101e;
--color-text: #00ff41; --color-text-secondary: #6acc70; --color-text-muted: #3a8a4a;
--color-border: #143514; --color-primary: #ff003c; --color-primary-hover: #cc0030;
font-family: "Berkeley Mono", "Share Tech Mono", "JetBrains Mono", ui-monospace, monospace;
}
/* v22 Bauhaus — cream + primary colors */
body[data-inbox-theme="bauhaus"] {
--color-bg: #f4f0e6; --color-surface: #fff; --color-surface-el: #ece6d4;
--color-text: #1a1a1a; --color-text-secondary: #333; --color-text-muted: #666;
--color-border: #1a1a1a; --color-primary: #e63946; --color-primary-hover: #c62939;
font-family: "Futura", "Avenir Next", "Helvetica Neue", sans-serif; letter-spacing: -0.01em;
}
/* v23 Memphis 80s — playful pink/teal/yellow, dotted bg */
body[data-inbox-theme="memphis"] {
--color-bg: #f5f4eb; --color-surface: #fff; --color-surface-el: #fff2d4;
--color-text: #1a1a26; --color-text-secondary: #3a3a4a; --color-text-muted: #5e5e6e;
--color-border: #1a1a26; --color-primary: #ff5fa2; --color-primary-hover: #e0438a;
font-family: "Futura", "Avenir Next", sans-serif;
}
/* v24 Vellum Manuscript — parchment + illuminated */
body[data-inbox-theme="vellum"] {
--color-bg: #f7eed0; --color-surface: #fcf6dc; --color-surface-el: #eadda3;
--color-text: #3a1f0c; --color-text-secondary: #5a3818; --color-text-muted: #8a6840;
--color-border: #c4a060; --color-primary: #a8201a; --color-primary-hover: #881810;
font-family: "Cormorant Garamond", "EB Garamond", Georgia, serif;
}
/* v25 Solarpunk — sage + ochre */
body[data-inbox-theme="solarpunk"] {
--color-bg: #f0ead2; --color-surface: #fffbeb; --color-surface-el: #e0e0bc;
--color-text: #1f3320; --color-text-secondary: #3f5040; --color-text-muted: #5d7553;
--color-border: #90a878; --color-primary: #578a4a; --color-primary-hover: #467038;
font-family: "Quattrocento Sans", "Open Sans", -apple-system, sans-serif;
}
/* v26 Frutiger Aero — y2k glossy blue */
body[data-inbox-theme="frutiger-aero"] {
--color-bg: #d6edff; --color-surface: #fff; --color-surface-el: #eaf4ff;
--color-text: #1c3a5c; --color-text-secondary: #3a5e80; --color-text-muted: #5e7a98;
--color-border: #a8c8e8; --color-primary: #34b5e8; --color-primary-hover: #1c9ad0;
font-family: "Segoe UI", "Frutiger", -apple-system, sans-serif;
}
/* v27 Crossword Grid — pure b&w, courier */
body[data-inbox-theme="crossword"] {
--color-bg: #fff; --color-surface: #fff; --color-surface-el: #f2f2f2;
--color-text: #000; --color-text-secondary: #2a2a2a; --color-text-muted: #666;
--color-border: #000; --color-primary: #1856ad; --color-primary-hover: #134290;
font-family: "Courier Prime", "Courier New", "American Typewriter", monospace;
}
/* v28 8-Bit Pixel — NES palette */
body[data-inbox-theme="pixel-8bit"] {
--color-bg: #2c3e50; --color-surface: #34495e; --color-surface-el: #1a252f;
--color-text: #ecf0f1; --color-text-secondary: #bdc3c7; --color-text-muted: #95a5a6;
--color-border: #000; --color-primary: #f1c40f; --color-primary-hover: #d4a800;
font-family: "Press Start 2P", "VT323", "Courier New", monospace;
}
/* v29 Watercolor — soft pastels with painterly bg */
body[data-inbox-theme="watercolor"] {
--color-bg: #f8f4ed; --color-surface: #fefcf7; --color-surface-el: #f0eadb;
--color-text: #3a4a52; --color-text-secondary: #5a6a72; --color-text-muted: #7a8a93;
--color-border: #c8c0b0; --color-primary: #d68a99; --color-primary-hover: #c06a7c;
font-family: "EB Garamond", "Cormorant Garamond", Georgia, serif;
}
/* v30 Sakura — pink + white + black, minimal japanese */
body[data-inbox-theme="sakura"] {
--color-bg: #fff9fa; --color-surface: #fff; --color-surface-el: #fdf0f2;
--color-text: #1a0a14; --color-text-secondary: #4a3a44; --color-text-muted: #8a6878;
--color-border: #f2c8d2; --color-primary: #e8597c; --color-primary-hover: #c8395c;
font-family: "Shippori Mincho", "Noto Serif JP", "Hiragino Mincho ProN", "Yu Mincho", serif;
}
/* v31 Forest Walk — mossy green + bark */
body[data-inbox-theme="forest-walk"] {
--color-bg: #1c2418; --color-surface: #2a3424; --color-surface-el: #3a4632;
--color-text: #e8e0c8; --color-text-secondary: #c4ba9a; --color-text-muted: #9aa080;
--color-border: #4a5638; --color-primary: #7a9c48; --color-primary-hover: #5a7c30;
font-family: "Lora", "Iowan Old Style", Georgia, serif;
}
/* v32 Botanical Print — field-guide cream + leaf green + copper */
body[data-inbox-theme="botanical"] {
--color-bg: #f4ede0; --color-surface: #fdfaf0; --color-surface-el: #e6d8c0;
--color-text: #1a2818; --color-text-secondary: #3a4628; --color-text-muted: #5a6648;
--color-border: #8a9a78; --color-primary: #2a5028; --color-primary-hover: #1a3a18;
font-family: "Cormorant Garamond", "EB Garamond", Georgia, serif;
}
/* v1 Classic Dense — defensive explicit selector. Restores :root tokens in case
a previously-applied theme set any vars not overridden by a sibling theme.
Without this, switching FROM (say) ottoman-tile BACK TO classic-dense relies
on CSS cascade alone — works in practice but fragile if any base var is ever
left unset by another theme. With this, classic-dense is a positive reset. */
body[data-inbox-theme="classic-dense"] {
--color-bg: #f5f5f7;
--color-surface: #ffffff;
--color-surface-el: #f0f0f2;
--color-text: #1a1a2e;
--color-text-secondary: #4a4a5e;
--color-text-muted: #585e6b;
--color-border: #e2e4e9;
--color-primary: #0a7c59;
--color-primary-hover: #065f46;
font-family: -apple-system, BlinkMacSystemFont, "Inter", "Plus Jakarta Sans", system-ui, sans-serif;
}