diff --git a/web/src/index.css b/web/src/index.css new file mode 100644 index 0000000..8e254ea --- /dev/null +++ b/web/src/index.css @@ -0,0 +1,211 @@ +@import "tailwindcss"; +@import "@fontsource/instrument-serif/index.css"; +@import "@fontsource/instrument-serif/400-italic.css"; +@import "@fontsource/inter/400.css"; +@import "@fontsource/inter/500.css"; +@import "@fontsource/inter/600.css"; +@import "@fontsource/ibm-plex-mono/400.css"; +@import "@fontsource/ibm-plex-mono/500.css"; +@import "@fontsource/vazirmatn/400.css"; +@import "@fontsource/vazirmatn/500.css"; + +@theme { + /* Ink — warm near-blacks, control-room at night (dark theme defaults) */ + --color-ink-950: oklch(0.145 0.004 75); + --color-ink-900: oklch(0.175 0.005 75); + --color-ink-850: oklch(0.205 0.006 75); + --color-ink-800: oklch(0.24 0.007 75); + --color-ink-700: oklch(0.32 0.008 75); + + /* Paper — warm off-whites */ + --color-paper: oklch(0.93 0.012 85); + --color-paper-dim: oklch(0.68 0.012 85); + --color-paper-faint: oklch(0.48 0.01 85); + + /* The one accent: brass, like watch hands */ + --color-brass: oklch(0.79 0.105 84); + --color-brass-dim: oklch(0.62 0.08 84); + + /* Status — semantic, deliberately desaturated */ + --color-up: oklch(0.74 0.105 158); + --color-warn: oklch(0.78 0.125 78); + --color-down: oklch(0.64 0.185 28); + --color-idle: oklch(0.52 0.012 80); + + --font-sans: "Inter", "Vazirmatn", ui-sans-serif, system-ui, sans-serif; + --font-display: "Instrument Serif", "Vazirmatn", ui-serif, serif; + --font-mono: "IBM Plex Mono", "Vazirmatn", ui-monospace, monospace; + --font-rtl: "Vazirmatn", ui-sans-serif, sans-serif; + + --ease-settle: cubic-bezier(0.22, 1, 0.36, 1); +} + +:root { + color-scheme: dark; + /* atmosphere knobs, re-tuned per theme */ + --veil-glow: oklch(0.32 0.04 84 / 0.1); + --veil-edge: oklch(0.1 0.004 75 / 0.75); + --grain-opacity: 0.035; + --dial-opacity: 0.62; + --panel-shadow: 0 32px 80px -16px rgba(0, 0, 0, 0.8); +} + +/* ——— light theme: the observatory at noon — warm paper, dark ink ——— */ +html[data-theme="light"] { + color-scheme: light; + + --color-ink-950: oklch(0.965 0.007 90); + --color-ink-900: oklch(0.99 0.004 90); + --color-ink-850: oklch(0.93 0.009 90); + --color-ink-800: oklch(0.885 0.011 88); + --color-ink-700: oklch(0.79 0.013 86); + + --color-paper: oklch(0.25 0.014 75); + --color-paper-dim: oklch(0.43 0.014 78); + --color-paper-faint: oklch(0.56 0.012 80); + + --color-brass: oklch(0.6 0.115 80); + --color-brass-dim: oklch(0.5 0.09 80); + + --color-up: oklch(0.55 0.115 158); + --color-warn: oklch(0.6 0.13 75); + --color-down: oklch(0.55 0.185 28); + --color-idle: oklch(0.62 0.012 80); + + --veil-glow: oklch(0.88 0.035 84 / 0.5); + --veil-edge: oklch(0.82 0.012 85 / 0.4); + --grain-opacity: 0.025; + --dial-opacity: 0.1; + --panel-shadow: 0 32px 80px -24px oklch(0.3 0.02 80 / 0.35); +} + +html, +body { + height: 100%; +} + +body { + background: var(--color-ink-950); + color: var(--color-paper); + font-family: var(--font-sans); + font-size: 14px; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + overflow-x: hidden; + transition: background-color 0.4s var(--ease-settle); +} + +/* Farsi mode: Vazirmatn carries body text; the serif stays for latin numerals */ +html[dir="rtl"] body { + font-family: var(--font-rtl); + letter-spacing: 0 !important; +} + +/* Atmosphere: vignette + faint warm glow from the top */ +body::before { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + z-index: 0; + background: + radial-gradient(120% 90% at 50% -10%, var(--veil-glow), transparent 55%), + radial-gradient(140% 140% at 50% 50%, transparent 55%, var(--veil-edge) 100%); +} + +/* Film grain, pure SVG noise — keeps flat fields from feeling dead. + No blend mode: plain alpha composites cheaply on its own layer. */ +body::after { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + z-index: 50; + opacity: var(--grain-opacity); + transform: translateZ(0); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); +} + +/* the nano-banana machined dial under the orbital */ +.dial-backdrop { + position: absolute; + inset: 0; + pointer-events: none; + background-size: 100% 100%; + opacity: var(--dial-opacity); + mask-image: radial-gradient(circle at center, black 40%, transparent 72%); + transition: opacity 0.4s var(--ease-settle); +} + +/* isolate the orbital's continuous repaints from the rest of the page */ +.orbital-stage { + contain: layout paint; + will-change: transform; +} + +::selection { + background: var(--color-brass); + color: var(--color-ink-950); +} + +:focus-visible { + outline: 1px solid var(--color-brass); + outline-offset: 3px; + border-radius: 2px; +} + +::-webkit-scrollbar { + width: 10px; + height: 10px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-thumb { + background: var(--color-ink-800); + border: 3px solid var(--color-ink-950); + border-radius: 6px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--color-ink-700); +} + +/* Mono micro-labels — the system's connective tissue */ +.microlabel { + font-family: var(--font-mono); + font-size: 10px; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--color-paper-faint); +} +html[dir="rtl"] .microlabel { + font-family: var(--font-rtl); + letter-spacing: 0; + font-size: 11px; +} + +.tabular { + font-variant-numeric: tabular-nums; +} + +/* Hairline rule with a soft fade at both ends */ +.rule-fade { + height: 1px; + background: linear-gradient( + to right, + transparent, + var(--color-ink-700) 18%, + var(--color-ink-700) 82%, + transparent + ); +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +}