@import 'tailwindcss'; @import 'tw-animate-css'; @import 'shadcn-svelte/tailwind.css'; @import './fonts.css'; @variant dark (&:where(.dark, .dark *)); /* The values below are the Mono color theme; applyColorTheme in color-theme-util.ts overrides the neutrals and the primary family at runtime */ :root { --h-xs: 26px; --h-sm: 34px; --h-md: 42px; --h-lg: 48px; --h-xl: 48px; --row-dense: 36px; --row: 44px; --row-2line: 52px; --col-auth: 464px; --col-content: 1120px; /* The identity column gives way on tablets so the other columns fit without scrolling sideways */ --table-id-max: clamp(240px, 36vw, 440px); --sidebar-w: 256px; --rail-w: 60px; --dialog-sm: 420px; --dialog-md: 480px; --dialog-lg: 560px; --sheet-w: 560px; --palette-w: 640px; --toast-w: 340px; --clear-end-phone: 148px; --z-sticky: 10; --z-nav: 20; --z-bar: 30; --z-overlay: 40; --z-popover: 50; --z-toast: 60; --z-tooltip: 70; --z-progress: 80; --halo-width: 3px; --selection-border: 1.5px; --dur-fast: 120ms; --dur-base: 200ms; --dur-slow: 280ms; --rise: 4px; --nudge: 2px; --slide: 24px; --press-scale: 0.98; --pop-scale: 0.96; --t-success-hold: 800ms; --t-redirect-fallback: 3000ms; --t-dim-delay: 200ms; --t-skeleton-delay: 150ms; --t-pulse: 1600ms; --t-spin: 800ms; --t-caret: 1000ms; --t-progress: 3000ms; --canvas: #ffffff; --surface: #ffffff; --surface-raised: #ffffff; --surface-sunken: #f5f5f5; --fill-muted: #f2f2f2; --fill-hover: #eeeeee; --fill-row-hover: #fafafa; --fill-selected: #ebebeb; --fill-skeleton: #eeeeee; --border: #e8e8e8; --border-strong: #8c8c8c; --border-control: #8c8c8c; --fg: #0a0a0a; --fg-muted: #5e5e5e; --fg-subtle: #a3a3a3; --inverse: #111111; --inverse-fg: #fafafa; --inverse-muted: #b5b5b5; --inverse-hover: #262626; --inverse-border: transparent; --success-solid: #319751; --success-fg: #206b38; --success-soft: #ebfaed; --success-border: #bcdfc2; --warning-solid: #c5770f; --warning-fg: #864e18; --warning-soft: #fff6e4; --warning-border: #eecf9c; --danger-solid: #d73337; --danger-fg: #b32228; --danger-soft: #fff1f0; --danger-border: #f9c1bf; --danger-fill: #c52b30; --danger-fill-hover: #b32228; --danger-fill-fg: #ffffff; --info-solid: #5e5e5e; --info-fg: #0a0a0a; --info-soft: #f5f5f5; --info-border: #e8e8e8; --well-light: #f5f5f5; --well-dark: #000000; --well-light-fg: #5e5e5e; --well-dark-fg: #a1a1a1; --qr-bg: #ffffff; --scrim: rgb(18 17 16 / 0.4); --ring: #0a0a0a; --ring-halo: rgb(10 10 10 / 0.24); --elevation-popover: 0 1px 2px rgb(31 29 27 / 0.06), 0 8px 24px -6px rgb(31 29 27 / 0.14); --elevation-overlay: 0 2px 4px rgb(31 29 27 / 0.06), 0 16px 40px -8px rgb(31 29 27 / 0.2); --elevation-thumb: 0 1px 2px rgb(0 0 0 / 0.2); --elevation-selected: 0 1px 2px rgb(31 29 27 / 0.06), 0 4px 14px rgb(31 29 27 / 0.07); --border-selected: color-mix(in oklab, var(--border-strong) 40%, var(--border)); --sidebar: #fafafa; --primary: #0a0a0a; --primary-foreground: #ffffff; --primary-hover: #262626; --primary-control: #0a0a0a; --primary-control-foreground: #ffffff; --primary-edge: transparent; --fw-display-l: 600; --fw-display-m: 600; /* shadcn-svelte variables, mapped onto the tokens above so the ui/ components keep their class names */ --background: var(--canvas); --foreground: var(--fg); --card: var(--surface); --card-foreground: var(--fg); --popover: var(--surface-raised); --popover-foreground: var(--fg); --secondary: var(--fill-muted); --secondary-foreground: var(--fg); --muted: var(--fill-muted); --muted-foreground: var(--fg-muted); --accent: var(--fill-hover); --accent-foreground: var(--fg); --destructive: var(--danger-fg); --destructive-foreground: var(--danger-fill-fg); --warning: var(--warning-soft); --warning-foreground: var(--warning-fg); --input: var(--fill-muted); --sidebar-foreground: var(--fg); --sidebar-primary: var(--primary); --sidebar-primary-foreground: var(--primary-foreground); --sidebar-accent: var(--fill-selected); --sidebar-accent-foreground: var(--fg); --sidebar-border: var(--border); --sidebar-ring: var(--ring); } .dark { --canvas: #000000; --surface: #000000; --surface-raised: #121212; --surface-sunken: #0e0e0e; --fill-muted: #171717; --fill-hover: #1a1a1a; --fill-row-hover: #0c0c0c; --fill-selected: #1f1f1f; --fill-skeleton: #1a1a1a; --border: #1f1f1f; --border-strong: #6b6b6b; --border-control: #6b6b6b; --fg: #ededed; --fg-muted: #a1a1a1; --fg-subtle: #5c5c5c; --inverse: #1f1f1f; --inverse-fg: #ededed; --inverse-muted: #b5b5b5; --inverse-hover: #2e2e2e; --inverse-border: #333333; --success-solid: #54b66e; --success-fg: #83d494; --success-soft: #1a2b1d; --success-border: #2c5235; --warning-solid: #eba941; --warning-fg: #f5ca7a; --warning-soft: #342611; --warning-border: #68491a; --danger-solid: #f45a56; --danger-fg: #ff8f8d; --danger-soft: #3b1e1e; --danger-border: #813939; --danger-fill: #c52b30; --danger-fill-hover: #b32228; --danger-fill-fg: #ffffff; --info-solid: #a1a1a1; --info-fg: #ededed; --info-soft: #0e0e0e; --info-border: #1f1f1f; --well-light: #f5f5f5; --well-dark: #000000; --well-light-fg: #5e5e5e; --well-dark-fg: #a1a1a1; --qr-bg: #ffffff; --scrim: rgb(0 0 0 / 0.6); --ring: #ededed; --ring-halo: rgb(237 237 237 / 0.24); --elevation-popover: 0 1px 2px rgb(0 0 0 / 0.4), 0 8px 24px -6px rgb(0 0 0 / 0.6); --elevation-overlay: 0 2px 4px rgb(0 0 0 / 0.4), 0 16px 40px -8px rgb(0 0 0 / 0.7); --elevation-thumb: 0 1px 2px rgb(0 0 0 / 0.5); --elevation-selected: 0 1px 2px rgb(0 0 0 / 0.4), 0 4px 14px rgb(0 0 0 / 0.5); --sidebar: #0a0a0a; --primary: #ededed; --primary-foreground: #000000; --primary-hover: #d6d6d6; --primary-control: #ededed; --primary-control-foreground: #000000; --primary-edge: transparent; --fw-display-l: 500; --fw-display-m: 500; color-scheme: dark; } /* Reduced motion: the OS setting and the Disable animations setting share one token collapse */ html.no-motion { --dur-fast: 0ms; --dur-base: 0ms; --dur-slow: 0ms; --rise: 0px; --nudge: 0px; --slide: 0px; --press-scale: 1; --pop-scale: 1; --t-pulse: 0ms; --t-caret: 0ms; --t-progress: 0ms; --t-spin: 1200ms; } @media (prefers-reduced-motion: reduce) { :root { --dur-fast: 0ms; --dur-base: 0ms; --dur-slow: 0ms; --rise: 0px; --nudge: 0px; --slide: 0px; --press-scale: 1; --pop-scale: 1; --t-pulse: 0ms; --t-caret: 0ms; --t-progress: 0ms; --t-spin: 1200ms; } } /* Safety net for motion that does not read the tokens (bits-ui keyframes, svelte-sonner): only spinners and scroll-linked fades keep moving */ html.no-motion *:not(.animate-spin, .scroll-fade-x, .scroll-fade-y), html.no-motion *::before, html.no-motion *::after { animation-duration: 0s !important; transition-duration: 0s !important; } @media (prefers-reduced-motion: reduce) { *:not(.animate-spin, .scroll-fade-x, .scroll-fade-y), *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; } } /* Set for two frames by setModeInstantly, so light and dark swap at once instead of fading control by control */ html.theme-switching *, html.theme-switching *::before, html.theme-switching *::after { transition: none !important; } @theme { --font-sans: 'Funnel Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif; --font-display: 'Funnel Display', 'Funnel Sans', ui-sans-serif, system-ui, sans-serif; --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace; --radius-xs: 6px; --radius-sm: 10px; --radius-md: 12px; --radius-lg: 16px; --radius-xl: 20px; --radius-2xl: 24px; --radius-3xl: 28px; --radius-4xl: 32px; --ease-out: cubic-bezier(0.2, 0, 0, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --ease-in: cubic-bezier(0.4, 0, 1, 1); } @theme inline { --text-display-l: 34px; --text-display-l--line-height: 42px; --text-display-l--font-weight: var(--fw-display-l); --text-display-l--letter-spacing: -0.02em; --text-display-m: 28px; --text-display-m--line-height: 36px; --text-display-m--font-weight: var(--fw-display-m); --text-display-m--letter-spacing: -0.015em; --text-display-s: 22px; --text-display-s--line-height: 30px; --text-display-s--font-weight: 500; --text-display-s--letter-spacing: -0.01em; --text-title: 18px; --text-title--line-height: 26px; --text-title--font-weight: 600; --text-title--letter-spacing: 0em; --text-heading: 15px; --text-heading--line-height: 22px; --text-heading--font-weight: 600; --text-heading--letter-spacing: 0em; --text-body-l: 17px; --text-body-l--line-height: 26px; --text-body-l--font-weight: 400; --text-body-l--letter-spacing: 0em; --text-body: 15px; --text-body--line-height: 22px; --text-body--font-weight: 400; --text-body--letter-spacing: 0em; --text-control: 14px; --text-control--line-height: 20px; --text-control--font-weight: 400; --text-control--letter-spacing: 0em; --text-caption: 13px; --text-caption--line-height: 18px; --text-caption--font-weight: 400; --text-caption--letter-spacing: 0em; --text-micro: 12px; --text-micro--line-height: 16px; --text-micro--font-weight: 500; --text-micro--letter-spacing: 0.01em; --text-mono: 14px; --text-mono--line-height: 20px; --text-mono--font-weight: 400; --text-mono--letter-spacing: 0em; --text-mono-s: 13px; --text-mono-s--line-height: 18px; --text-mono-s--font-weight: 400; --text-mono-s--letter-spacing: 0em; --text-code-cell: 30px; --text-code-cell--line-height: 38px; --text-code-cell--font-weight: 500; --text-code-cell--letter-spacing: 0em; --shadow-popover: var(--elevation-popover); --shadow-overlay: var(--elevation-overlay); --shadow-thumb: var(--elevation-thumb); --shadow-selected: var(--elevation-selected); --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-destructive-foreground: var(--destructive-foreground); --color-warning: var(--warning); --color-warning-foreground: var(--warning-foreground); --color-input: var(--input); --color-ring: var(--ring); --color-ring-halo: var(--ring-halo); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); --color-scrim: var(--scrim); --color-canvas: var(--canvas); --color-surface: var(--surface); --color-surface-raised: var(--surface-raised); --color-surface-sunken: var(--surface-sunken); --color-fill-muted: var(--fill-muted); --color-fill-hover: var(--fill-hover); --color-fill-row-hover: var(--fill-row-hover); --color-fill-selected: var(--fill-selected); --color-fill-skeleton: var(--fill-skeleton); --color-border: var(--border); --color-border-strong: var(--border-strong); --color-border-selected: var(--border-selected); --color-fg: var(--fg); --color-fg-muted: var(--fg-muted); --color-fg-subtle: var(--fg-subtle); --color-inverse: var(--inverse); --color-inverse-fg: var(--inverse-fg); --color-inverse-muted: var(--inverse-muted); --color-inverse-hover: var(--inverse-hover); --color-inverse-border: var(--inverse-border); --color-success-solid: var(--success-solid); --color-success-soft: var(--success-soft); --color-warning-solid: var(--warning-solid); --color-warning-fg: var(--warning-fg); --color-danger-solid: var(--danger-solid); --color-danger-fg: var(--danger-fg); --color-danger-soft: var(--danger-soft); --color-danger-fill: var(--danger-fill); --color-danger-fill-hover: var(--danger-fill-hover); --color-danger-fill-fg: var(--danger-fill-fg); --color-well-light: var(--well-light); --color-well-dark: var(--well-dark); --color-well-light-fg: var(--well-light-fg); --color-well-dark-fg: var(--well-dark-fg); --color-qr-bg: var(--qr-bg); --color-sidebar: var(--sidebar); --color-primary-hover: var(--primary-hover); --color-primary-control: var(--primary-control); --color-primary-control-foreground: var(--primary-control-foreground); } @layer base { * { @apply border-border outline-ring; } /* Links and anything else without its own focus style get the standard ring, which component utilities override */ :focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; } html { font-family: var(--font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; } /* Names are interpolated into sentences, so a long unbroken one wraps instead of pushing the page sideways */ body { @apply bg-canvas text-body text-fg wrap-break-word; } button { @apply cursor-pointer; } /* Text selection stays neutral: the accent marks state, never decoration */ ::selection { background: var(--fill-selected); color: var(--fg); } /* Lucide icons keep a constant stroke regardless of their rendered size */ svg.lucide { stroke-width: 1.5px; } svg.lucide * { vector-effect: non-scaling-stroke; } } /* Compositor-only motion; Tailwind 4 writes scale and translate as their own properties, so they are listed next to transform */ @utility transition-motion { transition-property: opacity, transform, translate, scale; transition-duration: var(--dur-fast); transition-timing-function: var(--ease-out); } .animate-fade-in { animation: fadeIn 0.3s ease-out forwards; opacity: 0; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .settings-content { view-transition-name: settings-content; } ::view-transition-old(root), ::view-transition-new(root) { animation: none; } ::view-transition-group(settings-content) { animation: none; } ::view-transition-old(settings-content) { animation: 120ms ease-out both vt-fade-out; } ::view-transition-new(settings-content) { animation: 180ms ease-out both vt-fade-in; } @keyframes vt-fade-out { to { opacity: 0; } } @keyframes vt-fade-in { from { opacity: 0; } } @keyframes bg-zoom { 0% { transform: scale(1.3); } 100% { transform: scale(1); } } .animate-bg-zoom { transform-origin: center; will-change: transform; animation: bg-zoom 0.7s cubic-bezier(0.25, 0.1, 0.25, 1) forwards; } @keyframes delayed-fade { 0%, 40% { opacity: 0; } 100% { opacity: 1; } } .animate-delayed-fade { animation: delayed-fade 0.5s ease-out forwards; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-10px); } 50% { transform: translateX(10px); } 75% { transform: translateX(-10px); } } .animate-shake { animation: shake 0.5s ease-in-out; } /* The bar shares its surface token with the cards it floats over, so it needs an elevation of its own */ .shadow-raised { box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.5), 0 1px 2px rgb(0 0 0 / 0.08), 0 12px 32px -10px rgb(0 0 0 / 0.25); } .dark .shadow-raised { box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.07), 0 1px 2px rgb(0 0 0 / 0.6), 0 16px 40px -12px rgb(0 0 0 / 0.9); } /* Marks a moment: the bar arriving, a save settling, a blocked navigation */ @keyframes bloom { 0% { opacity: 0; } 30% { opacity: 1; } 100% { opacity: 0; } } .animate-bloom { animation: bloom 1.5s ease-out forwards; } /* Dark mode has glow headroom: a luminous colour over a near-black pill reads as light spilling out of it */ /* Light mode has none, so the same gradient washes out to almost nothing there */ /* The light values keep the same origin below the pill, so the bloom rises the same way in both, but spread wider and carry more colour to register against white */ .bloom-pending { background: radial-gradient(150% 260% at 50% 140%, rgb(217 119 6 / 0.26), transparent 72%); } /* Waits out the bar's 380ms motion so it blooms after the pill settles */ /* `both` keeps it hidden during that wait */ .bloom-success { background: radial-gradient(150% 260% at 50% 140%, rgb(22 163 74 / 0.3), transparent 72%); animation-delay: 380ms; animation-fill-mode: both; } .bloom-error { background: radial-gradient( 150% 260% at 50% 140%, color-mix(in oklab, var(--destructive) 28%, transparent), transparent 72% ); } .dark .bloom-pending { background: radial-gradient(130% 150% at 50% 130%, rgb(251 191 36 / 0.24), transparent 70%); } .dark .bloom-success { background: radial-gradient(130% 150% at 50% 130%, rgb(34 197 94 / 0.24), transparent 70%); } .dark .bloom-error { background: radial-gradient( 130% 150% at 50% 130%, color-mix(in oklab, var(--destructive) 26%, transparent), transparent 70% ); } @media (prefers-reduced-motion: reduce) { .animate-bloom { animation: none; } }