@import "tw-animate-css"; @import "shadcn/tailwind.css"; /* Omics shares the document. Keep Tailwind's reset inside our mount and portals. */ @thoth-base { @tailwind base; } @tailwind components; @tailwind utilities; body.thot-full-document { margin: 0; } /* * Product theme — shares the Omics Portal identity (Manrope, 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. * Tokens belong to the React mount and Base UI portal roots, never the host header. */ @layer base { #root, [data-base-ui-portal] { color-scheme: light; --font-sans: "Manrope Variable", "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Arial, sans-serif; --font-heading: var(--font-sans); --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace; --text-page: 1.5rem; --text-section: 1.25rem; --text-body: 1rem; --text-control: 0.875rem; --text-meta: 0.75rem; /* 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.64 0.008 354.7; --ring: 0.5587 0.1881 23.2; --success: 0.46 0.095 160; --warning: 0.48 0.09 70; --info: var(--muted-foreground); /* Current navigation shares Instrument Red's hue, with lower chroma and higher lightness so selection reads as a muted location signal. */ --nav-active: 0.9250 0.0520 23.2; --nav-active-hover: 0.8950 0.0710 23.2; --nav-active-foreground: 0.3650 0.1100 23.2; --nav-active-border: 0.6000 0.1350 23.2; --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; } :is(.dark, [data-bs-theme="dark"]) :is(#root, [data-base-ui-portal]) { color-scheme: 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.73 0.15 23.2; --primary-foreground: 0.2178 0.005 23.2; --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.73 0.15 23.2; --destructive-foreground: 0.9310 0 90; --border: 0.3715 0 90; --input: 0.62 0.008 23.2; --ring: 0.6897 0.1779 16.9; --success: 0.78 0.10 160; --warning: 0.82 0.10 75; --nav-active: 0.3350 0.0550 20.3; --nav-active-hover: 0.3750 0.0650 20.3; --nav-active-foreground: 0.8900 0.0700 20.3; --nav-active-border: 0.6800 0.1350 20.3; --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; } :where(#root, [data-base-ui-portal]), :where(#root, [data-base-ui-portal]) * { @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. */ :where(#root, [data-base-ui-portal]) 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); } :where(#root, [data-base-ui-portal]) button:not(:disabled):active { transform: scale(0.97); filter: brightness(0.94); box-shadow: none; } @media (prefers-reduced-motion: reduce) { :where(#root, [data-base-ui-portal]) button:not(:disabled) { transition-duration: 0.01ms; } :where(#root, [data-base-ui-portal]) button:not(:disabled):active { transform: none; filter: brightness(0.9); box-shadow: none; } } #root, [data-base-ui-portal] { @apply font-sans text-foreground antialiased; line-height: 1.5; -webkit-text-size-adjust: 100%; } #root { @apply bg-background text-foreground antialiased; font-feature-settings: "ss01", "cv11"; } :where(#root, [data-base-ui-portal]) :is(input, textarea)::placeholder { color: oklch(var(--muted-foreground)); opacity: 1; } :where(#root, [data-base-ui-portal]) :is(button, input, select, textarea, summary):focus-visible { outline: 2px solid oklch(var(--ring)); outline-offset: 2px; } /* The composer already exposes keyboard focus on its enclosing focus-within frame. */ #root textarea.thot-composer-input:focus-visible { outline: none; } :where(#root, [data-base-ui-portal]) :where(h1, h2, h3, h4, h5, h6) { font-family: var(--font-heading); font-optical-sizing: auto; letter-spacing: -0.015em; } :where(#root, [data-base-ui-portal]) :is(code, pre, kbd, samp) { font-family: var(--font-mono); font-variant-numeric: tabular-nums; } :where(#root, [data-base-ui-portal]) ::selection { background: oklch(var(--primary) / 0.16); } /* Thin, brand-tinted scrollbars */ :where(#root, [data-base-ui-portal]) * { scrollbar-width: thin; scrollbar-color: oklch(var(--border)) transparent; } :where(#root, [data-base-ui-portal]) *::-webkit-scrollbar { width: 10px; height: 10px; } :where(#root, [data-base-ui-portal]) *::-webkit-scrollbar-thumb { background: oklch(var(--border)); border-radius: 9999px; border: 2px solid transparent; background-clip: padding-box; } :where(#root, [data-base-ui-portal]) *::-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 { .thot-host { display: flex; flex-direction: column; min-width: 0; min-height: 0; height: var(--thoth-app-height, 100dvh); color: oklch(var(--foreground)); background: oklch(var(--background)); color-scheme: light; } /* Embedded hosts can reserve space for their own header/footer around #root. */ .thot-host--embedded { max-height: 100%; } .thot-host[data-theme="dark"] { color-scheme: dark; } .thot-host--full { --thot-shell-gutter: max(20px, 1.5rem); } .thot-host--full > .thot-context-layout { margin-inline: var(--thot-shell-gutter); border-inline: 1px solid oklch(var(--border)); } .thot-host > .thot-context-layout { flex: 1; min-height: 0; height: auto; } .thot-full-header { /* Match Omics static/css/gsd-theme.css --gsd-red-primary in both themes. */ --thot-header-background: #cb333b; --thot-header-foreground: oklch(99.85% 0.0006 17.2); display: flex; flex: none; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1rem; min-height: 3.75rem; padding: 0.625rem var(--thot-shell-gutter); border-bottom: 1px solid var(--thot-header-background); background: var(--thot-header-background); color: var(--thot-header-foreground); } .thot-full-header__brand { font: 600 1.25rem/1.2 var(--font-heading); } .thot-full-header__controls { display: flex; align-items: center; flex-wrap: wrap; gap: 0.25rem; min-width: 0; } .thot-full-header__user { max-width: 15rem; min-width: 0; font-size: var(--text-control); } .thot-full-header__error { flex-basis: 100%; font-size: var(--text-control); color: inherit; } .thot-full-header__controls button { color: var(--thot-header-foreground); } .thot-full-header__controls button:is(:hover, [aria-expanded="true"]) { color: var(--thot-header-foreground); background: color-mix(in srgb, var(--thot-header-foreground) 14%, transparent); } .thot-full-header :is(button, select):focus-visible { outline: 2px solid var(--thot-header-foreground); outline-offset: 2px; } .thot-full-header .thot-shell-select { color: var(--thot-header-foreground); background: transparent; border-color: color-mix(in srgb, var(--thot-header-foreground) 65%, transparent); } .thot-full-header .thot-shell-select option { color: oklch(var(--foreground)); background: oklch(var(--card)); } /* Native selects can match :focus-visible after a pointer click as well. Suppress only that outer ring; keyboard focus retains its visible outline. */ .thot-full-header .thot-shell-select[data-pointer-focus="true"]:focus { outline: none; box-shadow: none; } .thot-shell-select { min-height: 2rem; max-width: 9rem; padding: 0.25rem 0.5rem; border: 1px solid oklch(var(--input)); border-radius: var(--radius); background: oklch(var(--background)); color: oklch(var(--foreground)); font: 600 var(--text-control)/1.5 var(--font-sans); } .thot-shell-select:focus-visible { outline: 3px solid oklch(var(--ring) / 0.5); outline-offset: 2px; } .thot-user-menu { z-index: 50; min-width: 10rem; padding: 0.25rem; border: 1px solid oklch(var(--border)); border-radius: var(--radius); background: oklch(var(--popover)); color: oklch(var(--popover-foreground)); box-shadow: var(--shadow-md); font: 500 0.875rem/1.5 var(--font-sans); outline: none; } .thot-user-menu__item { padding: 0.375rem 0.5rem; border-radius: 0.25rem; cursor: default; outline: none; } .thot-user-menu__item[data-highlighted] { background: oklch(var(--accent)); color: oklch(var(--accent-foreground)); } .thot-access-state { flex: 1; display: grid; align-content: center; justify-items: center; gap: 1rem; padding: 2rem max(20px, 1.5rem); color: oklch(var(--foreground)); background: oklch(var(--background)); } @media (max-width: 480px) { .thot-full-header__controls { flex: 1; justify-content: flex-end; } .thot-full-header__user { max-width: 9rem; } } /* Omics Portal and Thoth share one document in the embedded deployment. Keep rail geometry on product-specific class names so Hyper/Bootstrap's global spacing utilities (for example .px-4 !important) cannot resize it. */ .thot-session-navigation__header { padding: 1.25rem 1rem 0.75rem; } .thot-session-navigation__primary-controls { display: flex; min-width: 0; flex-direction: column; gap: 0.5rem; padding: 0 1rem 0.75rem; } .thot-session-accordion { display: flex; flex-direction: column; } .thot-session-accordion__item { display: flex; flex-direction: column; flex: 0 0 auto; border-top: 1px solid oklch(var(--border)); } .thot-session-accordion__item[data-open] { flex: 1 1 0; min-height: 2.5rem; max-height: calc(min(18rem, 35dvh) + 2.5rem); } .thot-session-accordion__item > h3 { flex: none; } .thot-session-accordion__trigger { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; width: 100%; min-height: 2.5rem; padding: 0.5rem; font: 600 var(--text-control)/1.5 var(--font-sans); text-align: left; } .thot-session-accordion__trigger:hover { background: oklch(var(--muted)); } .thot-session-accordion__panel { flex: 1 1 auto; max-height: min(18rem, 35dvh); min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; scrollbar-gutter: stable; padding: 0.25rem; } .thot-session-accordion__trigger:focus-visible, .thot-session-accordion__panel:focus-visible { outline: 2px solid oklch(var(--ring)); outline-offset: -2px; } /* UI labels use the same family as controls; monospace is for technical data. */ .thot-label { font-family: var(--font-sans); font-size: var(--text-meta); font-weight: 600; letter-spacing: normal; text-transform: none; color: oklch(var(--muted-foreground)); } .thot-prose { color: oklch(var(--foreground)); font-size: var(--text-body); line-height: 1.6; overflow-wrap: anywhere; } .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: var(--text-page); } .thot-prose h2 { font-size: var(--text-section); } .thot-prose h3 { font-size: var(--text-body); } .thot-prose :where(p, ul, ol, blockquote) { max-width: 75ch; } /* Shared reading contract for Memory and Evidence, independent of UI controls. */ .thot-knowledge-reader, .thot-knowledge-prose { font-family: var(--font-sans); font-size: var(--text-body); font-weight: 400; line-height: 1.65; letter-spacing: normal; color: oklch(var(--foreground)); width: 100%; min-width: 0; max-width: none; overflow-wrap: anywhere; } .thot-knowledge-title { font: 600 var(--text-page)/1.3 var(--font-sans); letter-spacing: -0.015em; margin-top: 0.25rem; } .thot-knowledge-heading { font: 600 var(--text-section)/1.4 var(--font-sans); letter-spacing: normal; margin: 0 0 0.5rem; } .thot-knowledge-meta { font: 400 var(--text-control)/1.5 var(--font-sans); letter-spacing: normal; } .thot-knowledge-meta dt { font-weight: 600; margin-bottom: 0.25rem; } .thot-knowledge-reader code, .thot-knowledge-reader pre, .thot-prose.thot-knowledge-prose code { font-family: var(--font-mono); font-size: var(--text-control); line-height: 1.65; } .thot-prose.thot-knowledge-prose :where(h1, h2, h3, h4, h5, h6) { font: 600 var(--text-body)/1.5 var(--font-sans); letter-spacing: normal; margin: 1.5rem 0 0.5rem; } .thot-prose.thot-knowledge-prose > :first-child { margin-top: 0; } .thot-knowledge-prose strong { font-weight: 600; } .thot-knowledge-prose :where(p, ul, ol, blockquote) { max-width: none; } .thot-prose.thot-knowledge-prose p + p { margin-top: 1.25em; } .thot-knowledge-prose pre { white-space: pre-wrap; overflow-wrap: anywhere; } .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: 1px solid oklch(var(--border)); border-radius: var(--radius); background: oklch(var(--muted) / 0.4); padding: 0.75em 1em; 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: var(--text-control); font-weight: 600; letter-spacing: normal; text-transform: none; 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); } } /* Shiki emits both palettes; select its dark values without rebuilding SQL. */ :is(.dark, [data-bs-theme="dark"]) .shiki, :is(.dark, [data-bs-theme="dark"]) .shiki span { color: var(--shiki-dark) !important; background-color: var(--shiki-dark-bg) !important; font-style: var(--shiki-dark-font-style) !important; font-weight: var(--shiki-dark-font-weight) !important; text-decoration: var(--shiki-dark-text-decoration) !important; } @layer components { .thot-database-grid, .thot-preview-grid, :is(.thot-database-grid, .thot-preview-grid) .ag-theme-alpine { --ag-font-family: var(--font-sans); --ag-font-size: var(--text-control); --ag-background-color: oklch(var(--card)); --ag-foreground-color: oklch(var(--foreground)); --ag-header-background-color: oklch(var(--muted) / 0.72); --ag-header-foreground-color: oklch(var(--foreground)); --ag-border-color: oklch(var(--border)); --ag-row-border-color: oklch(var(--border) / 0.72); --ag-odd-row-background-color: oklch(var(--muted) / 0.18); --ag-row-hover-color: oklch(var(--muted) / 0.55); --ag-selected-row-background-color: oklch(var(--primary) / 0.07); --ag-input-focus-border-color: oklch(var(--primary) / 0.6); --ag-range-selection-border-color: oklch(var(--primary) / 0.6); --ag-header-column-separator-color: oklch(var(--border)); --ag-header-column-separator-display: block; --ag-wrapper-border-radius: 0; --ag-cell-horizontal-padding: 12px; } .thot-database-grid .ag-root-wrapper { border: 0; } .thot-database-grid .ag-cell { display: flex; align-items: center; } .thot-database-grid .ag-header-cell-label { font-weight: 700; } .thot-database-grid .ag-cell-focus:not(.ag-cell-range-selected) { outline: 2px solid oklch(var(--ring) / 0.45); outline-offset: -2px; } .thot-database-grid .ag-cell.thot-database-actions-cell { padding-inline: 2px; } .thot-database-grid .ag-cell.thot-database-actions-cell.ag-cell-focus:not(.ag-cell-range-selected) { outline: none; } .thot-database-grid .ag-cell.thot-database-status-cell { padding-inline: 4px; } .thot-database-grid .ag-pinned-right-header, .thot-database-grid .ag-pinned-right-cols-container { box-shadow: -1px 0 0 oklch(var(--border)); } }