Files
Codewalkers/apps/web/src/index.css
Lukas May d03b204096 feat: Add theme-aware custom scrollbars
Thin 6px scrollbars using design tokens (--border, --muted-foreground)
so they blend properly in both light and dark mode. Uses standard
scrollbar-width/scrollbar-color plus WebKit pseudo-elements for
cross-browser coverage.
2026-03-04 12:44:54 +01:00

530 lines
14 KiB
CSS

@font-face {
font-family: 'Geist Sans';
src: url('/fonts/Geist-Variable.woff2') format('woff2');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('/fonts/GeistMono-Variable.woff2') format('woff2');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Playfair Display';
src: url('/fonts/PlayfairDisplay-Variable.woff2') format('woff2');
font-weight: 400 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Playfair Display';
src: url('/fonts/PlayfairDisplay-VariableItalic.woff2') format('woff2');
font-weight: 400 900;
font-style: italic;
font-display: swap;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
/* Core palette — Indigo brand */
--background: 0 0% 99%;
--foreground: 240 6% 10%;
--card: 0 0% 100%;
--card-foreground: 240 6% 10%;
--popover: 0 0% 100%;
--popover-foreground: 240 6% 10%;
--primary: 239 84% 67%;
--primary-foreground: 0 0% 100%;
--secondary: 240 5% 96%;
--secondary-foreground: 240 4% 16%;
--muted: 240 5% 93%;
--muted-foreground: 240 4% 46%;
--accent: 226 100% 97%;
--accent-foreground: 239 84% 67%;
--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 100%;
--border: 240 6% 90%;
--input: 240 6% 90%;
--ring: 239 84% 67%;
--radius: 0.375rem;
/* Extended indigo scale */
--indigo-50: 226 100% 97%;
--indigo-100: 228 96% 93%;
--indigo-200: 232 92% 86%;
--indigo-300: 235 88% 78%;
--indigo-400: 237 86% 72%;
--indigo-500: 239 84% 67%;
--indigo-600: 243 75% 59%;
--indigo-700: 245 58% 51%;
--indigo-800: 244 47% 42%;
--indigo-900: 242 47% 34%;
/* Status tokens — active */
--status-active-bg: 210 100% 95%;
--status-active-fg: 210 100% 40%;
--status-active-border: 210 100% 80%;
--status-active-dot: 210 100% 50%;
/* Status tokens — success */
--status-success-bg: 142 72% 94%;
--status-success-fg: 142 72% 29%;
--status-success-border: 142 72% 80%;
--status-success-dot: 142 72% 45%;
/* Status tokens — warning */
--status-warning-bg: 38 92% 95%;
--status-warning-fg: 38 92% 30%;
--status-warning-border: 38 92% 80%;
--status-warning-dot: 38 92% 50%;
/* Status tokens — error */
--status-error-bg: 0 84% 95%;
--status-error-fg: 0 84% 40%;
--status-error-border: 0 84% 80%;
--status-error-dot: 0 84% 50%;
/* Status tokens — neutral */
--status-neutral-bg: 240 5% 96%;
--status-neutral-fg: 240 4% 46%;
--status-neutral-border: 240 6% 90%;
--status-neutral-dot: 240 4% 46%;
/* Status tokens — urgent */
--status-urgent-bg: 270 91% 95%;
--status-urgent-fg: 270 91% 40%;
--status-urgent-border: 270 91% 80%;
--status-urgent-dot: 270 91% 55%;
/* Terminal tokens (always-dark aesthetic) */
--terminal-bg: 240 6% 7%;
--terminal-fg: 120 100% 80%;
--terminal-muted: 240 5% 55%;
--terminal-border: 240 4% 16%;
--terminal-selection: 239 84% 67%;
--terminal-system: 240 5% 55%;
--terminal-tool: 217 91% 60%;
--terminal-result: 142 72% 45%;
--terminal-error: 0 84% 60%;
--terminal-cursor: 120 100% 65%;
--terminal-selection-bg: 239 84% 67% / 0.25;
--terminal-link: 217 91% 70%;
--terminal-warning: 38 92% 60%;
--terminal-line-number: 240 5% 35%;
--terminal-ansi-black: 240 6% 7%;
--terminal-ansi-red: 0 84% 60%;
--terminal-ansi-green: 142 72% 45%;
--terminal-ansi-yellow: 38 92% 60%;
--terminal-ansi-blue: 217 91% 60%;
--terminal-ansi-magenta: 270 91% 65%;
--terminal-ansi-cyan: 195 80% 55%;
--terminal-ansi-white: 240 5% 85%;
/* Diff tokens */
--diff-add-bg: 142 72% 94%;
--diff-add-fg: 142 72% 29%;
--diff-add-border: 142 72% 80%;
--diff-remove-bg: 0 84% 95%;
--diff-remove-fg: 0 84% 40%;
--diff-remove-border: 0 84% 80%;
--diff-hunk-bg: 226 100% 97%;
/* Shadow tokens */
--shadow-xs: 0 1px 2px hsl(0 0% 0% / 0.04);
--shadow-sm: 0 1px 3px hsl(0 0% 0% / 0.06), 0 1px 2px hsl(0 0% 0% / 0.04);
--shadow-md: 0 4px 6px hsl(0 0% 0% / 0.06), 0 2px 4px hsl(0 0% 0% / 0.04);
--shadow-lg: 0 10px 15px hsl(0 0% 0% / 0.06), 0 4px 6px hsl(0 0% 0% / 0.04);
--shadow-xl: 0 20px 25px hsl(0 0% 0% / 0.08), 0 8px 10px hsl(0 0% 0% / 0.04);
/* Transition & animation tokens */
--duration-instant: 50ms;
--duration-fast: 100ms;
--duration-normal: 200ms;
--duration-slow: 350ms;
--duration-glacial: 500ms;
--ease-default: cubic-bezier(0.2, 0, 0, 1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
/* Spacing tokens */
--space-section: 2rem;
--space-section-lg: 3rem;
/* Background atmosphere */
--bg-gradient: radial-gradient(ellipse 80% 60% at 50% -10%, hsl(239 84% 67% / 0.04), transparent 70%);
/* Z-index scale */
--z-base: 0;
--z-raised: 1;
--z-sticky: 10;
--z-sidebar: 20;
--z-dropdown: 30;
--z-overlay: 40;
--z-modal: 50;
--z-toast: 60;
--z-command: 70;
--z-tooltip: 80;
}
.dark {
--background: 240 6% 7%;
--foreground: 240 5% 96%;
--card: 240 5% 11%;
--card-foreground: 240 5% 96%;
--popover: 240 5% 16%;
--popover-foreground: 240 5% 96%;
--primary: 239 84% 67%;
--primary-foreground: 0 0% 100%;
--secondary: 240 4% 16%;
--secondary-foreground: 240 5% 96%;
--muted: 240 4% 16%;
--muted-foreground: 240 5% 65%;
--accent: 239 40% 16%;
--accent-foreground: 239 84% 75%;
--destructive: 0 63% 31%;
--destructive-foreground: 0 0% 100%;
--border: 240 4% 16%;
--input: 240 4% 16%;
--ring: 239 84% 67%;
/* Surface level 3 for command palette */
--surface-3: 240 5% 21%;
/* Status tokens — dark mode */
--status-active-bg: 210 100% 12%;
--status-active-fg: 210 100% 70%;
--status-active-border: 210 100% 25%;
--status-active-dot: 210 100% 50%;
--status-success-bg: 142 72% 10%;
--status-success-fg: 142 72% 65%;
--status-success-border: 142 72% 22%;
--status-success-dot: 142 72% 45%;
--status-warning-bg: 38 92% 10%;
--status-warning-fg: 38 92% 65%;
--status-warning-border: 38 92% 22%;
--status-warning-dot: 38 92% 50%;
--status-error-bg: 0 84% 12%;
--status-error-fg: 0 84% 65%;
--status-error-border: 0 84% 25%;
--status-error-dot: 0 84% 50%;
--status-neutral-bg: 240 4% 16%;
--status-neutral-fg: 240 5% 65%;
--status-neutral-border: 240 4% 22%;
--status-neutral-dot: 240 5% 50%;
--status-urgent-bg: 270 91% 12%;
--status-urgent-fg: 270 91% 70%;
--status-urgent-border: 270 91% 25%;
--status-urgent-dot: 270 91% 55%;
/* Terminal tokens — dark mode */
--terminal-bg: 240 5% 11%;
--terminal-fg: 120 100% 80%;
--terminal-muted: 240 5% 55%;
--terminal-border: 240 4% 16%;
--terminal-selection: 239 84% 67%;
--terminal-system: 240 5% 55%;
--terminal-tool: 217 91% 60%;
--terminal-result: 142 72% 45%;
--terminal-error: 0 84% 60%;
--terminal-cursor: 120 100% 65%;
--terminal-selection-bg: 239 84% 67% / 0.25;
--terminal-link: 217 91% 70%;
--terminal-warning: 38 92% 60%;
--terminal-line-number: 240 5% 35%;
--terminal-ansi-black: 240 6% 7%;
--terminal-ansi-red: 0 84% 60%;
--terminal-ansi-green: 142 72% 45%;
--terminal-ansi-yellow: 38 92% 60%;
--terminal-ansi-blue: 217 91% 60%;
--terminal-ansi-magenta: 270 91% 65%;
--terminal-ansi-cyan: 195 80% 55%;
--terminal-ansi-white: 240 5% 85%;
/* Diff tokens — dark mode */
--diff-add-bg: 142 72% 10%;
--diff-add-fg: 142 72% 65%;
--diff-add-border: 142 72% 22%;
--diff-remove-bg: 0 84% 12%;
--diff-remove-fg: 0 84% 65%;
--diff-remove-border: 0 84% 25%;
--diff-hunk-bg: 239 40% 16%;
/* Background atmosphere — dark mode */
--bg-gradient: radial-gradient(ellipse 80% 60% at 50% -10%, hsl(239 84% 67% / 0.06), transparent 70%);
/* Shadow tokens — dark mode (inset highlights + ambient glow) */
--shadow-xs: none;
--shadow-sm: inset 0 1px 0 hsl(0 0% 100% / 0.04);
--shadow-md: inset 0 1px 0 hsl(0 0% 100% / 0.05), 0 2px 8px hsl(0 0% 0% / 0.3);
--shadow-lg: inset 0 1px 0 hsl(0 0% 100% / 0.06), 0 4px 16px hsl(0 0% 0% / 0.4);
--shadow-xl: inset 0 1px 0 hsl(0 0% 100% / 0.06), 0 8px 32px hsl(0 0% 0% / 0.5);
}
}
/* Keyframes */
@keyframes status-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes graph-layer-enter {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
/* Global focus-visible styles */
*:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
border-radius: var(--radius);
}
*:focus:not(:focus-visible) {
outline: none;
}
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
outline: none;
box-shadow: 0 0 0 2px hsl(var(--background)), 0 0 0 4px hsl(var(--ring));
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
/* Custom scrollbars */
* {
scrollbar-width: thin;
scrollbar-color: hsl(var(--border)) transparent;
}
*:hover {
scrollbar-color: hsl(var(--muted-foreground) / 0.35) transparent;
}
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: hsl(var(--border));
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background-color: hsl(var(--muted-foreground) / 0.5);
}
::-webkit-scrollbar-corner {
background: transparent;
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
margin: 0;
min-width: 320px;
height: 100vh;
overflow: hidden;
background-image: var(--bg-gradient);
background-attachment: fixed;
}
}
/* Noise texture overlay */
body::before {
content: '';
position: fixed;
inset: 0;
z-index: -1;
opacity: 0.015;
pointer-events: none;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 256px 256px;
}
.dark body::before {
opacity: 0.03;
}
/* Notion-style page link blocks inside the editor */
.page-link-block {
display: flex;
align-items: center;
gap: 0.5rem;
width: 100%;
padding: 0.2rem 0.25rem;
border-radius: 0.25rem;
cursor: pointer;
color: hsl(var(--foreground));
font-size: 0.9375rem;
line-height: 1.4;
transition: background-color 0.15s;
}
.page-link-block:hover {
background-color: hsl(var(--muted));
}
.page-link-block svg {
color: hsl(var(--muted-foreground));
flex-shrink: 0;
}
/* Block selection highlight */
.ProseMirror .block-selected {
background-color: hsl(var(--primary) / 0.08);
border-radius: 0.25rem;
box-shadow: 0.375rem 0 0 hsl(var(--primary) / 0.08), -0.375rem 0 0 hsl(var(--primary) / 0.08);
}
.dark .ProseMirror .block-selected {
background-color: hsl(var(--primary) / 0.12);
box-shadow: 0.375rem 0 0 hsl(var(--primary) / 0.12), -0.375rem 0 0 hsl(var(--primary) / 0.12);
}
/* Hide cursor and text selection during block selection mode */
.ProseMirror.has-block-selection {
caret-color: transparent;
}
.ProseMirror.has-block-selection *::selection {
background: transparent;
}
/* Notion-style placeholder on empty blocks */
.ProseMirror .is-empty::before {
color: hsl(var(--muted-foreground));
content: attr(data-placeholder);
float: left;
height: 0;
pointer-events: none;
}
/* Table wrapper overflow */
.ProseMirror .tableWrapper { overflow-x: auto; margin: 1em 0; }
/* Cell positioning for resize handles */
.ProseMirror table td, .ProseMirror table th { position: relative; min-width: 50px; vertical-align: top; }
/* Column resize handle */
.ProseMirror .column-resize-handle { position: absolute; right: -2px; top: 0; bottom: -2px; width: 4px; background-color: hsl(var(--primary) / 0.4); pointer-events: none; z-index: 20; }
/* Resize cursor */
.ProseMirror.resize-cursor { cursor: col-resize; }
/* Selected cell highlight */
.ProseMirror td.selectedCell, .ProseMirror th.selectedCell { background-color: hsl(var(--primary) / 0.08); }
.dark .ProseMirror td.selectedCell, .dark .ProseMirror th.selectedCell { background-color: hsl(var(--primary) / 0.15); }
/* Inline code styling — remove prose backtick pseudo-elements */
.ProseMirror :not(pre) > code {
background-color: hsl(var(--muted));
padding: 0.15em 0.35em;
border-radius: 0.25rem;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.875em;
}
.ProseMirror :not(pre) > code::before,
.ProseMirror :not(pre) > code::after {
content: none;
}
.dark .ProseMirror :not(pre) > code {
background-color: hsl(var(--muted));
}
/* Code block styling */
.ProseMirror pre {
background-color: hsl(var(--muted));
padding: 1rem;
border-radius: 0.375rem;
overflow-x: auto;
}
.ProseMirror pre code {
background: none;
padding: 0;
border-radius: 0;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.875em;
color: inherit;
}
.ProseMirror pre code::before,
.ProseMirror pre code::after {
content: none;
}
@layer utilities {
.card-hover-lift {
transition: transform var(--duration-normal) var(--ease-out),
box-shadow var(--duration-normal) var(--ease-out);
}
.card-hover-lift:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.glow-active {
box-shadow: 0 0 8px hsl(var(--status-active-dot) / 0.4);
}
.glow-success {
box-shadow: 0 0 8px hsl(var(--status-success-dot) / 0.4);
}
.glow-error {
box-shadow: 0 0 8px hsl(var(--status-error-dot) / 0.4);
}
.glow-warning {
box-shadow: 0 0 8px hsl(var(--status-warning-dot) / 0.4);
}
}