Repository Public
1@import 'tailwindcss';23/*4 * Design tokens. `@theme` holds the LIGHT theme (the default, also what renders before any5 * script runs); `[data-theme='dark']` overrides the same variables. `data-theme` is set on6 * <html> by /theme-init.js (blocking, same-origin) and by the theme store.7 * Text-capable tokens (text, text-2, muted, accent, success, warning, error, info-ink) meet8 * WCAG AA on bg/surface/surface-2 in both themes — verified by dev/check-contrast.mjs.9 * `*-vivid` tokens are for fills (dots, bars, rings), never for text.10 */11@theme {12 --color-bg: #f7f6f3;13 --color-surface: #ffffff;14 --color-surface-2: #f2f1ed;15 --color-elevated: #ffffff;16 --color-text: #17181c;17 --color-text-2: #555b69;18 --color-muted: #626876;19 --color-faint: #8e94a3;20 --color-accent: #a04a06;21 --color-accent-2: #d9620f;22 --color-accent-fg: #ffffff;23 /* Brand gradient stops (mark, primary CTA, phone home header) + ink for text on a white pill over it. */24 --color-brand-1: #f7a614;25 --color-brand-2: #f5840f;26 --color-brand-3: #e8590c;27 --color-brand-ink: #8f3f04;28 --color-brand-fg: #2b1400;29 --color-term-text: #e6e8ee;30 --color-term-dim: #9aa3b2;31 --color-diff-add: #0c70491f;32 --color-diff-del: #bf2c341c;33 --color-info: #3b7ff5;34 --color-info-ink: #1d4fc4;35 --color-info-fg: #ffffff;36 --color-success: #0c7049;37 --color-warning: #805800;38 --color-error: #bf2c34;39 --color-success-vivid: #1fa971;40 --color-warning-vivid: #e0a100;41 --color-error-vivid: #e5484d;42 --color-line: #0000000f;43 --color-line-2: #00000017;44 --color-line-3: #0000002e;45 --color-card-line: #0000000a;46 --color-hover: #0000000a;47 --color-scrim: #17182059;48 --color-term-bg: #16181d;49 --radius-sm: 10px;50 --radius-md: 16px;51 --radius-lg: 22px;52 --shadow-card: 0 1px 2px #1718200a, 0 4px 14px -6px #1718201a;53 --shadow-float: 0 2px 6px #1718200f, 0 12px 32px -10px #17182033;54 --shadow-pop: 0 4px 12px #17182014, 0 24px 56px -16px #17182047;55 --font-sans: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, 'Helvetica Neue', sans-serif;56 --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;57 --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);58 --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);59}6061[data-theme='dark'] {62 --color-bg: #080b10;63 --color-surface: #10151d;64 --color-surface-2: #161d27;65 --color-elevated: #1d2632;66 --color-text: #f4f7fb;67 --color-text-2: #a1adbd;68 --color-muted: #8492a6;69 --color-faint: #5d6a7d;70 --color-accent: #ffa64d;71 --color-accent-2: #ff8a3d;72 --color-accent-fg: #221000;73 --color-info: #5b9bff;74 --color-info-ink: #93bcff;75 --color-info-fg: #06142e;76 --color-success: #42c995;77 --color-warning: #e7b86b;78 --color-error: #f08080;79 --color-success-vivid: #42c995;80 --color-warning-vivid: #e7b86b;81 --color-error-vivid: #ed7777;82 --color-line: #ffffff0f;83 --color-line-2: #ffffff17;84 --color-line-3: #ffffff2b;85 --color-card-line: #ffffff14;86 --color-hover: #ffffff12;87 --color-scrim: #00000099;88 --color-term-bg: #05070a;89 --color-brand-ink: #ffb366;90 --color-diff-add: #42c99526;91 --color-diff-del: #ed777726;92 --shadow-card: 0 1px 2px #00000040;93 --shadow-float: 0 8px 24px -8px #000000a6;94 --shadow-pop: 0 16px 48px -12px #000000cc;95 color-scheme: dark;96}9798@layer base {99 html {100 color-scheme: light;101 }102 html,103 body {104 height: 100%;105 background: var(--color-bg);106 color: var(--color-text);107 -webkit-text-size-adjust: 100%;108 overscroll-behavior: none;109 }110 body {111 font-family: var(--font-sans);112 font-size: 13px;113 line-height: 1.5;114 -webkit-font-smoothing: antialiased;115 -webkit-tap-highlight-color: transparent;116 font-feature-settings: 'ss01', 'cv11';117 }118 *,119 ::before,120 ::after {121 border-color: var(--color-line-2);122 }123 :focus-visible {124 outline: 2px solid var(--color-accent);125 outline-offset: 1px;126 }127 ::selection {128 background: color-mix(in srgb, var(--color-accent) 30%, transparent);129 }130 button {131 cursor: pointer;132 }133 button:disabled {134 cursor: not-allowed;135 }136 /* Real inputs never go below 16px on touch devices: iOS zooms the page otherwise. */137 @media (pointer: coarse) {138 input,139 textarea,140 select {141 font-size: 16px !important;142 }143 }144 * {145 scrollbar-width: thin;146 scrollbar-color: var(--color-line-3) transparent;147 }148}149150@layer components {151 /* Elevated surface: soft layered shadow in light, hairline in dark. */152 .card {153 background: var(--color-surface);154 border: 1px solid var(--color-card-line);155 border-radius: var(--radius-md);156 box-shadow: var(--shadow-card);157 }158 /* Brand gradient: mark, primary call to action, phone home header, activity accents only. */159 .bg-brand {160 background-image: linear-gradient(135deg, var(--color-brand-1) 0%, var(--color-brand-2) 55%, var(--color-brand-3) 115%);161 color: var(--color-brand-fg);162 }163 .text-brand {164 background-image: linear-gradient(120deg, var(--color-accent) 0%, var(--color-accent-2) 110%);165 -webkit-background-clip: text;166 background-clip: text;167 color: transparent;168 }169 .pressable {170 transition: transform 140ms var(--ease-out), box-shadow 140ms var(--ease-out);171 }172 .pressable:active {173 transform: scale(0.97);174 }175 /* Skeleton / indeterminate shimmer (never a fake percentage). */176 .shimmer {177 background-image: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--color-text) 9%, transparent) 50%, transparent 80%);178 background-size: 200% 100%;179 animation: aos-shimmer 1.4s linear infinite;180 }181 .shimmer-accent {182 background-image: linear-gradient(100deg, transparent 0%, var(--color-accent) 45%, var(--color-accent-2) 55%, transparent 100%);183 background-size: 220% 100%;184 animation: aos-shimmer 1.6s linear infinite;185 }186 .glass {187 background: color-mix(in srgb, var(--color-surface) 78%, transparent);188 -webkit-backdrop-filter: saturate(1.6) blur(18px);189 backdrop-filter: saturate(1.6) blur(18px);190 }191 .tnum {192 font-variant-numeric: tabular-nums;193 }194 .app-viewport {195 /* Height is driven by window.visualViewport (see useVisualViewport); 100dvh is the fallback. */196 height: var(--vvh, 100dvh);197 }198 .pt-safe {199 padding-top: env(safe-area-inset-top);200 }201 .pb-safe {202 padding-bottom: env(safe-area-inset-bottom);203 }204 .px-safe {205 padding-left: env(safe-area-inset-left);206 padding-right: env(safe-area-inset-right);207 }208 .no-scrollbar {209 scrollbar-width: none;210 }211 .no-scrollbar::-webkit-scrollbar {212 display: none;213 }214}215216@keyframes aos-fade-in {217 from {218 opacity: 0;219 }220}221@keyframes aos-pop-in {222 from {223 opacity: 0;224 transform: translateY(4px) scale(0.985);225 }226}227@keyframes aos-slide-right {228 from {229 transform: translateX(100%);230 }231}232@keyframes aos-slide-left {233 from {234 transform: translateX(-100%);235 }236}237@keyframes aos-slide-up {238 from {239 transform: translateY(100%);240 }241}242@keyframes aos-shimmer {243 from {244 background-position: 120% 0;245 }246 to {247 background-position: -120% 0;248 }249}250@keyframes aos-ping {251 0% {252 transform: scale(1);253 opacity: 0.55;254 }255 100% {256 transform: scale(2.6);257 opacity: 0;258 }259}260@keyframes aos-draw {261 to {262 stroke-dashoffset: 0;263 }264}265@keyframes aos-pulse {266 50% {267 opacity: 0.45;268 }269}270.anim-fade {271 animation: aos-fade-in 140ms var(--ease-out);272}273.anim-pop {274 animation: aos-pop-in 160ms var(--ease-out);275}276.anim-slide-right {277 animation: aos-slide-right 200ms var(--ease-out);278}279.anim-slide-left {280 animation: aos-slide-left 200ms var(--ease-out);281}282.anim-slide-up {283 animation: aos-slide-up 200ms var(--ease-out);284}285.anim-ping {286 animation: aos-ping 1.8s var(--ease-out) infinite;287}288.anim-draw {289 stroke-dasharray: 1;290 stroke-dashoffset: 1;291 animation: aos-draw 420ms 80ms var(--ease-out) forwards;292}293/* Cross-fade while the theme changes (class added for ~300 ms by the theme store). */294html.theme-fade,295html.theme-fade * {296 transition: background-color 260ms ease, border-color 260ms ease, color 200ms ease, fill 200ms ease, box-shadow 260ms ease !important;297}298.anim-pulse {299 animation: aos-pulse 1.6s ease-in-out infinite;300}301@media (prefers-reduced-motion: reduce) {302 *,303 ::before,304 ::after {305 animation-duration: 1ms !important;306 animation-iteration-count: 1 !important;307 transition-duration: 1ms !important;308 scroll-behavior: auto !important;309 }310}311