@import "tw-animate-css"; @import "shadcn/tailwind.css"; @tailwind base; @tailwind components; @tailwind utilities; /* * GSD theme — mirrors the Omics Portal design system (Manrope + Fraunces, warm * off-white surfaces, #cb333b red). Tokens are RAW OKLCH triplets (L C H) so the * Tailwind v3 config can wrap them as `oklch(var(--token) / )` and * opacity utilities (bg-primary/80, …) keep working. Dark tokens follow either a * `.dark` class or the portal's `[data-bs-theme="dark"]`, ready for embedding. */ @layer base { :root { --font-sans: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Arial, sans-serif; --font-heading: "Fraunces", "Source Serif Pro", Georgia, "Times New Roman", serif; --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace; /* Layered elevation, tinted with the foreground hue so depth reads warm on warm surfaces. Borders mark structure; shadows mark elevation. */ --shadow-tint: 0.2678 0.0097 355.6; --shadow-xs: 0 1px 2px oklch(var(--shadow-tint) / 0.05); --shadow-sm: 0 1px 2px oklch(var(--shadow-tint) / 0.05), 0 2px 6px -1px oklch(var(--shadow-tint) / 0.05); --shadow-md: 0 2px 4px -2px oklch(var(--shadow-tint) / 0.06), 0 12px 32px -8px oklch(var(--shadow-tint) / 0.1); --background: 0.9918 0.0011 17.2; /* surface */ --foreground: 0.2678 0.0097 355.6; /* text */ --card: 0.9985 0.0006 17.2; --card-foreground: 0.2678 0.0097 355.6; --popover: 0.9985 0.0006 17.2; --popover-foreground: 0.2678 0.0097 355.6; --primary: 0.5587 0.1881 23.2; /* gsd red */ --primary-foreground: 0.9918 0.0011 17.2; --primary-hover: 0.5095 0.1812 24.1; --secondary: 0.9709 0.0011 17.2; /* surface-alt */ --secondary-foreground: 0.2678 0.0097 355.6; --muted: 0.9709 0.0011 17.2; --muted-foreground: 0.5133 0.0088 345.6; --accent: 0.9408 0.0011 17.2; /* sunken */ --accent-foreground: 0.2678 0.0097 355.6; --destructive: 0.5587 0.1881 23.2; --destructive-foreground: 0.9918 0.0011 17.2; --border: 0.9093 0.0035 354.7; --input: 0.9093 0.0035 354.7; --ring: 0.5587 0.1881 23.2; --success: 0.7577 0.1581 165.0; --warning: 0.8523 0.1386 78.9; --info: 0.7035 0.1128 221.3; --radius: 0.5rem; --sidebar: 0.9709 0.0011 17.2; --sidebar-foreground: 0.2678 0.0097 355.6; --sidebar-primary: 0.5587 0.1881 23.2; --sidebar-primary-foreground: 0.9918 0.0011 17.2; --sidebar-accent: 0.9408 0.0011 17.2; --sidebar-accent-foreground: 0.2678 0.0097 355.6; --sidebar-border: 0.9093 0.0035 354.7; --sidebar-ring: 0.5587 0.1881 23.2; } .dark, [data-bs-theme="dark"] { --shadow-tint: 0 0 0; --background: 0.2178 0 90; --foreground: 0.9310 0 90; --card: 0.2350 0 90; --card-foreground: 0.9310 0 90; --popover: 0.2350 0 90; --popover-foreground: 0.9310 0 90; --primary: 0.6023 0.1848 20.3; --primary-foreground: 0.9310 0 90; --primary-hover: 0.6897 0.1779 16.9; --secondary: 0.2972 0 90; --secondary-foreground: 0.9310 0 90; --muted: 0.2972 0 90; --muted-foreground: 0.7826 0 90; --accent: 0.3485 0 90; --accent-foreground: 0.9310 0 90; --destructive: 0.6023 0.1848 20.3; --destructive-foreground: 0.9310 0 90; --border: 0.3715 0 90; --input: 0.3715 0 90; --ring: 0.6897 0.1779 16.9; --sidebar: 0.2350 0 90; --sidebar-foreground: 0.9310 0 90; --sidebar-primary: 0.6023 0.1848 20.3; --sidebar-primary-foreground: 0.9310 0 90; --sidebar-accent: 0.3485 0 90; --sidebar-accent-foreground: 0.9310 0 90; --sidebar-border: 0.3715 0 90; --sidebar-ring: 0.6897 0.1779 16.9; } * { @apply border-border outline-ring/50; } /* A click should read as a physical state change, not only as a hover ending. Keep the response short and compositor-friendly so repeated actions stay fast. */ button:not(:disabled) { transform-origin: center; transition-property: color, background-color, border-color, box-shadow, filter, transform; transition-duration: 140ms; transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } button:not(:disabled):active { transform: scale(0.97); filter: brightness(0.94); box-shadow: none; } @media (prefers-reduced-motion: reduce) { button:not(:disabled) { transition-duration: 0.01ms; } button:not(:disabled):active { transform: none; filter: brightness(0.9); box-shadow: none; } } html { @apply font-sans; } body { @apply bg-background text-foreground antialiased; font-feature-settings: "ss01", "cv11"; } h1, h2, h3, h4 { font-family: var(--font-heading); font-optical-sizing: auto; letter-spacing: -0.015em; } code, pre, kbd, samp { font-family: var(--font-mono); font-variant-numeric: tabular-nums; } ::selection { background: oklch(var(--primary) / 0.16); } /* Thin, brand-tinted scrollbars */ * { scrollbar-width: thin; scrollbar-color: oklch(var(--border)) transparent; } *::-webkit-scrollbar { width: 10px; height: 10px; } *::-webkit-scrollbar-thumb { background: oklch(var(--border)); border-radius: 9999px; border: 2px solid transparent; background-clip: padding-box; } *::-webkit-scrollbar-thumb:hover { background: oklch(var(--muted-foreground) / 0.5); } } /* * Minimal markdown prose for assistant turns (no typography plugin installed). * Scoped so it never leaks into widgets. */ @layer components { /* Standard micro-label: panel headers, nav sections, meta rows. Set in the mono register so labels/meta read as a distinct typographic layer from the sans body prose (mono needs less tracking than the sans did). */ .thot-label { font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: oklch(var(--muted-foreground)); } .thot-prose { color: oklch(var(--foreground)); font-size: 0.9375rem; line-height: 1.65; } .thot-prose > :first-child { margin-top: 0; } .thot-prose > :last-child { margin-bottom: 0; } .thot-prose p { margin: 0.6em 0; } .thot-prose h1, .thot-prose h2, .thot-prose h3 { font-family: var(--font-heading); font-weight: 600; line-height: 1.25; margin: 1.1em 0 0.5em; letter-spacing: -0.01em; } .thot-prose h1 { font-size: 1.45rem; } .thot-prose h2 { font-size: 1.2rem; } .thot-prose h3 { font-size: 1.02rem; } .thot-prose ul, .thot-prose ol { margin: 0.6em 0; padding-left: 1.3em; } .thot-prose li { margin: 0.25em 0; } .thot-prose a { color: oklch(var(--primary)); text-decoration: underline; text-underline-offset: 2px; } .thot-prose code { font-family: var(--font-mono); font-size: 0.85em; background: oklch(var(--muted)); padding: 0.12em 0.4em; border-radius: 0.3rem; border: 1px solid oklch(var(--border) / 0.6); } .thot-prose pre { background: oklch(var(--muted)); padding: 0.9rem 1rem; border-radius: calc(var(--radius) + 2px); overflow-x: auto; border: 1px solid oklch(var(--border) / 0.7); box-shadow: var(--shadow-xs); } .thot-prose pre code { background: transparent; padding: 0; } .thot-prose blockquote { border-left: 2px solid oklch(var(--border)); padding-left: 0.9em; color: oklch(var(--muted-foreground)); margin: 0.7em 0; } .thot-prose table { border-collapse: separate; border-spacing: 0; width: 100%; margin: 0.7em 0; font-size: 0.875rem; border: 1px solid oklch(var(--border) / 0.8); border-radius: calc(var(--radius) + 2px); overflow: hidden; } .thot-prose th, .thot-prose td { padding: 0.45em 0.7em; text-align: left; } .thot-prose td { border-top: 1px solid oklch(var(--border) / 0.6); font-variant-numeric: tabular-nums; } .thot-prose th { background: oklch(var(--muted)); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: oklch(var(--muted-foreground)); } .thot-activity-prose, .thot-activity-prose p, .thot-activity-prose li, .thot-activity-prose a, .thot-activity-prose code, .thot-activity-prose th, .thot-activity-prose td { overflow-wrap: anywhere; word-break: break-word; } .thot-activity-prose table { table-layout: fixed; } .thot-activity-prose pre { overflow-x: hidden; white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; } .thot-activity-prose pre code { white-space: inherit; } } @layer components { .thot-awaiting-input { background: oklch(var(--success) / 0.14); border-color: oklch(var(--success) / 0.55); } .thot-awaiting-input:focus { box-shadow: 0 0 0 3px oklch(var(--success) / 0.18); } /* Live-activity pulse: a soft ring emanates from the red stop dot while the harness is actively working, signalling "something is happening". Ring only (no layout properties animated); calm 1.6s ease-out cadence, silenced for reduced motion. */ .thot-pulse { animation: thot-pulse-ring 1.5s ease-in-out infinite; } @media (prefers-reduced-motion: reduce) { .thot-pulse { animation: none; } } .thot-prose p + p { margin-top: 1em; } .thot-prose ul { list-style: disc; } .thot-prose ol { list-style: decimal; } .thot-prose ul ul { list-style: circle; } .thot-prose ol ol { list-style: lower-alpha; } } @keyframes thot-pulse-ring { 0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 oklch(var(--primary) / 0.4); } 50% { transform: scale(1.15); box-shadow: 0 0 0 5px oklch(var(--primary) / 0); } }