@tailwind base; @tailwind components; @tailwind utilities; /* --------------------------------------------------------------------- * Design tokens (shadcn-style, oklch). PRODUCT-SPEC §27: design tokens, * no hard-coded colors — components reference these variables only. * * CONVENTION: the core theme tokens (--background … --ring) store RAW * oklch CHANNEL TRIPLES ("L C H"), not full colors, because * tailwind.config.ts references them as `oklch(var(--token) / * )`. Storing full `oklch(…)` colors there produced the * invalid nested `oklch(oklch(…))` which the browser resolves to * transparent — silently blanking every themed bg/text/border utility and * making dark mode invisible. Code that needs the finished color must * wrap explicitly: `oklch(var(--primary))` or `oklch(var(--primary) / a)`. * (The --factory-* tokens below are full colors by design: they are * consumed directly via `var()` in inline styles, never through Tailwind.) * ------------------------------------------------------------------- */ :root { /* ------------------------------------------------------------------ * F1Soft-themed light palette (recorded 2025 — "colorful theme" request, * reference f1soft.com). Brand language: vivid fintech BLUE (#2299dd) as * the signature, deep NAVY ink (#0d1720) for text, a CRIMSON red * (#a31e21) for destructive, GOLD (#ebb76a) / CORAL (#ff6b4a) accents, on * a pale blue-white canvas (#f4f9fd) instead of flat white. * * `--primary` is a slightly deepened brand blue (#1976c2, 0.554 0.143 * 249.3): the pure #2299dd only reaches 3.15:1 with white text (fails AA * for the app's small button labels); this keeps the same vivid blue hue * family at 4.76:1. The bright #2299dd lives on `--ring` (focus/selection) * and in the brand gradient below, where it never carries text. * ------------------------------------------------------------------ */ --background: 0.979 0.008 241.7; /* #f4f9fd pale blue-white */ --foreground: 0.2 0.023 246.4; /* #0d1720 navy ink */ --card: 1 0 0; --card-foreground: 0.2 0.023 246.4; --popover: 1 0 0; --popover-foreground: 0.2 0.023 246.4; --primary: 0.554 0.143 249.3; /* #1976c2 brand blue (AA on white text) */ --primary-foreground: 1 0 0; --secondary: 0.954 0.017 250.8; /* #e8f1fb pale blue */ --secondary-foreground: 0.2 0.023 246.4; --muted: 0.958 0.013 248; /* pale blue-gray canvas tint */ --muted-foreground: 0.513 0.03 244.8; /* #596977 slate */ --accent: 0.919 0.021 248.1; /* #dae6f2 hover/active tint */ --accent-foreground: 0.2 0.023 246.4; --destructive: 0.466 0.168 25.9; /* #a31e21 f1soft crimson */ --destructive-foreground: 1 0 0; --border: 0.905 0.022 248; /* #d3e2f0 */ --input: 0.905 0.022 248; --ring: 0.653 0.141 240.6; /* #2299dd brand blue (focus/selection) */ --radius: 0.5rem; /* Brand tokens (FULL colors — consumed via var() in gradients/inline styles, never through the Tailwind oklch wrapper). */ --factory-brand-blue: #2299dd; --factory-brand-blue-deep: #1976c2; --factory-brand-navy: #0d1720; --factory-brand-navy-mid: #2e448d; --factory-brand-red: #a31e21; --factory-brand-gold: #ebb76a; --factory-brand-coral: #ff6b4a; /* Signature mark / hero gradient (f1soft blue → deep navy-blue). */ --factory-brand-gradient: linear-gradient(135deg, #2299dd 0%, #2e448d 100%); /* Soft tinted backdrop for hero/auth surfaces. */ --factory-brand-gradient-soft: linear-gradient( 135deg, #e8f1fb 0%, #f4f9fd 55%, #f7dfdf 100% ); --factory-code-bg: oklch(0.21 0.018 265.6); --factory-code-fg: oklch(0.93 0.012 264); /* Code block font size (display + edit overlay must share it). */ --factory-code-font-size: 13px; /* Syntax token palette (Prism token classes, .factory-codeblock .token). Tuned for the dark code surface above — both themes use a dark code canvas, so one palette serves light and dark. */ --factory-code-comment: oklch(0.64 0.03 250); --factory-code-keyword: oklch(0.74 0.15 250); --factory-code-function: oklch(0.76 0.15 295); --factory-code-string: oklch(0.8 0.15 152); --factory-code-number: oklch(0.82 0.13 80); --factory-code-constant: oklch(0.74 0.18 35); --factory-code-operator: oklch(0.8 0.05 250); --factory-code-variable: oklch(0.78 0.13 215); --factory-code-punctuation: oklch(0.78 0.02 250); --factory-code-property: oklch(0.78 0.11 210); --factory-code-class-name: oklch(0.83 0.11 90); --factory-code-tag: oklch(0.74 0.15 250); /* Factory block colors (light theme) — see @factory/shared BLOCK_COLORS. */ --factory-color-gray: oklch(0.553 0.016 285.938); --factory-color-brown: oklch(0.588 0.128 61.038); --factory-color-orange: oklch(0.705 0.213 48.029); --factory-color-yellow: oklch(0.828 0.169 87.152); --factory-color-green: oklch(0.723 0.192 149.579); --factory-color-blue: oklch(0.623 0.188 259.815); --factory-color-purple: oklch(0.627 0.192 294.588); --factory-color-pink: oklch(0.718 0.183 3.855); --factory-color-red: oklch(0.592 0.249 25.768); --factory-color-gray_bg: oklch(0.963 0.003 286.358); --factory-color-brown_bg: oklch(0.942 0.028 66.205); --factory-color-orange_bg: oklch(0.965 0.019 52.759); --factory-color-yellow_bg: oklch(0.967 0.036 101.928); --factory-color-green_bg: oklch(0.958 0.032 156.209); --factory-color-blue_bg: oklch(0.943 0.028 262.992); --factory-color-purple_bg: oklch(0.949 0.031 294.114); --factory-color-pink_bg: oklch(0.955 0.025 2.134); --factory-color-red_bg: oklch(0.954 0.028 25.631); } .dark { /* F1Soft-themed DARK palette: the site's own deep-navy surfaces (#0d1720 / #14202b) instead of flat near-black gray, with the bright brand blue #2299dd as the primary. Navy ink reads 5.75:1 on the blue (AA), so `--primary-foreground` is the navy, not white. */ --background: 0.2 0.023 246.4; /* #0d1720 */ --foreground: 0.964 0.01 247.9; /* #eef4fa */ --card: 0.238 0.027 246.9; /* #14202b */ --card-foreground: 0.964 0.01 247.9; --popover: 0.238 0.027 246.9; --popover-foreground: 0.964 0.01 247.9; --primary: 0.653 0.141 240.6; /* #2299dd brand blue */ --primary-foreground: 0.2 0.023 246.4; /* navy ink */ --secondary: 0.263 0.033 249.2; /* #182634 */ --secondary-foreground: 0.964 0.01 247.9; --muted: 0.247 0.029 249; /* #16222e */ --muted-foreground: 0.719 0.033 243.9; /* #93a7b8 */ --accent: 0.312 0.044 245.9; /* #1d3346 hover/active */ --accent-foreground: 0.964 0.01 247.9; --destructive: 0.674 0.214 23.3; /* #ff4d53 (brighter in dark) */ --destructive-foreground: 0.985 0.002 247.839; /* NOTE: the border tokens are SOLID navy hairlines (#24374a) because Tailwind's `oklch(var(--x) / )` wrapper can't carry a second alpha inside the var — expressed as the equivalent solid value for the navy background. `/N` modifier utilities on border/input still work for stronger lines. */ --border: 0.329 0.042 249.2; /* #24374a */ --input: 0.329 0.042 249.2; --ring: 0.653 0.141 240.6; /* #2299dd brand blue (focus/selection) */ --factory-code-bg: oklch(0.183 0.021 249); /* #0b131b */ --factory-code-fg: oklch(0.92 0.012 264); } @layer base { * { @apply border-border; } html { @apply scroll-smooth; } body { @apply bg-background text-foreground antialiased; font-feature-settings: "cv02", "cv03", "cv04", "cv11"; } ::selection { @apply bg-ring/20; } } /* Thin, theme-aware scrollbars (WebKit + Firefox). */ * { scrollbar-width: thin; scrollbar-color: oklch(var(--muted-foreground) / 0.35) transparent; } *::-webkit-scrollbar { width: 8px; height: 8px; } *::-webkit-scrollbar-thumb { background: oklch(var(--muted-foreground) / 0.35); border-radius: 4px; } *::-webkit-scrollbar-thumb:hover { background: oklch(var(--muted-foreground) / 0.55); } *::-webkit-scrollbar-track { background: transparent; } /* --------------------------------------------------------------------- * Editor / prose tweaks. * ------------------------------------------------------------------- */ .editor-page { min-height: calc(100vh - 3.5rem); padding-top: 2.5rem; } .block-row { /* TASK-0100 S5: `group` is a marker utility and CANNOT be @apply-ed (Tailwind 3.4: "@apply should not be used with the 'group' utility"), which made next dev 500 every page render. The marker now lives in the JSX at the .block-row usage sites (block-renderer.tsx, page-view.tsx); this class keeps the layout + state styles. */ @apply relative -mx-8 px-8 transition-colors duration-75; } .block-row:hover { @apply bg-accent/40; } .block-row.is-selected { @apply bg-accent ring-1 ring-ring/40 rounded-sm; } /* TASK-0123: the multi-selection (⌘/Ctrl+click or Shift+click range) gets a stronger, primary-colored ring so it reads as a distinct "batch" from the single highlight (the writing toolbar's target). */ .block-row.is-multi-selected { @apply bg-primary/10 ring-1 ring-primary/50 rounded-sm; } /* Deep-link focus flash. */ .block-focus-flash { animation: block-focus-flash 1.6s ease-out; } @keyframes block-focus-flash { 0% { background-color: oklch(var(--ring) / 0.25); } 100% { background-color: transparent; } } .editor-content { @apply outline-none text-foreground; min-height: 1.5em; /* Body copy was 16px (Tailwind base) — a touch large for a document editor. 14.5px reads more like Notion's dense body text. (Request: "text editor font is a bit bigger, make it small".) */ font-size: 14.5px; /* Long unbroken strings (pasted URLs, identifiers, error dumps) must wrap inside the block instead of stretching it past the column width. Only `overflow-wrap` — normal prose still wraps at word boundaries. */ overflow-wrap: break-word; } .editor-content p.is-editor-empty:first-child::before { content: attr(data-placeholder); @apply pointer-events-none float-left h-0 text-muted-foreground; } .editor-content ul { @apply list-disc pl-6; } .editor-content ol { @apply list-decimal pl-6; } .editor-content code { @apply rounded bg-muted px-1.5 py-0.5 font-mono text-[0.875em]; } .editor-content pre { @apply my-2 overflow-x-auto rounded-md p-3 font-mono text-[13px] leading-relaxed; background: var(--factory-code-bg); color: var(--factory-code-fg); } .editor-content pre code { @apply bg-transparent p-0 text-inherit; } /* --------------------------------------------------------------------- Syntax highlighting for code blocks (.factory-codeblock — block-renderer CodeBlock, display + edit-overlay). Prism emits ``; each token family maps to a --factory-code-* token defined in :root, so both themes get colors from the palette instead of hard-coded values. --------------------------------------------------------------------- */ .factory-codeblock code { color: var(--factory-code-fg); } .factory-codeblock .token.comment, .factory-codeblock .token.prolog, .factory-codeblock .token.doctype, .factory-codeblock .token.cdata { color: var(--factory-code-comment); font-style: italic; } .factory-codeblock .token.punctuation { color: var(--factory-code-punctuation); } .factory-codeblock .token.namespace { opacity: 0.7; } .factory-codeblock .token.property, .factory-codeblock .token.tag, .factory-codeblock .token.constant, .factory-codeblock .token.symbol, .factory-codeblock .token.deleted { color: var(--factory-code-constant); } .factory-codeblock .token.boolean, .factory-codeblock .token.number { color: var(--factory-code-number); } .factory-codeblock .token.selector, .factory-codeblock .token.attr-name, .factory-codeblock .token.string, .factory-codeblock .token.char, .factory-codeblock .token.builtin, .factory-codeblock .token.inserted { color: var(--factory-code-string); } .factory-codeblock .token.operator, .factory-codeblock .token.entity, .factory-codeblock .token.url { color: var(--factory-code-operator); } .factory-codeblock .token.atrule, .factory-codeblock .token.attr-value, .factory-codeblock .token.keyword { color: var(--factory-code-keyword); } .factory-codeblock .token.function, .factory-codeblock .token.class-name { color: var(--factory-code-function); } .factory-codeblock .token.regex, .factory-codeblock .token.important, .factory-codeblock .token.variable { color: var(--factory-code-variable); } .editor-content a { @apply cursor-pointer text-blue-600 underline decoration-blue-600/50 underline-offset-2 hover:decoration-blue-600 dark:text-blue-400; } .editor-content table { @apply w-full border-collapse; } .editor-content img { @apply max-w-full rounded-md; } /* Task items (Tiptap task-list/task-item). */ .editor-content ul[data-type="taskList"] { @apply list-none pl-1; } .editor-content ul[data-type="taskList"] li { @apply flex gap-2; } .editor-content ul[data-type="taskList"] li > label { @apply mt-1.5 flex shrink-0; } .editor-content ul[data-type="taskList"] li > label input[type="checkbox"] { @apply size-4 cursor-pointer rounded border-border accent-[oklch(var(--ring))]; } .editor-content ul[data-type="taskList"] li[data-checked="true"] > div { @apply text-muted-foreground line-through; } /* Focus visibility (a11y, PRODUCT-SPEC §27). */ :focus-visible { @apply outline-none ring-2 ring-ring/60 ring-offset-1 ring-offset-background rounded-sm; } /* Respect reduced motion. */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } /* Whiteboard toolbar (T-168). */ .wb-tool { @apply rounded px-2 py-0.5 text-xs text-muted-foreground hover:bg-muted; } .wb-tool.active { @apply bg-primary/10 text-foreground; }