c5aba094bd
- AI Tools moves from a Settings section into a modal behind a button at the Settings tab bar's right edge (AiToolsModal, `actions` on PageTabs, /settings#ai-tools); rows get an enable switch, Default badge, and an Update button for every tool whose catalog names an updater (no version lookup on open); not-installed tools fold behind a disclosure, a finished job's log folds to one line; shared AiToolIcon - codex updates through its own `codex update`, openclaw/hermes gain `update --yes`; update-all runs every installed updater and skips an npm one only when npm does not manage the binary - Add-lane tool picker is one button showing the chosen tool that opens the enabled tools as buttons - Claude Code / Codex AgentHub sub-tab folded into Overview (home editor, hooks, pricing); the path list drops CLAUDE_HOME/CODEX_HOME; HomeDirSetting shows the saved value only while the field differs - Preview/Raw toggle for markdown files in the config FileViewer and the Changes panel's whole-file view (MarkdownPreview: react-markdown + remark-gfm, raw HTML never run, frontmatter as a code block) - docs and the CLAUDE.md marker updated
583 lines
21 KiB
CSS
583 lines
21 KiB
CSS
/**
|
|
* @file index.css
|
|
* @description Global styles and Tailwind CSS configuration for the application.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
/* Palette sourced from Radix Colors (radix-ui.com/colors), an accessible
|
|
* 12-step system built for UI, contrast-checked with APCA — chosen after
|
|
* three rounds of hand-picked values that kept overshooting (too flat, then
|
|
* too dark, then too glaring). Radix's own role guidance for a 12-step scale:
|
|
* 1-2 app/chrome background 6-8 borders (6 subtle, 7-8 stronger)
|
|
* 3-5 component background 9-10 solid (buttons, vibrant fills)
|
|
* 11-12 text (11 secondary, 12 primary)
|
|
* The DARK theme follows it literally: `slate` supplies surface/border/fg and
|
|
* `blue` supplies accent. The LIGHT theme keeps the structure (same roles, same
|
|
* rising-lightness ramp) but swaps the hue family for Claude's own warm ivory
|
|
* and terracotta, because a cool near-white page reads as glare. `green`/
|
|
* `red`/`amber` step 11 supplies the status tokens — the same step used for
|
|
* fg-secondary, since 11 is Radix's guaranteed-readable-text step. Values are
|
|
* the literal Radix hex constants (steps 1/2/3/4/5/6/7/9/11/12), converted to
|
|
* RGB triplets for Tailwind's `<alpha-value>` opacity support.
|
|
*/
|
|
:root,
|
|
[data-mode="light"] {
|
|
/* Light theme — the CSS default, so it applies with no class on <html>.
|
|
`[data-mode="light"]` lets a light theme preview re-scope inside a dark
|
|
page (the Settings appearance cards).
|
|
Radix `slate` light, RE-ORDERED so lightness rises with the index exactly
|
|
as it does in dark: the page is the DARKEST step and a card is brighter
|
|
than the page it sits on. The previous light block used the scale in its
|
|
native direction, which inverted the whole language — a near-white page
|
|
(glare) under grey cards that read as recessed, and every `hover:bg-*`
|
|
darkening instead of lifting.
|
|
|
|
The HUE is warm — Claude's own ivory/terracotta family, not a cool slate.
|
|
A cool near-white ramp kept reading as glare no matter how far the page
|
|
step was pulled down, because the brightest thing on screen was also the
|
|
bluest. Cream lowers the perceived glare at the same measured lightness
|
|
and gives every neutral a warm cast to sit against. The whole ramp sits
|
|
one notch below Claude's own ivory (#faf9f5 card) and no step reaches pure
|
|
white: at full brightness a large light panel still tires the eye. */
|
|
--surface-0: 232 229 218; /* #e8e5da — page background */
|
|
--surface-1: 236 233 223; /* #ece9df — sub-headers inside a card */
|
|
--surface-2: 240 237 228; /* #f0ede4 — inputs, chips, toolbars */
|
|
--surface-3: 245 243 236; /* #f5f3ec — `.card`, Claude's ivory a step down */
|
|
--surface-4: 249 247 241; /* #f9f7f1 — hover / active lift */
|
|
--surface-5: 252 251 247; /* #fcfbf7 — topmost, rare */
|
|
--border: 207 201 184; /* #cfc9b8 */
|
|
--border-light: 222 217 204; /* #ded9cc */
|
|
/* Claude's terracotta (#cc785c), taken down two steps: the brand value is
|
|
3.1:1 on ivory and 3.3:1 under white text, so it works as a large fill and
|
|
fails as a link or a button label. This is 5.3:1 as text on a card and
|
|
5.9:1 white-on-accent. Dark mode keeps its blue — inverting a warm accent
|
|
onto a near-black page is a different problem with a different answer. */
|
|
--accent: 163 74 40; /* #a34a28 */
|
|
--accent-hover: 142 63 32; /* #8e3f20 */
|
|
--fg-primary: 31 30 27; /* #1f1e1b — 15.0:1 on a card */
|
|
--fg-secondary: 96 91 83; /* #605b53 — 6.1:1 */
|
|
/* Measured, not eyeballed: this carries real content (timestamps, counts),
|
|
so it is held above 4.5:1 — 5.4:1 on a card, 4.7:1 on the page — and still
|
|
sits a clear step below fg-secondary. */
|
|
--fg-muted: 104 99 89; /* #686359 */
|
|
/* Warm and soft, to match the surfaces: a neutral-grey shadow goes muddy
|
|
over cream. The SHADOW carries "raised" here, not the quiet border. */
|
|
--shadow-card: 0 1px 2px rgb(60 50 30 / 0.05), 0 2px 6px rgb(60 50 30 / 0.07);
|
|
/* Status: darkened two steps from Radix 11. One step cleared 4.5:1 against
|
|
the card; these also clear it against the status's OWN densest chip (a
|
|
20% tint of itself — 4.5:1), which is where the label actually sits. */
|
|
--status-success: 22 104 66; /* #166842 */
|
|
--status-danger: 170 36 41; /* #aa2429 */
|
|
--status-warning: 133 79 0; /* #854f00 */
|
|
/* What every status/accent FILL is pre-mixed against (see `tint()` in
|
|
tailwind.config.js) — the card surface, because that is where chips and
|
|
alert strips overwhelmingly sit. */
|
|
/* Re-declared by every scope that sets a theme (this block, `.dark`), so it
|
|
resolves against THAT scope's surface-3; a new scope must re-declare it too. */
|
|
--tint-base: var(--surface-3);
|
|
/* Syntax colours for `lib/highlight.ts`. Same hues as the dark set, taken
|
|
four steps down the Tailwind ramp (300 → 700): a pastel keyword is legible
|
|
on a near-black code block and invisible on a light one. */
|
|
--syn-comment: 107 114 128; /* gray-500 #6b7280 */
|
|
--syn-string: 4 120 87; /* emerald-700 #047857 */
|
|
--syn-number: 194 65 12; /* orange-700 #c2410c */
|
|
--syn-keyword: 109 40 217; /* violet-700 #6d28d9 */
|
|
--syn-builtin: 3 105 161; /* sky-700 #0369a1 */
|
|
--syn-function: 180 83 9; /* amber-700 #b45309 */
|
|
--syn-operator: 190 24 93; /* pink-700 #be185d */
|
|
--syn-punctuation: 107 114 128; /* gray-500 #6b7280 */
|
|
--syn-property: 14 116 144; /* cyan-700 #0e7490 */
|
|
--syn-tag: 190 18 60; /* rose-700 #be123c */
|
|
--syn-plain: var(--fg-primary);
|
|
--syn-add: 4 120 87; /* emerald-700 */
|
|
--syn-del: 185 28 28; /* red-700 #b91c1c */
|
|
}
|
|
|
|
.dark {
|
|
/* Radix `slate` (dark), steps 1/2/3/4/5/6/7. The scale is built in the
|
|
opposite direction on purpose — step 6 is LIGHTER than step 3/4 here,
|
|
which is what makes borders rise off a panel instead of sinking into it
|
|
(the bug in the previous, hand-picked dark border). */
|
|
--surface-0: 17 17 19; /* slate-1 #111113 */
|
|
--surface-1: 24 25 27; /* slate-2 #18191b */
|
|
--surface-2: 33 34 37; /* slate-3 #212225 */
|
|
--surface-3: 39 42 45; /* slate-4 #272a2d */
|
|
--surface-4: 46 49 53; /* slate-5 #2e3135 */
|
|
--surface-5: 54 58 63; /* slate-6 #363a3f */
|
|
--border: 54 58 63; /* slate-6 #363a3f */
|
|
--border-light: 67 72 78; /* slate-7 #43484e */
|
|
--accent: 0 144 255; /* blue-9 #0090ff — identical value both themes, Radix's brand anchor */
|
|
--accent-hover: 59 158 255; /* blue-10 #3b9eff */
|
|
--fg-primary: 237 238 240; /* slate-12 #edeef0 */
|
|
--fg-secondary: 176 180 186; /* slate-11 #b0b4ba */
|
|
--fg-muted: 105 110 119; /* slate-9 #696e77 */
|
|
/* Dark surfaces already separate by lightness step; a shadow adds nothing
|
|
visible against a dark page and reads as a stray dark smudge. */
|
|
--shadow-card: none;
|
|
--status-success: 61 214 140; /* green-11 dark #3dd68c */
|
|
--status-danger: 255 149 146; /* red-11 dark #ff9592 */
|
|
--status-warning: 255 202 22; /* amber-11 dark #ffca16 */
|
|
--tint-base: var(--surface-3);
|
|
/* Unchanged from the pastels this file has always drawn code in. */
|
|
--syn-comment: 107 114 128; /* gray-500 #6b7280 */
|
|
--syn-string: 110 231 183; /* emerald-300 #6ee7b7 */
|
|
--syn-number: 253 186 116; /* orange-300 #fdba74 */
|
|
--syn-keyword: 196 181 253; /* violet-300 #c4b5fd */
|
|
--syn-builtin: 125 211 252; /* sky-300 #7dd3fc */
|
|
--syn-function: 254 240 138; /* yellow-200 #fef08a */
|
|
--syn-operator: 249 168 212; /* pink-300 #f9a8d4 */
|
|
--syn-punctuation: 156 163 175; /* gray-400 #9ca3af */
|
|
--syn-property: 103 232 249; /* cyan-300 #67e8f9 */
|
|
--syn-tag: 253 164 175; /* rose-300 #fda4af */
|
|
--syn-plain: 229 231 235; /* gray-200 #e5e7eb — kept off fg-primary so Default is unchanged */
|
|
--syn-add: 110 231 183; /* emerald-300 */
|
|
--syn-del: 252 165 165; /* red-300 #fca5a5 */
|
|
}
|
|
|
|
/* Named themes (`data-theme` on <html>, set by hooks/useTheme.ts, picked in
|
|
* Settings → Appearance). Each overrides only what differs from its mode's
|
|
* default block above; `--tint-base` and light `--syn-plain` are derived there.
|
|
* Dark ones pair with `.dark`, light ones with `[data-mode="light"]`, so a
|
|
* theme can never paint over the wrong mode whatever order the attributes
|
|
* land in. Contrast is held to the defaults' own bar: fg-muted ≥4.5:1 on a
|
|
* light card, status labels ≥4.5:1 on their own /20 chip in light themes. */
|
|
.dark[data-theme="darcula"] {
|
|
--surface-0: 30 31 32; /* #1e1f20 */
|
|
--surface-1: 35 36 37; /* #232425 */
|
|
--surface-2: 39 41 42; /* #27292a */
|
|
--surface-3: 43 43 43; /* #2b2b2b */
|
|
--surface-4: 51 53 55; /* #333537 */
|
|
--surface-5: 60 63 65; /* #3c3f41 */
|
|
--border: 63 66 68; /* #3f4244 */
|
|
--border-light: 77 81 83; /* #4d5153 */
|
|
--accent: 53 146 196; /* #3592c4 */
|
|
--accent-hover: 74 163 214; /* #4aa3d6 */
|
|
--fg-primary: 220 220 220; /* #dcdcdc */
|
|
--fg-secondary: 169 183 198; /* #a9b7c6 */
|
|
--fg-muted: 140 146 150; /* #8c9296 */
|
|
--status-success: 126 194 135; /* #7ec287 */
|
|
--status-danger: 255 143 140; /* #ff8f8c */
|
|
--status-warning: 232 191 106; /* #e8bf6a */
|
|
--syn-comment: 128 128 128; /* #808080 */
|
|
--syn-string: 127 159 105; /* #7f9f69 */
|
|
--syn-number: 104 151 187; /* #6897bb */
|
|
--syn-keyword: 204 120 50; /* #cc7832 */
|
|
--syn-builtin: 136 136 198; /* #8888c6 */
|
|
--syn-function: 255 198 109; /* #ffc66d */
|
|
--syn-operator: 169 183 198; /* #a9b7c6 */
|
|
--syn-punctuation: 169 183 198; /* #a9b7c6 */
|
|
--syn-property: 168 139 192; /* #a88bc0 */
|
|
--syn-tag: 232 191 106; /* #e8bf6a */
|
|
--syn-add: 106 171 115; /* #6aab73 */
|
|
--syn-del: 255 107 104; /* #ff6b68 */
|
|
--syn-plain: 169 183 198; /* #a9b7c6 */
|
|
}
|
|
|
|
.dark[data-theme="apple-dark"] {
|
|
--surface-0: 22 22 24; /* #161618 */
|
|
--surface-1: 28 28 30; /* #1c1c1e */
|
|
--surface-2: 36 36 38; /* #242426 */
|
|
--surface-3: 44 44 46; /* #2c2c2e */
|
|
--surface-4: 54 54 56; /* #363638 */
|
|
--surface-5: 58 58 60; /* #3a3a3c */
|
|
--border: 56 56 58; /* #38383a */
|
|
--border-light: 72 72 74; /* #48484a */
|
|
--accent: 10 132 255; /* #0a84ff */
|
|
--accent-hover: 64 156 255; /* #409cff */
|
|
--fg-primary: 245 245 247; /* #f5f5f7 */
|
|
--fg-secondary: 174 174 178; /* #aeaeb2 */
|
|
--fg-muted: 142 142 147; /* #8e8e93 */
|
|
--status-success: 48 209 88; /* #30d158 */
|
|
--status-danger: 255 140 134; /* #ff8c86 */
|
|
--status-warning: 255 214 10; /* #ffd60a */
|
|
--syn-comment: 127 140 152; /* #7f8c98 */
|
|
--syn-string: 252 106 93; /* #fc6a5d */
|
|
--syn-number: 208 191 105; /* #d0bf69 */
|
|
--syn-keyword: 252 95 163; /* #fc5fa3 */
|
|
--syn-builtin: 93 216 255; /* #5dd8ff */
|
|
--syn-function: 103 183 164; /* #67b7a4 */
|
|
--syn-operator: 161 161 166; /* #a1a1a6 */
|
|
--syn-punctuation: 161 161 166; /* #a1a1a6 */
|
|
--syn-property: 181 140 240; /* #b58cf0 */
|
|
--syn-tag: 252 95 163; /* #fc5fa3 */
|
|
--syn-add: 48 209 88; /* #30d158 */
|
|
--syn-del: 255 105 97; /* #ff6961 */
|
|
--syn-plain: 229 229 234; /* #e5e5ea */
|
|
}
|
|
|
|
[data-mode="light"][data-theme="apple-light"] {
|
|
--surface-0: 233 233 238; /* #e9e9ee */
|
|
--surface-1: 239 239 244; /* #efeff4 */
|
|
--surface-2: 245 245 248; /* #f5f5f8 */
|
|
--surface-3: 251 251 253; /* #fbfbfd */
|
|
--surface-4: 253 253 254; /* #fdfdfe */
|
|
--surface-5: 255 255 255; /* #ffffff */
|
|
--border: 209 209 214; /* #d1d1d6 */
|
|
--border-light: 229 229 234; /* #e5e5ea */
|
|
--accent: 0 102 204; /* #0066cc */
|
|
--accent-hover: 0 85 179; /* #0055b3 */
|
|
--fg-primary: 29 29 31; /* #1d1d1f */
|
|
--fg-secondary: 81 81 84; /* #515154 */
|
|
--fg-muted: 110 110 115; /* #6e6e73 */
|
|
--shadow-card: 0 1px 2px rgb(0 0 0 / 0.05), 0 2px 6px rgb(0 0 0 / 0.06);
|
|
--status-success: 23 107 46; /* #176b2e */
|
|
--status-danger: 179 0 14; /* #b3000e */
|
|
--status-warning: 122 79 0; /* #7a4f00 */
|
|
--syn-comment: 93 108 121; /* #5d6c79 */
|
|
--syn-string: 196 26 22; /* #c41a16 */
|
|
--syn-number: 28 0 207; /* #1c00cf */
|
|
--syn-keyword: 155 35 147; /* #9b2393 */
|
|
--syn-builtin: 11 79 121; /* #0b4f79 */
|
|
--syn-function: 50 109 116; /* #326d74 */
|
|
--syn-operator: 75 75 80; /* #4b4b50 */
|
|
--syn-punctuation: 75 75 80; /* #4b4b50 */
|
|
--syn-property: 57 0 160; /* #3900a0 */
|
|
--syn-tag: 155 35 147; /* #9b2393 */
|
|
--syn-add: 31 122 54; /* #1f7a36 */
|
|
--syn-del: 197 0 15; /* #c5000f */
|
|
}
|
|
|
|
[data-mode="light"][data-theme="intellij-light"] {
|
|
--surface-0: 236 238 242; /* #eceef2 */
|
|
--surface-1: 241 242 245; /* #f1f2f5 */
|
|
--surface-2: 247 248 250; /* #f7f8fa */
|
|
--surface-3: 253 253 254; /* #fdfdfe */
|
|
--surface-4: 255 255 255; /* #ffffff */
|
|
--surface-5: 255 255 255; /* #ffffff */
|
|
--border: 211 213 219; /* #d3d5db */
|
|
--border-light: 228 230 235; /* #e4e6eb */
|
|
--accent: 47 106 227; /* #2f6ae3 */
|
|
--accent-hover: 39 88 192; /* #2758c0 */
|
|
--fg-primary: 30 31 34; /* #1e1f22 */
|
|
--fg-secondary: 73 75 87; /* #494b57 */
|
|
--fg-muted: 108 112 126; /* #6c707e */
|
|
--shadow-card: 0 1px 2px rgb(30 31 34 / 0.05), 0 2px 6px rgb(30 31 34 / 0.06);
|
|
--status-success: 23 106 45; /* #176a2d */
|
|
--status-danger: 173 28 38; /* #ad1c26 */
|
|
--status-warning: 124 82 0; /* #7c5200 */
|
|
--syn-comment: 112 112 112; /* #707070 */
|
|
--syn-string: 6 125 23; /* #067d17 */
|
|
--syn-number: 23 80 235; /* #1750eb */
|
|
--syn-keyword: 0 51 179; /* #0033b3 */
|
|
--syn-builtin: 0 0 128; /* #000080 */
|
|
--syn-function: 0 98 122; /* #00627a */
|
|
--syn-operator: 75 75 75; /* #4b4b4b */
|
|
--syn-punctuation: 75 75 75; /* #4b4b4b */
|
|
--syn-property: 135 16 148; /* #871094 */
|
|
--syn-tag: 0 51 179; /* #0033b3 */
|
|
--syn-add: 6 125 23; /* #067d17 */
|
|
--syn-del: 192 31 42; /* #c01f2a */
|
|
}
|
|
|
|
[data-mode="light"][data-theme="canvas"] {
|
|
--surface-0: 227 220 205; /* #e3dccd */
|
|
--surface-1: 232 226 212; /* #e8e2d4 */
|
|
--surface-2: 237 232 220; /* #ede8dc */
|
|
--surface-3: 243 239 230; /* #f3efe6 */
|
|
--surface-4: 247 244 237; /* #f7f4ed */
|
|
--surface-5: 250 248 243; /* #faf8f3 */
|
|
--border: 203 191 166; /* #cbbfa6 */
|
|
--border-light: 220 211 192; /* #dcd3c0 */
|
|
--accent: 122 82 48; /* #7a5230 */
|
|
--accent-hover: 102 63 34; /* #663f22 */
|
|
--fg-primary: 43 38 32; /* #2b2620 */
|
|
--fg-secondary: 94 85 74; /* #5e554a */
|
|
--fg-muted: 107 97 85; /* #6b6155 */
|
|
--status-success: 54 93 36; /* #365d24 */
|
|
--status-danger: 147 41 31; /* #93291f */
|
|
--status-warning: 109 76 0; /* #6d4c00 */
|
|
--syn-comment: 125 114 98; /* #7d7262 */
|
|
--syn-string: 77 107 31; /* #4d6b1f */
|
|
--syn-number: 154 91 0; /* #9a5b00 */
|
|
--syn-keyword: 138 59 18; /* #8a3b12 */
|
|
--syn-builtin: 47 94 110; /* #2f5e6e */
|
|
--syn-function: 122 90 0; /* #7a5a00 */
|
|
--syn-operator: 138 48 80; /* #8a3050 */
|
|
--syn-punctuation: 107 97 85; /* #6b6155 */
|
|
--syn-property: 59 102 96; /* #3b6660 */
|
|
--syn-tag: 142 47 47; /* #8e2f2f */
|
|
--syn-add: 77 107 31; /* #4d6b1f */
|
|
--syn-del: 159 47 35; /* #9f2f23 */
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: rgb(var(--border)) rgb(var(--surface-2));
|
|
}
|
|
|
|
*::-webkit-scrollbar {
|
|
width: 6px;
|
|
height: 6px;
|
|
}
|
|
|
|
*::-webkit-scrollbar-track {
|
|
background: rgb(var(--surface-2));
|
|
}
|
|
|
|
*::-webkit-scrollbar-thumb {
|
|
background: rgb(var(--border));
|
|
border-radius: 3px;
|
|
}
|
|
|
|
*::-webkit-scrollbar-thumb:hover {
|
|
background: rgb(var(--border-light));
|
|
}
|
|
|
|
::selection {
|
|
background: rgb(var(--accent) / 0.3);
|
|
color: rgb(var(--fg-primary));
|
|
}
|
|
|
|
::-webkit-calendar-picker-indicator {
|
|
cursor: pointer;
|
|
opacity: 0.7;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
/* The browser draws this glyph near-black. Inverting it is a DARK-mode fix;
|
|
applied globally it painted a white icon onto a white field. */
|
|
.dark ::-webkit-calendar-picker-indicator {
|
|
filter: invert(1) brightness(0.8);
|
|
}
|
|
|
|
::-webkit-calendar-picker-indicator:hover {
|
|
opacity: 1;
|
|
}
|
|
|
|
.time-input-custom::-webkit-calendar-picker-indicator {
|
|
display: none;
|
|
-webkit-appearance: none;
|
|
}
|
|
}
|
|
|
|
@layer components {
|
|
.card {
|
|
@apply bg-surface-3 border border-border rounded-xl;
|
|
box-shadow: var(--shadow-card);
|
|
}
|
|
|
|
.card-hover {
|
|
@apply card transition-all duration-200 hover:border-border-light hover:bg-surface-4;
|
|
}
|
|
|
|
.btn-primary {
|
|
@apply inline-flex items-center gap-2 px-4 py-2 bg-accent hover:bg-accent-hover text-white text-sm font-medium rounded-lg transition-colors duration-150;
|
|
}
|
|
|
|
.btn-ghost {
|
|
@apply inline-flex items-center gap-2 px-3 py-1.5 text-sm text-fg-secondary hover:text-fg-primary hover:bg-surface-4 rounded-lg transition-colors duration-150;
|
|
}
|
|
|
|
.badge {
|
|
@apply inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-full border whitespace-nowrap shrink-0;
|
|
}
|
|
|
|
.input {
|
|
@apply bg-surface-2 border border-border rounded-lg px-3 py-2 text-sm text-fg-primary placeholder-fg-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent/30 transition-colors;
|
|
}
|
|
}
|
|
|
|
@layer utilities {
|
|
/* Hide the scrollbar on horizontally scrollable strips (e.g. the Settings
|
|
TOC) where chevron affordances replace it. */
|
|
.no-scrollbar {
|
|
scrollbar-width: none;
|
|
}
|
|
.no-scrollbar::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
/* The run console's terminal attaches to tmux, which repaints the whole pane
|
|
on every frame — xterm's own scrollback stays empty forever, so its
|
|
viewport scrollbar renders as a groove with no thumb that never moves.
|
|
Scrolling there goes through mouse reports to the pane's program, not the
|
|
DOM, so hide the dead affordance. */
|
|
.xterm-viewport {
|
|
scrollbar-width: none;
|
|
}
|
|
.xterm-viewport::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
/* Visually hidden until focused — first Tab lands here before the sidebar. */
|
|
.skip-to-content {
|
|
position: absolute;
|
|
left: 0.75rem;
|
|
top: 0.75rem;
|
|
z-index: 100;
|
|
padding: 0.5rem 0.75rem;
|
|
border-radius: 0.5rem;
|
|
border: 1px solid rgb(var(--border-light));
|
|
background: rgb(var(--surface-2));
|
|
color: rgb(var(--fg-primary));
|
|
font-size: 0.8125rem;
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
transform: translateY(-150%);
|
|
transition: transform 0.15s ease;
|
|
}
|
|
.skip-to-content:focus {
|
|
transform: translateY(0);
|
|
outline: 2px solid rgb(var(--accent));
|
|
outline-offset: 2px;
|
|
}
|
|
}
|
|
|
|
@keyframes pulse-dot {
|
|
0%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
.animate-pulse-dot {
|
|
animation: pulse-dot 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
}
|
|
|
|
/* Rendered markdown (MarkdownPreview.tsx): theme tokens only, so every theme
|
|
reads it; no typography plugin. */
|
|
.md-preview {
|
|
color: rgb(var(--fg-secondary));
|
|
font-size: 13px;
|
|
line-height: 1.6;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
.md-preview > :first-child {
|
|
margin-top: 0;
|
|
}
|
|
.md-preview h1,
|
|
.md-preview h2,
|
|
.md-preview h3,
|
|
.md-preview h4,
|
|
.md-preview h5,
|
|
.md-preview h6 {
|
|
color: rgb(var(--fg-primary));
|
|
font-weight: 600;
|
|
line-height: 1.3;
|
|
margin: 1.4em 0 0.6em;
|
|
}
|
|
.md-preview h1 {
|
|
font-size: 1.6em;
|
|
padding-bottom: 0.3em;
|
|
border-bottom: 1px solid rgb(var(--border));
|
|
}
|
|
.md-preview h2 {
|
|
font-size: 1.3em;
|
|
padding-bottom: 0.25em;
|
|
border-bottom: 1px solid rgb(var(--border));
|
|
}
|
|
.md-preview h3 {
|
|
font-size: 1.12em;
|
|
}
|
|
.md-preview h4,
|
|
.md-preview h5,
|
|
.md-preview h6 {
|
|
font-size: 1em;
|
|
}
|
|
.md-preview p,
|
|
.md-preview ul,
|
|
.md-preview ol,
|
|
.md-preview blockquote,
|
|
.md-preview pre,
|
|
.md-preview table {
|
|
margin: 0 0 0.9em;
|
|
}
|
|
.md-preview ul {
|
|
list-style: disc;
|
|
padding-left: 1.5em;
|
|
}
|
|
.md-preview ol {
|
|
list-style: decimal;
|
|
padding-left: 1.5em;
|
|
}
|
|
.md-preview li + li {
|
|
margin-top: 0.2em;
|
|
}
|
|
.md-preview li > ul,
|
|
.md-preview li > ol {
|
|
margin: 0.2em 0 0;
|
|
}
|
|
.md-preview li.task-list-item {
|
|
list-style: none;
|
|
margin-left: -1.3em;
|
|
}
|
|
.md-preview li.task-list-item input {
|
|
margin-right: 0.4em;
|
|
vertical-align: middle;
|
|
}
|
|
.md-preview a {
|
|
color: rgb(var(--accent));
|
|
text-decoration: underline;
|
|
text-underline-offset: 2px;
|
|
}
|
|
.md-preview strong {
|
|
color: rgb(var(--fg-primary));
|
|
font-weight: 600;
|
|
}
|
|
.md-preview code {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 0.88em;
|
|
padding: 0.1em 0.35em;
|
|
border-radius: 4px;
|
|
background: rgb(var(--surface-3));
|
|
color: rgb(var(--fg-primary));
|
|
}
|
|
.md-preview pre,
|
|
.md-preview .md-frontmatter {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
padding: 0.75em 1em;
|
|
border-radius: 6px;
|
|
border: 1px solid rgb(var(--border));
|
|
background: rgb(var(--surface-0));
|
|
overflow-x: auto;
|
|
white-space: pre;
|
|
}
|
|
.md-preview .md-frontmatter {
|
|
margin: 0 0 1em;
|
|
color: rgb(var(--fg-muted));
|
|
}
|
|
.md-preview pre code {
|
|
padding: 0;
|
|
background: none;
|
|
font-size: inherit;
|
|
}
|
|
.md-preview blockquote {
|
|
padding: 0 1em;
|
|
border-left: 3px solid rgb(var(--border));
|
|
color: rgb(var(--fg-muted));
|
|
}
|
|
.md-preview hr {
|
|
margin: 1.5em 0;
|
|
border: 0;
|
|
border-top: 1px solid rgb(var(--border));
|
|
}
|
|
.md-preview table {
|
|
display: block;
|
|
max-width: 100%;
|
|
overflow-x: auto;
|
|
border-collapse: collapse;
|
|
}
|
|
.md-preview th,
|
|
.md-preview td {
|
|
padding: 0.35em 0.75em;
|
|
border: 1px solid rgb(var(--border));
|
|
}
|
|
.md-preview th {
|
|
color: rgb(var(--fg-primary));
|
|
font-weight: 600;
|
|
background: rgb(var(--surface-2));
|
|
}
|
|
.md-preview img {
|
|
max-width: 100%;
|
|
}
|