mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
The assistant-ui markdown defaults (heading margins up to 32px, 20px paragraph margins, 24px list indent, 24px blockquote padding, 16px code padding) are tuned for the full-page Thread and waste space in the narrow sidebar column. Scope tighter spacing to .ask-fabro-sidebar for headings, paragraphs, lists, blockquotes, and code blocks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
349 lines
12 KiB
CSS
349 lines
12 KiB
CSS
@import "@xterm/xterm/css/xterm.css";
|
|
|
|
/*
|
|
* Do NOT `import "./app.css"` from JS — Bun's CSS bundler rejects the
|
|
* `@layer name, name;` ordering rule between `@import` rules below. This file
|
|
* is built standalone by the Tailwind CLI step in `scripts/build.ts`; the
|
|
* generated `assets/app.css` is linked from `index.template.html`.
|
|
*/
|
|
|
|
/*
|
|
* Cascade layer order. @assistant-ui/react-ui ships unlayered CSS authored
|
|
* against Tailwind v3; in Tailwind v4 utilities live in @layer utilities, and
|
|
* any unlayered CSS wins over layered CSS regardless of selector specificity.
|
|
* Putting assistant-ui in a named layer that we declare BEFORE utilities makes
|
|
* Tailwind v4 utility classes cascade above assistant-ui's scoped preflight.
|
|
*/
|
|
@layer theme, base, assistant-ui, components, utilities;
|
|
|
|
@import "tailwindcss";
|
|
@plugin "@tailwindcss/typography";
|
|
|
|
@import "@assistant-ui/react-ui/styles/index.css" layer(assistant-ui);
|
|
@import "@assistant-ui/react-ui/styles/markdown.css" layer(assistant-ui);
|
|
|
|
@layer base {
|
|
a[href],
|
|
button,
|
|
select,
|
|
summary,
|
|
[role="button"],
|
|
[role="link"],
|
|
[role="option"],
|
|
[role="menuitem"],
|
|
[role="tab"] {
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
|
|
@theme {
|
|
--font-sans: "Geist", ui-sans-serif, system-ui, sans-serif,
|
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
--font-mono: "JetBrains Mono", ui-monospace, monospace;
|
|
|
|
/* Primary — Teal */
|
|
--color-teal-300: #B5DDEF;
|
|
--color-teal-500: #67B2D7;
|
|
--color-teal-700: #357F9E;
|
|
|
|
/* Neutrals Dark — Navy */
|
|
--color-navy-950: #0F1729;
|
|
--color-navy-800: #252C3D;
|
|
--color-navy-600: #4B5768;
|
|
|
|
/* Neutrals Light — Ice */
|
|
--color-ice-50: #F7F9FB;
|
|
--color-ice-100: #E8EDF3;
|
|
--color-ice-300: #A8B5C5;
|
|
|
|
/* Accent */
|
|
--color-mint: #5AC8A8;
|
|
--color-amber: #F0A45B;
|
|
--color-coral: #E86B6B;
|
|
|
|
/* ── Semantic tokens ── */
|
|
--color-page: #0F1729;
|
|
--color-panel: #252C3D;
|
|
--color-panel-alt: #1a2133;
|
|
--color-overlay: rgba(255, 255, 255, 0.04);
|
|
--color-overlay-strong: rgba(255, 255, 255, 0.10);
|
|
--color-fg: #ffffff;
|
|
--color-fg-2: #E8EDF3;
|
|
--color-fg-3: #A8B5C5;
|
|
--color-fg-muted: #4B5768;
|
|
--color-line: rgba(255, 255, 255, 0.06);
|
|
--color-line-strong: rgba(255, 255, 255, 0.12);
|
|
--color-focus: rgba(103, 178, 215, 0.4);
|
|
/* Text color that sits on --color-teal-500 primary fills. */
|
|
--color-on-primary: #0F1729;
|
|
}
|
|
|
|
/* ── Chart variables ── */
|
|
|
|
:root {
|
|
--chart-gridline: rgba(255, 255, 255, 0.04);
|
|
--chart-axis-label: rgba(75, 87, 104, 1);
|
|
}
|
|
|
|
/* ── Background atmosphere ── */
|
|
|
|
.bg-atmosphere {
|
|
background-color: var(--color-page);
|
|
background-image:
|
|
radial-gradient(ellipse 120% 60% at 15% 5%, rgba(53, 127, 158, 0.12) 0%, transparent 50%),
|
|
radial-gradient(ellipse 80% 50% at 85% 90%, rgba(90, 200, 168, 0.07) 0%, transparent 45%);
|
|
background-attachment: fixed;
|
|
}
|
|
|
|
.bg-atmosphere::before {
|
|
content: "";
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 1;
|
|
pointer-events: none;
|
|
opacity: 0.07;
|
|
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
background-repeat: repeat;
|
|
background-size: 200px 200px;
|
|
}
|
|
|
|
/* ── @pierre/diffs brand overrides ── */
|
|
|
|
:root {
|
|
--diffs-font-family: "JetBrains Mono", ui-monospace, monospace;
|
|
--diffs-header-font-family: "Geist", ui-sans-serif, system-ui, sans-serif;
|
|
--diffs-font-size: 13px;
|
|
--diffs-line-height: 20px;
|
|
|
|
/* Surfaces */
|
|
--diffs-bg-buffer-override: #0F1729;
|
|
--diffs-bg-context-override: #161d2e;
|
|
--diffs-bg-hover-override: #1c2438;
|
|
--diffs-bg-separator-override: #252C3D;
|
|
|
|
/* Line numbers */
|
|
--diffs-fg-number-override: #4B5768;
|
|
|
|
/* Additions — mint */
|
|
--diffs-addition-color-override: #5AC8A8;
|
|
--diffs-fg-number-addition-override: rgba(90, 200, 168, 0.5);
|
|
|
|
/* Deletions — coral */
|
|
--diffs-deletion-color-override: #E86B6B;
|
|
--diffs-fg-number-deletion-override: rgba(232, 107, 107, 0.5);
|
|
}
|
|
|
|
/* ── Server-rendered SVG graph overrides ── */
|
|
/* The server injects @media (prefers-color-scheme: dark) which won't reliably
|
|
fire when the OS is in light mode, so we apply dark graph colors always. */
|
|
|
|
.graph-svg text { fill: #c6d4e0; }
|
|
.graph-svg [stroke="#357f9e"] { stroke: #67B2D7; }
|
|
.graph-svg [stroke="#666666"] { stroke: #5a7a94; }
|
|
.graph-svg polygon[fill="#357f9e"] { fill: #67B2D7; }
|
|
.graph-svg polygon[fill="#666666"] { fill: #5a7a94; }
|
|
.graph-svg ellipse[fill="#ffffff"],
|
|
.graph-svg polygon[fill="#ffffff"] { fill: #1a2b3c; }
|
|
.graph-svg ellipse[stroke="#357f9e"],
|
|
.graph-svg polygon[stroke="#357f9e"] { stroke: #67B2D7; }
|
|
.graph-svg [fill="#1a1a1a"] { fill: #c6d4e0; }
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* assistant-ui theme overrides (--aui-* variables) — mapped to Fabro tokens.
|
|
* Values are HSL component triples so assistant-ui's hsl(var(...)) wrapper
|
|
* works. Scoped to .fabro-chat so the shadcn theme cannot leak out.
|
|
*
|
|
* Source colors come from the @theme block above:
|
|
* navy-950 #0F1729 = 220 47% 11%
|
|
* panel #252C3D = 222 24% 19%
|
|
* panel-alt #1a2133 = 223 33% 15%
|
|
* teal-500 #67B2D7 = 200 60% 62% (Fabro's "teal" is a sky blue)
|
|
* mint #5AC8A8 = 163 49% 57%
|
|
* ice-100 #E8EDF3 = 213 27% 93%
|
|
* ice-300 #A8B5C5 = 213 22% 72%
|
|
* ------------------------------------------------------------------------- */
|
|
.fabro-chat {
|
|
--aui-background: 220 47% 11%;
|
|
--aui-foreground: 0 0% 100%;
|
|
--aui-card: 222 24% 19%;
|
|
--aui-card-foreground: 0 0% 100%;
|
|
--aui-popover: 222 24% 19%;
|
|
--aui-popover-foreground: 0 0% 100%;
|
|
--aui-primary: 200 60% 62%;
|
|
--aui-primary-foreground: 220 47% 11%;
|
|
--aui-secondary: 223 33% 15%;
|
|
--aui-secondary-foreground: 0 0% 100%;
|
|
--aui-muted: 223 33% 15%;
|
|
--aui-muted-foreground: 213 22% 72%;
|
|
--aui-accent: 163 49% 57%;
|
|
--aui-accent-foreground: 220 47% 11%;
|
|
--aui-destructive: 0 76% 66%;
|
|
--aui-destructive-foreground: 0 0% 100%;
|
|
--aui-border: 218 28% 17%;
|
|
--aui-input: 218 28% 17%;
|
|
--aui-ring: 200 60% 62%;
|
|
--aui-radius: 0.5rem;
|
|
--aui-thread-max-width: 44rem;
|
|
}
|
|
|
|
/* In the narrow Ask-Fabro sidebar column, drop the message-column max-width so
|
|
* messages and the composer span the full column width. Declared AFTER
|
|
* .fabro-chat so it wins on cascade order (the element has both classes).
|
|
* Also nudge the base font size down to 14px for a tighter feel. */
|
|
.ask-fabro-sidebar {
|
|
--aui-thread-max-width: 100%;
|
|
font-size: 0.875rem; /* 14px */
|
|
}
|
|
|
|
/* Override assistant-ui defaults that are tuned for the full-page Thread but
|
|
* waste space inside the narrow sidebar column. Layered into assistant-ui so
|
|
* we beat the unlayered Tailwind v3 rules without `!important`. */
|
|
@layer assistant-ui {
|
|
/* Let user and assistant message bubbles span the full sidebar column
|
|
* (default clips them to 80% of an already-narrow column). */
|
|
.ask-fabro-sidebar .aui-user-message-content,
|
|
.ask-fabro-sidebar .aui-assistant-message-content {
|
|
max-width: 100%;
|
|
font-size: 0.875rem;
|
|
line-height: 1.5rem;
|
|
}
|
|
/* Shrink the right-justified spacer on user messages so short replies do
|
|
* not crowd the right edge unnecessarily. */
|
|
.ask-fabro-sidebar .aui-user-message-root {
|
|
grid-template-columns: minmax(24px, 1fr) auto;
|
|
padding-top: 0.5rem;
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
.ask-fabro-sidebar .aui-assistant-message-root {
|
|
padding-top: 0.5rem;
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
/* min-width: 0 on the grid track + min-width: 0 / overflow on the content
|
|
* so wide children (long lines in code blocks, tables) honour the column
|
|
* width and let their own overflow-x scroll instead of stretching the
|
|
* sidebar. Same fix on user messages for symmetry. */
|
|
.ask-fabro-sidebar .aui-assistant-message-content,
|
|
.ask-fabro-sidebar .aui-user-message-content {
|
|
min-width: 0;
|
|
overflow-x: hidden;
|
|
}
|
|
/* Give user message bubbles a lighter, solid surface so they read as raised
|
|
* cards. The default muted bubble color (panel-alt) is nearly identical to
|
|
* the translucent `bg-panel/40` sidebar once composited over the page, so
|
|
* bubbles visually disappeared into the column. */
|
|
.ask-fabro-sidebar .aui-user-message-content {
|
|
background-color: var(--color-panel);
|
|
}
|
|
/* Inset the assistant message content from the column's right edge so the
|
|
* code block (dark pre box) has visible right margin and doesn't appear to
|
|
* bleed against the sidebar edge when its content overflows. */
|
|
.ask-fabro-sidebar .aui-assistant-message-content {
|
|
padding-right: 1rem;
|
|
}
|
|
/* The viewport-footer centers children; stretch instead so the composer
|
|
* fills the column width (otherwise it shrinks to its intrinsic content).
|
|
* `margin-top: auto` pushes the footer to the bottom of the flex column so
|
|
* the composer sits at the bottom in the empty state (without it, the
|
|
* footer flows after the empty Welcome/Messages area at the top). */
|
|
.ask-fabro-sidebar .aui-thread-viewport-footer {
|
|
align-items: stretch;
|
|
padding-bottom: 0;
|
|
margin-top: auto;
|
|
}
|
|
/* Hide the assistant avatar to reclaim horizontal space — the column is
|
|
* narrow enough that the 2.5rem avatar + 1rem gutter is too much chrome.
|
|
* Also hide the welcome-state avatar for the same reason. */
|
|
.ask-fabro-sidebar .aui-assistant-message-root > .aui-avatar-root,
|
|
.ask-fabro-sidebar .aui-thread-welcome-root .aui-avatar-root {
|
|
display: none;
|
|
}
|
|
.ask-fabro-sidebar .aui-assistant-message-root {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
.ask-fabro-sidebar .aui-assistant-message-content {
|
|
grid-column: 1;
|
|
}
|
|
/* Hide the per-message Copy / Refresh action bar to reclaim vertical space. */
|
|
.ask-fabro-sidebar .aui-assistant-action-bar-root,
|
|
.ask-fabro-sidebar .aui-user-action-bar-root {
|
|
display: none;
|
|
}
|
|
/* Welcome message also wants smaller text. */
|
|
.ask-fabro-sidebar .aui-thread-welcome-message {
|
|
font-size: 0.875rem;
|
|
line-height: 1.5rem;
|
|
}
|
|
/* Drop the solid navy background that assistant-ui paints on the thread
|
|
* root + viewport; the sidebar already supplies its own translucent panel
|
|
* background and the painted navy created a visible block around the
|
|
* composer at the bottom of the column. */
|
|
.ask-fabro-sidebar .aui-thread-root,
|
|
.ask-fabro-sidebar .aui-thread-viewport,
|
|
.ask-fabro-sidebar .aui-thread-viewport-footer {
|
|
background-color: transparent;
|
|
}
|
|
/* Code blocks: the <pre> is already constrained to the column via the
|
|
* parent's overflow-x: hidden, but Chromium drops the pre's padding-right
|
|
* when content overflows, so long code lines visually bleed up to the
|
|
* pre's right edge. Promoting <code> to inline-block lets its own
|
|
* padding-right become part of the scrollable content. */
|
|
.ask-fabro-sidebar .aui-md-pre {
|
|
max-width: 100%;
|
|
}
|
|
.ask-fabro-sidebar .aui-md-pre > code {
|
|
display: inline-block;
|
|
min-width: 100%;
|
|
padding-right: 1rem;
|
|
}
|
|
/* Shrink markdown headings for the narrow column. The assistant-ui defaults
|
|
* go up to 36px (h1), which dominates the sidebar. H1 stays distinct at
|
|
* 18px; H2/H3 read as bold body text; H4-H6 get no special styling. The
|
|
* default heading margins (mt-8/mb-8 = 32px) are also sized for the
|
|
* full-page Thread, so tighten them to suit the smaller type. */
|
|
.ask-fabro-sidebar .aui-md-h1 {
|
|
font-size: 1.125rem; /* 18px */
|
|
line-height: 1.5rem;
|
|
font-weight: 700;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
.ask-fabro-sidebar .aui-md-h2,
|
|
.ask-fabro-sidebar .aui-md-h3 {
|
|
font-size: 0.875rem; /* 14px */
|
|
line-height: 1.5rem;
|
|
font-weight: 700;
|
|
margin-top: 1rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.ask-fabro-sidebar .aui-md-h4,
|
|
.ask-fabro-sidebar .aui-md-h5,
|
|
.ask-fabro-sidebar .aui-md-h6 {
|
|
font-size: 0.875rem; /* 14px */
|
|
line-height: 1.5rem;
|
|
font-weight: 400;
|
|
margin-top: 1rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
/* Tighten paragraph spacing: the default 20px margins + 28px line-height
|
|
* are sized for the wide Thread. */
|
|
.ask-fabro-sidebar .aui-md-p {
|
|
margin-top: 0.75rem;
|
|
margin-bottom: 0.75rem;
|
|
line-height: 1.5rem;
|
|
}
|
|
/* Pull list indentation in (default ml-6 = 24px eats column width) and
|
|
* shrink the vertical margins. */
|
|
.ask-fabro-sidebar .aui-md-ul,
|
|
.ask-fabro-sidebar .aui-md-ol {
|
|
margin-top: 0.75rem;
|
|
margin-bottom: 0.75rem;
|
|
margin-left: 1.25rem;
|
|
}
|
|
/* Blockquote: default pl-6 (24px) is a large share of the narrow column. */
|
|
.ask-fabro-sidebar .aui-md-blockquote {
|
|
padding-left: 0.75rem;
|
|
}
|
|
/* Code blocks: trim the default p-4 (16px) padding. */
|
|
.ask-fabro-sidebar .aui-md-pre {
|
|
padding: 0.75rem;
|
|
}
|
|
}
|