Files
flxn-app/src/themes/cassette/theme.css
T
2026-08-23 17:17:04 -07:00

551 lines
20 KiB
CSS

/* Cassette Futurism — 1970s NASA/Braun control-deck instrument panel.
Light: warm beige enclosure with recessed panel seams and rounded-rect
modules in varied beige tones; buttons read as physical keys (top bevel,
1px darker base edge, press sinks 1px). Dark: powered-down deck with
glowing indicator lamps. Ramps/autoContrast live in manifest.ts; this
file carries shape, seams, and the physical-key/readout language. */
/* ---------- 1. Tokens, any scheme — (0,2,0) ---------- */
[data-theme="cassette"][data-theme] {
--mantine-font-family: "Jost", ui-sans-serif, system-ui, sans-serif;
--mantine-font-family-headings: "Jost", ui-sans-serif, system-ui, sans-serif;
--mantine-font-family-monospace: "Space Mono", ui-monospace, "SFMono-Regular",
monospace;
--mantine-heading-font-weight: 600;
--mantine-radius-xs: 6px;
--mantine-radius-sm: 8px;
--mantine-radius-md: 10px;
--mantine-radius-lg: 14px;
--mantine-radius-xl: 20px;
--mantine-radius-default: 10px;
--flxn-avatar-radius: 14px;
--flxn-avatar-border: 2px solid var(--mantine-color-default-border);
--flxn-badge-radius: 8px;
/* uppercase micro-label treatment shared by controls (buttons, badges,
tabs, toggles) — the "labeled toggle" panel aesthetic */
--cassette-label-font: "Space Mono", ui-monospace, monospace;
--cassette-label-tracking: 0.045em;
/* fine enclosure grain, tiled, baked-in low opacity */
--cassette-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
}
/* ---------- 2. Per-scheme tokens — (0,3,0) ---------- */
[data-theme="cassette"][data-theme][data-mantine-color-scheme="light"] {
--mantine-color-body: #ece4d4;
--mantine-color-text: #2c2620;
--mantine-color-bright: #1b1712;
--mantine-color-dimmed: #6b6255;
--mantine-color-placeholder: #857b6c;
--mantine-color-anchor: var(--mantine-primary-color-filled);
--mantine-color-error: #a43f2d;
--mantine-color-default: #f1ebdd;
--mantine-color-default-hover: #e4dcc8;
--mantine-color-default-color: #2c2620;
--mantine-color-default-border: #b9ad95;
--cassette-module: #f1ebdd;
--cassette-module-alt: #e7dfc9;
--cassette-seam-hi: rgba(255, 255, 255, 0.6);
--cassette-seam-lo: rgba(44, 38, 30, 0.28);
--cassette-well: rgba(44, 38, 30, 0.14);
--mantine-shadow-xs: inset 0 1px 0 var(--cassette-seam-hi),
0 1px 2px rgba(44, 38, 30, 0.18);
--mantine-shadow-sm: inset 0 1px 0 var(--cassette-seam-hi),
0 1px 2px rgba(44, 38, 30, 0.2), 0 2px 6px rgba(44, 38, 30, 0.12);
--mantine-shadow-md: inset 0 1px 0 var(--cassette-seam-hi),
0 3px 8px rgba(44, 38, 30, 0.18);
--mantine-shadow-lg: inset 0 1px 0 var(--cassette-seam-hi),
0 6px 16px rgba(44, 38, 30, 0.2);
--mantine-shadow-xl: inset 0 1px 0 var(--cassette-seam-hi),
0 10px 28px rgba(44, 38, 30, 0.24);
--flxn-gold: #ac7c19;
--flxn-silver: #837259;
--flxn-bronze: #9e4b1b;
--flxn-toast-success: #587a34;
--flxn-toast-error: #a43f2d;
--flxn-podium-1-bg: color-mix(in srgb, var(--mantine-color-yellow-5) 16%, #f6f1e6);
--flxn-podium-1-border: var(--mantine-color-yellow-7);
--flxn-podium-1-label: var(--mantine-color-yellow-9);
--flxn-podium-2-bg: color-mix(in srgb, var(--mantine-color-gray-5) 16%, #f6f1e6);
--flxn-podium-2-border: var(--mantine-color-gray-6);
--flxn-podium-2-label: var(--mantine-color-gray-8);
--flxn-podium-3-bg: color-mix(in srgb, var(--mantine-color-orange-5) 14%, #f6f1e6);
--flxn-podium-3-border: var(--mantine-color-orange-7);
--flxn-podium-3-label: var(--mantine-color-orange-9);
--flxn-showcase-bg: #f6f1e6;
--flxn-overlay: rgba(33, 28, 22, 0.45);
--flxn-dotgrid-color: #cabf9f;
--flxn-pop-shadow: rgba(44, 38, 30, 0.3);
}
[data-theme="cassette"][data-theme][data-mantine-color-scheme="dark"] {
--mantine-color-body: #211e19;
--mantine-color-text: #d8d0c0;
--mantine-color-bright: #f2ece0;
--mantine-color-dimmed: #8f8574;
--mantine-color-placeholder: #6f6656;
--mantine-color-anchor: var(--mantine-primary-color-light-color);
--mantine-color-error: #e2685a;
--mantine-color-default: #2a251f;
--mantine-color-default-hover: #332d25;
--mantine-color-default-color: #d8d0c0;
--mantine-color-default-border: #4a4335;
--cassette-module: #2a251f;
--cassette-module-alt: #241f19;
--cassette-seam-hi: rgba(255, 255, 255, 0.07);
--cassette-seam-lo: rgba(0, 0, 0, 0.55);
--cassette-well: rgba(0, 0, 0, 0.5);
--mantine-shadow-xs: inset 0 1px 0 var(--cassette-seam-hi),
0 1px 2px rgba(0, 0, 0, 0.5);
--mantine-shadow-sm: inset 0 1px 0 var(--cassette-seam-hi),
0 2px 6px rgba(0, 0, 0, 0.55);
--mantine-shadow-md: inset 0 1px 0 var(--cassette-seam-hi),
0 4px 12px rgba(0, 0, 0, 0.55);
--mantine-shadow-lg: inset 0 1px 0 var(--cassette-seam-hi),
0 8px 20px rgba(0, 0, 0, 0.6);
--mantine-shadow-xl: inset 0 1px 0 var(--cassette-seam-hi),
0 14px 32px rgba(0, 0, 0, 0.65);
--flxn-gold: #e0ac2c;
--flxn-silver: #a89c88;
--flxn-bronze: #d47237;
--flxn-toast-success: #86ac56;
--flxn-toast-error: #e2685a;
--flxn-podium-1-bg: color-mix(in srgb, var(--mantine-color-yellow-7) 26%, #241f19);
--flxn-podium-1-border: var(--mantine-color-yellow-5);
--flxn-podium-1-label: var(--mantine-color-yellow-3);
--flxn-podium-2-bg: color-mix(in srgb, var(--mantine-color-gray-6) 20%, #241f19);
--flxn-podium-2-border: var(--mantine-color-gray-4);
--flxn-podium-2-label: var(--mantine-color-gray-2);
--flxn-podium-3-bg: color-mix(in srgb, var(--mantine-color-orange-7) 26%, #241f19);
--flxn-podium-3-border: var(--mantine-color-orange-5);
--flxn-podium-3-label: var(--mantine-color-orange-3);
--flxn-showcase-bg: #241f19;
--flxn-overlay: rgba(0, 0, 0, 0.6);
--flxn-dotgrid-color: #3a352c;
--flxn-pop-shadow: rgba(0, 0, 0, 0.55);
}
/* ---------- 3. Enclosure texture: seams + grain (1 fixed overlay) ---------- */
[data-theme="cassette"] body {
background-color: var(--mantine-color-body);
background-image: var(--cassette-grain);
}
/* ---------- 4. AppShell: top bezel + seam rules ---------- */
[data-theme="cassette"] .mantine-AppShell-header {
background-color: var(--cassette-module);
border-bottom: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 -1px 0 var(--cassette-seam-hi),
0 2px 6px rgba(0, 0, 0, 0.12);
}
[data-theme="cassette"] .mantine-AppShell-header .mantine-Title-root {
font-family: var(--cassette-label-font);
text-transform: uppercase;
letter-spacing: var(--cassette-label-tracking);
}
[data-theme="cassette"] .mantine-AppShell-navbar {
background-color: var(--cassette-module);
border-inline-end: 1px solid var(--mantine-color-default-border);
}
[data-theme="cassette"] nav[role="navigation"].mantine-Paper-root {
background-color: var(--cassette-module);
border: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), var(--mantine-shadow-md);
}
/* ---------- 5. Buttons & ActionIcons: physical keys ---------- */
[data-theme="cassette"] .mantine-Button-root,
[data-theme="cassette"] .mantine-ActionIcon-root {
border-radius: var(--mantine-radius-md);
border: 1px solid var(--mantine-color-default-border);
font-family: var(--cassette-label-font);
font-weight: 700;
text-transform: uppercase;
letter-spacing: var(--cassette-label-tracking);
transition: transform 100ms ease, box-shadow 100ms ease;
}
[data-theme="cassette"] .mantine-Button-root[data-variant="default"],
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="default"] {
background-color: var(--cassette-module);
border-bottom: 3px solid color-mix(in srgb, var(--mantine-color-default-border) 70%, var(--mantine-color-bright));
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
color: var(--mantine-color-text);
}
[data-theme="cassette"] .mantine-Button-root[data-variant="filled"],
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="filled"],
[data-theme="cassette"] .mantine-Button-root:not([data-variant]),
[data-theme="cassette"] .mantine-ActionIcon-root:not([data-variant]) {
background-color: var(--mantine-primary-color-filled);
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 55%, black);
border-bottom: 3px solid color-mix(in srgb, var(--mantine-primary-color-filled) 45%, black);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
color: var(--mantine-primary-color-contrast);
}
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Button-root[data-variant="filled"],
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-ActionIcon-root[data-variant="filled"],
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Button-root:not([data-variant]),
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-ActionIcon-root:not([data-variant]) {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),
0 0 8px color-mix(in srgb, var(--mantine-primary-color-filled) 55%, transparent);
}
[data-theme="cassette"] .mantine-Button-root[data-variant="light"],
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="light"] {
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 40%, transparent);
}
[data-theme="cassette"] .mantine-Button-root[data-variant="subtle"],
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="subtle"],
[data-theme="cassette"] .mantine-Button-root[data-variant="transparent"],
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="transparent"] {
border-color: transparent;
border-bottom-width: 1px;
}
/* pressed state — static sink cue, always on (no motion required) */
[data-theme="cassette"] .mantine-Button-root:active:not(:disabled):not([data-disabled]):not([data-loading]),
[data-theme="cassette"] .mantine-ActionIcon-root:active:not(:disabled):not([data-disabled]):not([data-loading]) {
border-bottom-width: 1px;
box-shadow: inset 0 2px 4px var(--cassette-well);
}
[data-theme="cassette"] .mantine-Button-root:disabled,
[data-theme="cassette"] .mantine-Button-root[data-disabled],
[data-theme="cassette"] .mantine-ActionIcon-root:disabled,
[data-theme="cassette"] .mantine-ActionIcon-root[data-disabled] {
box-shadow: none;
border-bottom-width: 1px;
}
/* the actual 1px sink — guarded, motion-only */
@media (prefers-reduced-motion: no-preference) {
[data-theme="cassette"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
transform: translateY(1px);
}
}
/* ---------- 6. Inputs: recessed readout wells ---------- */
[data-theme="cassette"] .mantine-Input-input {
background-color: var(--cassette-module-alt);
border: 1px solid var(--mantine-color-default-border);
border-radius: var(--mantine-radius-sm);
font-family: var(--cassette-label-font);
box-shadow: inset 0 1px 3px var(--cassette-well);
}
[data-theme="cassette"] .mantine-Input-input:focus,
[data-theme="cassette"] .mantine-Input-input:focus-within {
border-color: var(--mantine-primary-color-filled);
outline: none;
box-shadow: inset 0 1px 3px var(--cassette-well),
0 0 0 3px color-mix(in srgb, var(--mantine-primary-color-filled) 28%, transparent);
}
[data-theme="cassette"] .mantine-PinInput-field {
font-family: var(--cassette-label-font);
}
/* ---------- 7. Panels: Paper, Card, Modal, Popover, Notification, Alert ---------- */
[data-theme="cassette"] .mantine-Paper-root,
[data-theme="cassette"] .mantine-Card-root,
[data-theme="cassette"] .mantine-Popover-dropdown,
[data-theme="cassette"] .mantine-Modal-content,
[data-theme="cassette"] .mantine-Notification-root,
[data-theme="cassette"] .mantine-Alert-root {
background-color: var(--cassette-module);
border: 1px solid var(--mantine-color-default-border);
}
[data-theme="cassette"] .mantine-Paper-root,
[data-theme="cassette"] .mantine-Card-root {
box-shadow: var(--mantine-shadow-sm);
}
[data-theme="cassette"] .mantine-Modal-content {
box-shadow: var(--mantine-shadow-xl);
}
[data-theme="cassette"] .mantine-Modal-header {
background-color: var(--cassette-module-alt);
border-bottom: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
}
[data-theme="cassette"] .mantine-Tooltip-tooltip {
background-color: var(--mantine-color-bright);
color: var(--mantine-color-body);
border: 1px solid var(--mantine-color-default-border);
font-family: var(--cassette-label-font);
font-size: 0.75rem;
}
/* ---------- 8. Tabs & SegmentedControl: labeled toggles ---------- */
[data-theme="cassette"] .mantine-Tabs-tab {
font-family: var(--cassette-label-font);
font-weight: 700;
text-transform: uppercase;
letter-spacing: var(--cassette-label-tracking);
}
[data-theme="cassette"] .mantine-Tabs-tab[data-active] {
border-color: var(--mantine-primary-color-filled);
color: var(--mantine-primary-color-filled);
}
[data-theme="cassette"] .mantine-SegmentedControl-root {
background-color: var(--cassette-module-alt);
border: 1px solid var(--mantine-color-default-border);
border-radius: var(--mantine-radius-md);
box-shadow: inset 0 1px 3px var(--cassette-well);
}
[data-theme="cassette"] .mantine-SegmentedControl-label {
font-family: var(--cassette-label-font);
text-transform: uppercase;
letter-spacing: var(--cassette-label-tracking);
font-size: 0.7rem;
}
[data-theme="cassette"] .mantine-SegmentedControl-indicator {
background-color: var(--cassette-module);
border: 1px solid var(--mantine-color-default-border);
border-radius: var(--mantine-radius-sm);
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), 0 1px 2px var(--cassette-well);
}
/* ---------- 9. Badges, ThemeIcon, Checkbox/Radio, Switch ---------- */
[data-theme="cassette"] .mantine-Badge-root {
border: 1px solid var(--mantine-color-default-border);
border-radius: var(--mantine-radius-sm);
font-family: var(--cassette-label-font);
letter-spacing: var(--cassette-label-tracking);
}
[data-theme="cassette"] .mantine-ThemeIcon-root {
border: 1px solid var(--mantine-color-default-border);
}
[data-theme="cassette"] .mantine-Checkbox-input,
[data-theme="cassette"] .mantine-Radio-radio {
border: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 1px 2px var(--cassette-well);
}
/* checked-glyph on-color is hardcoded white by Mantine regardless of
autoContrast; recompute per accent so amber/lime checks stay legible */
[data-theme="cassette"] .mantine-Checkbox-root {
--checkbox-icon-color: var(--mantine-primary-color-contrast);
}
[data-theme="cassette"] .mantine-Radio-root {
--radio-icon-color: var(--mantine-primary-color-contrast);
}
[data-theme="cassette"] .mantine-Switch-track {
border: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 1px 3px var(--cassette-well);
}
[data-theme="cassette"] .mantine-Switch-thumb {
border: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), 0 1px 2px var(--cassette-well);
}
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Switch-input:checked + .mantine-Switch-track {
box-shadow: inset 0 1px 3px var(--cassette-well),
0 0 6px color-mix(in srgb, var(--mantine-primary-color-filled) 60%, transparent);
}
/* ---------- 10. Progress: VU meter with tick marks ---------- */
[data-theme="cassette"] .mantine-Progress-root {
position: relative;
background-color: var(--cassette-module-alt);
border: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 1px 3px var(--cassette-well);
}
[data-theme="cassette"] .mantine-Progress-root::after {
content: "";
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
background-image: repeating-linear-gradient(
90deg,
var(--mantine-color-default-border) 0 1px,
transparent 1px 12.5%
);
opacity: 0.6;
}
[data-theme="cassette"] .mantine-Progress-section {
background-color: var(--mantine-primary-color-filled);
background-image: linear-gradient(
180deg,
rgba(255, 255, 255, 0.32) 0%,
rgba(255, 255, 255, 0.05) 45%,
rgba(0, 0, 0, 0.1) 100%
);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Progress-section {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16),
0 0 6px color-mix(in srgb, var(--mantine-primary-color-filled) 65%, transparent);
}
/* ---------- 11. Divider: tape-window (two reel circles + line) ---------- */
[data-theme="cassette"] .mantine-Divider-root {
position: relative;
--divider-color: var(--mantine-color-default-border);
}
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::before,
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::after {
content: "";
position: absolute;
top: 50%;
width: 8px;
height: 8px;
border-radius: 50%;
transform: translateY(-50%);
background-color: var(--cassette-module);
border: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 1px 1px var(--cassette-well), inset 0 -1px 0 var(--cassette-seam-hi);
pointer-events: none;
}
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::before {
left: 42%;
}
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::after {
left: 58%;
}
/* ---------- 12. App hooks: tab strip ---------- */
[data-theme="cassette"] .flxn-tabs[data-stuck] {
background-color: var(--cassette-module);
border-bottom-color: var(--mantine-color-default-border);
box-shadow: inset 0 -1px 0 var(--cassette-seam-hi);
}
[data-theme="cassette"] .flxn-tab {
font-family: var(--cassette-label-font);
font-weight: 700;
text-transform: uppercase;
letter-spacing: var(--cassette-label-tracking);
font-size: 0.75rem;
}
/* underline indicator (not a filled pill), so accent text stays legible */
[data-theme="cassette"] .flxn-tab[data-active]::before {
content: "";
display: inline-block;
width: 6px;
height: 6px;
margin-inline-end: 6px;
border-radius: 50%;
background-color: var(--mantine-primary-color-filled);
vertical-align: middle;
}
[data-theme="cassette"][data-mantine-color-scheme="dark"] .flxn-tab[data-active]::before {
box-shadow: 0 0 5px color-mix(in srgb, var(--mantine-primary-color-filled) 80%, transparent);
}
[data-theme="cassette"] .flxn-tabs-indicator {
border-bottom: 3px solid var(--mantine-primary-color-filled);
}
[data-theme="cassette"][data-mantine-color-scheme="dark"] .flxn-tabs-indicator {
box-shadow: none;
}
/* ---------- 13. App hooks: nav tiles ---------- */
[data-theme="cassette"] .flxn-tile {
background-color: var(--cassette-module);
border: 1px solid var(--mantine-color-default-border);
border-bottom: 3px solid color-mix(in srgb, var(--mantine-color-default-border) 70%, var(--mantine-color-bright));
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
transition: transform 100ms ease, box-shadow 100ms ease;
}
[data-theme="cassette"] .flxn-tile:active {
border-bottom-width: 1px;
box-shadow: inset 0 2px 4px var(--cassette-well);
}
@media (prefers-reduced-motion: no-preference) {
[data-theme="cassette"] .flxn-tile.flxn-press:active {
transform: translateY(1px);
}
}
/* flat tint — no plate behind the glyph */
[data-theme="cassette"] .flxn-tile-icon {
color: var(--mantine-primary-color-light-color);
}
/* ---------- 14. App hooks: see-all as a labeled key chip ---------- */
[data-theme="cassette"] .flxn-see-all {
border-radius: var(--mantine-radius-sm);
border: 1px solid color-mix(in srgb, var(--mantine-primary-color-filled) 45%, transparent);
background-color: var(--mantine-primary-color-light);
color: var(--mantine-primary-color-light-color);
font-family: var(--cassette-label-font);
font-weight: 700;
text-transform: uppercase;
letter-spacing: var(--cassette-label-tracking);
font-size: 0.7rem;
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
}
/* ---------- 15. App hooks: match card + reaction tray ---------- */
[data-theme="cassette"] .flxn-match-card {
background-color: var(--cassette-module);
border: 1px solid var(--mantine-color-default-border);
box-shadow: var(--mantine-shadow-sm);
}
[data-theme="cassette"] .flxn-reaction-row {
background-color: var(--cassette-module-alt);
border: 1px solid var(--mantine-color-default-border);
box-shadow: inset 0 2px 4px var(--cassette-well);
}
/* ---------- 16. App hooks: avatar frame (porthole bezel) ---------- */
[data-theme="cassette"] .flxn-avatar-frame {
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), inset 0 -1px 2px var(--cassette-well);
}