Spaces:
Running
Running
File size: 11,086 Bytes
5f3e9f5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | @tailwind base;
@tailwind components;
@tailwind utilities;
/* βββ Theme tokens βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Palette is stored as space-separated RGB triplets so Tailwind's
`rgb(var(--brand-500) / <alpha-value>)` pattern works. The Settings page
overrides these at runtime to re-skin the whole app.
The remaining tokens (surface / line / text) are also exposed as CSS vars
so we can tune the system once and have every surface react. Light and
dark are both intentionally near-monochrome β the brand color does the
accenting; surfaces stay quiet. */
:root {
/* Default brand: refined indigo (#4f46e5 scale). Settings can override. */
--brand-50: 238 242 255;
--brand-100: 224 231 255;
--brand-200: 199 210 254;
--brand-300: 165 180 252;
--brand-400: 129 140 248;
--brand-500: 99 102 241;
--brand-600: 79 70 229;
--brand-700: 67 56 202;
--brand-800: 55 48 163;
--brand-900: 49 46 129;
/* Neutral surfaces (light). */
--bg-app: 250 250 252; /* page background */
--bg-surface: 255 255 255; /* cards, sidebar, inputs */
--bg-muted: 246 247 250; /* hover, subtle backgrounds */
--bg-strong: 244 244 248; /* selected rows, kbd */
--line: 226 230 238; /* primary border */
--line-soft: 235 238 245; /* hairline / divider */
--text-strong: 15 23 42; /* headings */
--text: 30 41 59; /* body */
--text-muted: 100 116 139; /* secondary */
--text-faint: 148 163 184; /* tertiary */
}
.dark {
--bg-app: 9 11 17;
--bg-surface: 17 20 27;
--bg-muted: 22 26 34;
--bg-strong: 28 33 43;
--line: 39 45 58;
--line-soft: 30 36 48;
--text-strong: 248 250 252;
--text: 226 232 240;
--text-muted: 148 163 184;
--text-faint: 100 116 139;
}
@layer base {
html,
body,
#root {
@apply h-full;
}
html {
/* Inter ships with stylistic alternates β `cv11` gives a single-storey
`a`, `ss01` evens out punctuation. Both are part of why Linear, Vercel,
Stripe, Resend etc. all look the same: it's the Inter feature stack. */
font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11', 'ss01';
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
body {
@apply font-sans antialiased;
color: rgb(var(--text));
background-color: rgb(var(--bg-app));
}
/* Headings get tighter tracking + a hair more weight than the body. */
h1, h2, h3, h4, h5, h6 {
@apply font-display tracking-tight;
color: rgb(var(--text-strong));
}
/* Numbers should align in stat tiles, table cells, durations, etc. */
.tabular,
[data-slot='number'] {
font-variant-numeric: tabular-nums;
}
/* Selection uses the brand color at low alpha. */
::selection {
background-color: rgb(var(--brand-500) / 0.18);
color: rgb(var(--text-strong));
}
/* App scrollbars: thin, near-invisible, lifts on hover. */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-thumb {
background-color: rgb(var(--line));
border: 2px solid transparent;
background-clip: padding-box;
border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover {
background-color: rgb(var(--text-faint));
background-clip: padding-box;
}
::-webkit-scrollbar-track {
background: transparent;
}
}
@layer components {
/* βββ Surfaces ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
`.glass` is kept as the primary card surface for backwards compat with
every page that already uses the name. The new look is: white surface,
1px hairline, almost-invisible shadow. No glassmorphism β just a quiet,
flat card. */
.surface {
background-color: rgb(var(--bg-surface));
border: 1px solid rgb(var(--line));
@apply rounded-xl;
}
.glass {
@apply surface shadow-glass;
}
.glass-strong {
@apply surface shadow-glass-lg;
}
.card { @apply glass p-6; }
.card-sm { @apply glass p-4; }
.divider {
height: 1px;
background-color: rgb(var(--line-soft));
}
/* βββ Typography helpers βββββββββββββββββββββββββββββββββββββββββββββββ */
.eyebrow {
@apply inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-[0.14em];
color: rgb(var(--text-muted));
}
.h-page {
@apply font-display text-2xl font-semibold tracking-tight md:text-3xl;
color: rgb(var(--text-strong));
}
.h-section {
@apply font-display text-base font-semibold tracking-tight;
color: rgb(var(--text-strong));
}
.text-muted { color: rgb(var(--text-muted)); }
.text-faint { color: rgb(var(--text-faint)); }
/* βββ Buttons βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
A single `.btn` base, then variants. Every variant has a visible focus
ring (a11y), a subtle hover, and an `active:` press state. */
.btn {
@apply relative inline-flex select-none items-center justify-center gap-2
rounded-lg px-3.5 py-2 text-sm font-medium leading-none
transition duration-150 ease-out
disabled:cursor-not-allowed disabled:opacity-50
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-400/60
focus-visible:ring-offset-2 focus-visible:ring-offset-[rgb(var(--bg-app))];
}
.btn-primary {
@apply btn bg-brand-600 text-white shadow-sm
hover:bg-brand-500
active:bg-brand-700;
}
.btn-secondary {
@apply btn text-slate-800 dark:text-slate-100;
background-color: rgb(var(--bg-surface));
border: 1px solid rgb(var(--line));
}
.btn-secondary:hover {
background-color: rgb(var(--bg-muted));
}
.btn-secondary:active {
background-color: rgb(var(--bg-strong));
}
.btn-ghost {
@apply btn bg-transparent;
color: rgb(var(--text-muted));
}
.btn-ghost:hover {
color: rgb(var(--text-strong));
background-color: rgb(var(--bg-muted));
}
.btn-danger {
@apply btn bg-rose-600 text-white shadow-sm
hover:bg-rose-500
active:bg-rose-700
focus-visible:ring-rose-400/60;
}
.btn-sm { @apply px-2.5 py-1.5 text-xs; }
.btn-lg { @apply px-5 py-2.5 text-[15px]; }
/* βββ Form controls βββββββββββββββββββββββββββββββββββββββββββββββββββ */
.input,
.textarea,
.select {
@apply w-full rounded-lg px-3.5 py-2.5 text-sm leading-snug
transition-colors duration-150
placeholder:text-[rgb(var(--text-faint))]
focus:outline-none;
background-color: rgb(var(--bg-surface));
border: 1px solid rgb(var(--line));
color: rgb(var(--text-strong));
}
.input:hover,
.textarea:hover,
.select:hover {
border-color: rgb(var(--text-faint) / 0.7);
}
.input:focus,
.textarea:focus,
.select:focus {
@apply ring-2 ring-brand-400/40;
border-color: rgb(var(--brand-500));
}
.label {
@apply mb-1.5 block text-[11px] font-semibold uppercase tracking-[0.12em];
color: rgb(var(--text-muted));
}
/* βββ Badges / pills βββββββββββββββββββββββββββββββββββββββββββββββββββ */
.badge {
@apply inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-[11px] font-medium leading-none;
border: 1px solid rgb(var(--line));
background-color: rgb(var(--bg-muted));
color: rgb(var(--text-muted));
height: 22px;
}
.badge-success { @apply badge border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-500/30 dark:bg-emerald-500/10 dark:text-emerald-300; }
.badge-running { @apply badge border-sky-200 bg-sky-50 text-sky-700 dark:border-sky-500/30 dark:bg-sky-500/10 dark:text-sky-300; }
.badge-error { @apply badge border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-500/30 dark:bg-rose-500/10 dark:text-rose-300; }
.badge-warning { @apply badge border-amber-200 bg-amber-50 text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200; }
.badge-info { @apply badge border-indigo-200 bg-indigo-50 text-indigo-700 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-300; }
.badge-neutral { @apply badge; }
/* βββ Misc ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
.kbd {
@apply inline-flex h-5 items-center rounded border px-1.5 font-mono text-[10px] font-medium;
background-color: rgb(var(--bg-strong));
border-color: rgb(var(--line));
color: rgb(var(--text-muted));
}
/* Subtle dotted background used behind hero / empty states. */
.dot-grid {
background-image: radial-gradient(rgb(var(--line)) 1px, transparent 1px);
background-size: 22px 22px;
background-position: -1px -1px;
}
}
@layer utilities {
/* Centered max-width container used by list / dashboard pages. */
.container-page {
@apply mx-auto w-full max-w-6xl;
}
/* Narrower container for single-task / form-driven pages
(wizards, settings, single-form tools). */
.container-form {
@apply mx-auto w-full max-w-5xl;
}
/* Sticky action bar used at the bottom of long forms / wizards.
Sits flush with the viewport bottom, gets a hairline top border
and a soft surface tint so it reads above the form content. */
.sticky-action-bar {
@apply sticky bottom-0 z-10 -mx-4 mt-4 flex flex-wrap items-center gap-3
border-t px-4 py-3 backdrop-blur md:-mx-10 md:px-10;
border-color: rgb(var(--line));
background-color: rgb(var(--bg-app) / 0.85);
}
/* Subtle entrance animation for the main column. */
@keyframes app-fade-in {
from { opacity: 0; transform: translateY(2px); }
to { opacity: 1; transform: none; }
}
.animate-app-fade-in {
animation: app-fade-in 240ms ease-out both;
}
/* Shimmer highlight used by the progress bar while a run is working. */
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(250%); }
}
}
|