From e85ddd6337bb53c7b4db8a5ddd6b2711e2ed5f9d Mon Sep 17 00:00:00 2001 From: Real-Fruit-Snacks <87195021+Real-Fruit-Snacks@users.noreply.github.com> Date: Sun, 5 Jul 2026 08:14:27 -0400 Subject: [PATCH] Terminal Workbench v1.1.1 A terminal-inspired Obsidian theme with full dark and light modes, a consistent monospace "manifest" idiom across properties, code blocks, tabs, and breadcrumbs, styled Mermaid diagrams, square-rounded tags, and custom task states. Includes a GitHub Pages showcase, a portable design spec, and a release workflow that publishes manifest.json and theme.css on version tags. --- .github/workflows/release.yml | 24 + .gitignore | 10 + LICENSE | 21 + README.md | 85 ++ docs/.nojekyll | 0 docs/THEME-SPEC.md | 196 ++++ docs/index.html | 291 ++++++ manifest.json | 6 + theme.css | 1711 +++++++++++++++++++++++++++++++++ versions.json | 16 + 10 files changed, 2360 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docs/.nojekyll create mode 100644 docs/THEME-SPEC.md create mode 100644 docs/index.html create mode 100644 manifest.json create mode 100644 theme.css create mode 100644 versions.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1096710 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +name: Release Obsidian theme + +on: + push: + tags: + - "*" + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Create release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + tag="${GITHUB_REF#refs/tags/}" + gh release create "$tag" \ + --title="$tag" \ + manifest.json theme.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93e9851 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Dev tooling and process artifacts — never ship these +.claude/ +docs/preview.html +docs/superpowers/ + +# OS / editor / build noise +.DS_Store +node_modules/ +*.log +.obsidian/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e8f483a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Matt and Codex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..59ace80 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# Terminal Workbench + +[![Latest release](https://img.shields.io/github/v/release/Real-Fruit-Snacks/terminal-workbench?label=release&color=2a9d6e)](https://github.com/Real-Fruit-Snacks/terminal-workbench/releases/latest) +[![License: MIT](https://img.shields.io/github/license/Real-Fruit-Snacks/terminal-workbench?color=2a9d6e)](LICENSE) +[![Obsidian](https://img.shields.io/badge/obsidian-1.5.0%2B-483699)](https://obsidian.md) + +A modern terminal-inspired theme for [Obsidian](https://obsidian.md), built for people who spend the day in panes, shells, logs, editors, and command palettes. + +The design goal is not retro green-on-black nostalgia. It is a calm, dense, high-contrast working surface: graphite backgrounds, crisp typography, restrained ANSI-style accents, readable code, and pane chrome that feels close to a modern terminal without turning your notes into a novelty skin. + +**[View the live showcase](https://real-fruit-snacks.github.io/terminal-workbench/)** for both modes, the full palette, and feature details. + +## Highlights + +- Full dark and light modes, each a deliberate palette rather than an inversion +- A consistent "terminal manifest" idiom across the interface: monospace micro-labels for properties, code block headers, tab titles, and breadcrumbs +- Code blocks with a header band, language label, and framed styling that matches between editing and reading views +- Custom task states with distinct checkbox colors: done, cancelled, deferred, and important +- Styled Mermaid flowchart, state, sequence, and class diagrams that follow the theme palette +- Respects your Obsidian settings: accent color, interface, text, and monospace fonts, and font size all flow through +- Print-friendly: decorative elements are stripped from PDF export + +## Installation + +### Community themes + +Once available in the community directory: + +1. Open `Settings > Appearance`. +2. Under **Themes**, select **Manage**. +3. Search for `Terminal Workbench` and select **Install and use**. + +### Manual + +1. Create the folder `/.obsidian/themes/Terminal Workbench/`. +2. Download `theme.css` and `manifest.json` from the [latest release](https://github.com/Real-Fruit-Snacks/terminal-workbench/releases/latest) and copy them into that folder. +3. Open Obsidian and go to `Settings > Appearance > Themes`. +4. Choose `Terminal Workbench`. + +Requires Obsidian `1.5.0` or newer. + +## Respecting your settings + +Terminal Workbench builds on Obsidian's own settings rather than replacing them: + +- The accent color follows `Settings > Appearance > Accent color` if you customize it; otherwise the theme's terminal green is used. +- Interface, text, and monospace fonts set under `Settings > Appearance` take priority over the theme's font stacks. +- Font size is controlled by the Appearance font-size slider, untouched by the theme. + +## Customization + +Terminal Workbench includes settings for the [Style Settings](https://github.com/mgmeyers/obsidian-style-settings) community plugin: + +- Primary, secondary, and warm accent colors, configurable separately for light and dark mode +- Editor, UI, and code fonts +- Editor line width and UI corner radius +- Compact workspace mode +- Soft neon highlights +- Active-line terminal prompt marker + +Suggested fonts (the theme falls back to system fonts without them): + +- Editor and code: Berkeley Mono, JetBrains Mono, Cascadia Code, IBM Plex Mono +- Interface: Inter, SF Pro Text, Segoe UI + +## Compatibility + +The theme uses `color-mix()` for derived tints, supported by every desktop build and current mobile build that meets the minimum app version. On very old Android WebViews the theme falls back to static colors for selection, hover, and glow effects; other tints degrade gracefully. + +## Development + +| Path | Purpose | +|---|---| +| `theme.css` | The theme | +| `manifest.json` | Theme metadata | +| `versions.json` | Release compatibility map | +| `docs/index.html` | Showcase page (GitHub Pages) | +| `docs/THEME-SPEC.md` | Portable design specification for reusing this visual system elsewhere | +| `.github/workflows/release.yml` | Creates a GitHub release with `manifest.json` and `theme.css` when a version tag is pushed | + +To cut a release: bump `version` in `manifest.json`, add the entry to `versions.json`, then push a tag with the same version number. + +## License + +[MIT](LICENSE) diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/THEME-SPEC.md b/docs/THEME-SPEC.md new file mode 100644 index 0000000..050ce2c --- /dev/null +++ b/docs/THEME-SPEC.md @@ -0,0 +1,196 @@ +# Terminal Workbench — Portable Design Spec + +A platform-agnostic specification of the Terminal Workbench visual system. Hand this to any tool, framework, or designer to reproduce the theme's look in a terminal emulator, a website, a code editor, a dashboard, a slide deck — anywhere. It captures **what** the theme is (colors, type, shape, motion, the design philosophy) independent of Obsidian's specific CSS class names. + +> Origin: distilled from the Terminal Workbench Obsidian theme v1.1.0. The Obsidian implementation lives in `theme.css`; this document is the reusable core. + +--- + +## 1. Design philosophy + +The one paragraph that governs every decision below: + +> **A calm, dense, high-contrast working surface for people who live in panes, shells, logs, and code — not retro green-on-black novelty.** Graphite backgrounds, crisp typography, restrained ANSI-style accents, readable code, and chrome that feels close to a modern terminal. The interface stays quiet; signal (links, prompts, active elements, syntax) carries the color. When in doubt, remove the flourish. + +Five principles that fall out of that: + +1. **Quiet chrome, loud signal.** Backgrounds, borders, and inactive UI are near-monochrome graphite. Color is spent only on things that mean something: the active pane, a link, a syntax token, a status. +2. **Dense but breathable.** Tight vertical rhythm and small UI text, but generous line-height in prose (1.7) so long reading sessions don't fatigue. +3. **One accent family, used sparingly.** A single green primary + a cyan secondary + a warm amber. Never a rainbow. Semantic red/orange/violet exist only for meaning (error, value, keyword). +4. **Monospace as a UI voice, not just for code.** Structural labels (section headers, tab titles, breadcrumbs, metadata keys) use the mono font in small uppercase with wide tracking — the "terminal manifest" idiom. Prose and long-form body stay in a humanist sans/serif. +5. **Flat, not glassy.** No gradients as decoration, no drop shadows except functional elevation (menus, modals). Depth comes from layered flat surfaces and hairline borders. + +--- + +## 2. Color system + +The theme is built on **semantic tokens** that resolve to different raw values in dark and light mode. Always design against the token names; the raw hex is per-mode. This is the whole point of the system — a consumer wires up the token names once and gets both modes. + +### 2.1 Accent ramp (mode-aware) + +Three accents. In light mode they darken to stay legible on light surfaces. + +| Token | Role | Dark | Light | +|---|---|---|---| +| `accent` (primary) | Prompts, active tab, primary action, H2, string literals, success | `#63f2ab` (mint green) | `#007a4d` | +| `accent-alt` (secondary) | Links, H3, metadata, functions, quiet highlights | `#6bdcff` (cyan) | `#006f9e` | +| `warm` | Warnings, text-highlight, H4, unresolved links, properties | `#f0c674` (amber) | `#a46600` | + +Semantic hues (used only where they carry meaning — errors, syntax): + +| Token | Dark | Light | Used for | +|---|---|---|---| +| `red` | `#ff6e7a` | `#c8324c` | Errors, cancelled state, code tags | +| `orange` | `#f7a35c` | `#b65800` | Code values / numbers | +| `violet` | `#b78cff` | `#7357b8` | Code keywords | + +**Rule:** the primary accent should be derivable from / overridable by the host's own accent setting where one exists (e.g. an HSL triple), falling back to the mint green. Don't hard-clobber a user's accent choice. + +### 2.2 Surfaces (graphite ramp) + +Five background steps from deepest to lightest, plus borders. Depth = stepping through these, never shadows. + +| Token | Dark | Light | Role | +|---|---|---|---| +| `bg-0` | `#090c0d` | `#f5f7f4` | Page / editor background (deepest dark / lightest light) | +| `bg-1` | `#0e1214` | `#edf2ee` | Sidebars, secondary panels, title/tab bar | +| `bg-2` | `#13191c` | `#e2eae5` | Form fields, code block body, table header | +| `bg-3` | `#182024` | `#d6e1db` | Hover states, active tab block, code header band | +| `bg-4` | `#202a2f` | `#c8d5cf` | Highest raised surface | +| `border` | `#2a363d` | `#bfcbc5` | Default hairline (1px) | +| `border-strong` | `#39484f` | `#9daea7` | Hover / emphasized dividers | + +**Layering rule (important for panels):** a nested panel steps to the next lighter surface in dark mode and the next *darker* surface in light mode — the ordinal always means "further from the page." A code block is a good test case: page → body one step in → header band one step further. Keep at least ~1.1:1 luminance contrast between adjacent layers or they blur together (this is the exact bug that made the light-mode code block look flat before being deepened). + +### 2.3 Text + +| Token | Dark | Light | Role | +|---|---|---|---| +| `text-normal` | `#dce4df` | `#17201d` | Primary body text | +| `text-soft` | `#b4c3bd` | `#34443f` | Secondary text, code default | +| `text-muted` | `#879994` | `#60706a` | Labels, inactive tabs, captions | +| `text-faint` | `#63736f` | `#81918a` | Separators, icons, placeholder, glyphs | +| `text-on-accent` | `#07100d` | `#f9fbf8` | Text sitting on an accent fill | + +**Contrast:** target WCAG AA (4.5:1) for body and small text. Note that a bright dark-mode accent (e.g. mint on near-black) often needs to be *darkened* — not lightened — for light mode to keep small-text contrast; the light accents above are chosen for exactly this. Verify small colored text (tags, labels) specifically, not just body. + +### 2.4 Derived tints + +Translucent tints are generated from the accents rather than hand-picked, so they track a changed accent automatically. Pattern: `mix(accent, transparent, N%)`. + +| Purpose | Recipe | +|---|---| +| Selection background | `accent` @ ~20% (dark) / ~17% (light) | +| Active-line / row highlight | `accent-alt` @ ~7.5% | +| Nav item active background | `accent` @ ~10.5% | +| Blockquote background | `accent` @ ~7% | +| Tag background / border | `accent` @ 13% fill, 28% border | +| Text highlight (mark) | `warm` @ ~22% | +| Focus ring | `accent` @ ~18%, as a 2px outline | + +Provide static fallbacks where the mixing function may be unsupported (old engines): a flat pre-mixed hex for the load-bearing ones (selection, hover, glow). + +--- + +## 3. Typography + +Three font roles. The consumer supplies actual families; these are the defaults and the *usage rules* matter more than the specific fonts. + +| Role | Default stack | Used for | +|---|---|---| +| `font-mono` | Berkeley Mono → JetBrains Mono → Cascadia Code → IBM Plex Mono → SFMono-Regular → Consolas → monospace | Code, and all "manifest" UI labels | +| `font-ui` | Inter → SF Pro Text → Segoe UI → system-ui → sans-serif | Interface chrome, nav, prose (interface) | +| `font-text` | same as mono here (editor is monospace by design) | Editor / reading body | + +**Respect host font settings:** if the platform lets a user pick fonts, the theme's stacks should be a *fallback layer*, not an override. Users' choices win. + +### The "terminal manifest" label idiom + +This is the theme's signature UI move — reuse it for any structural label: + +``` +font: var(--font-mono); +font-size: 10.5px; /* 9.5–11px depending on prominence */ +font-weight: 600–700; +letter-spacing: 0.06–0.09em; +text-transform: uppercase; +color: text-muted; /* or text-faint for the quietest */ +``` + +Applied to: section/property headings ("PROPERTIES"), code-block language labels, tab titles, breadcrumb segments. It's what makes disparate UI regions feel like one system. + +### Prose type scale + +| Element | Size | Weight | Color | Notes | +|---|---|---|---|---| +| Body | 15px | 400 | text-normal | line-height 1.7 | +| Inline title / H1 | 2.1em / 1.72em | 760 | text-normal | H1/H2 get a fading underline rule | +| H2 | 1.38em | 740 | **accent** | | +| H3 | 1.16em | 720 | **accent-alt** | | +| H4 | 1.04em | 700 | **warm** | | +| H5–H6 | 0.95em | 700 | text-muted | uppercase, wide tracking | +| Inline code | 0.92em | — | code-default on bg-2, hairline border, pill radius | mono | + +Line-height: `1.7` normal (prose), `1.45` tight (UI), `1.62` code. + +--- + +## 4. Shape, spacing, motion + +| Property | Value | Notes | +|---|---|---| +| Corner radius (base) | 6px | `radius-s` = 4px, `radius-m` = 6px, `radius-l` = 8px | +| Pill radius | 999px | toggles, slider thumbs | +| Tag / chip radius | 4px (`radius-s`) | tags, small chips — square with rounded corners, not oval | +| Checkbox radius | 4px | | +| Border width | 1px hairline everywhere | the primary way surfaces are defined | +| Border on single-sided accents | 0 radius | rounded corners only with full borders | +| Pane shadow | `0 20px 60px rgba(0,0,0,0.22)` | menus/modals/popovers only — the one place shadows are allowed | +| Optional "soft neon" glow | `0 0 18px mix(accent, transparent, 28%)` | opt-in accent glow on active elements; off by default | + +**Motion:** transitions only on interactive state changes (background, color, border, box-shadow), ~120ms ease. **Gate all motion behind `prefers-reduced-motion`** — no animation for users who opt out. + +**Density:** offer a compact mode that tightens UI font sizes and control heights (~15% smaller) without touching prose readability. + +--- + +## 5. Component patterns + +How the tokens compose into recurring UI, described behaviorally so they port to any widget system: + +- **Active pane/tab:** solid `bg-3` block fill + accent-colored mono uppercase label. Seated flush in its bar (no detached floating outline). Optional top accent line + glow when "soft neon" is on. +- **Inactive tab/nav item:** transparent background, `text-muted` label; on hover → subtle `bg` hover tint + brighter text; active nav item gets an inset accent left-bar (2px). +- **Panels (code blocks, callouts, embeds, metadata):** hairline border, `radius-m`, background one surface-step from the page. Structural header uses the manifest label idiom, separated by a faded hairline. +- **Callouts:** tinted from the callout's semantic color — `mix(color, page, ~9%)` fill, `mix(color, border, ~34%)` border, 3px solid color left-bar, no shadow. +- **Inputs:** `bg` field, hairline border, `radius`; focus = accent border + 2px accent-tint ring, no glow. +- **Primary button:** accent fill, `text-on-accent`, weight 650. Hover lightens the accent. +- **Tables:** collapsed hairline grid, `radius-m` outer, header on `bg-2`, alternating row tint at ~2.5–3% opacity, hover row tint from `accent-alt` @ ~7%. +- **Tags/chips:** accent tint fill + border, `radius-s` (square with rounded corners), small; hover inverts to solid accent + `text-on-accent`. Reserve the full pill radius for toggles and slider thumbs. +- **Checkboxes/states:** drive fill and border from a single `checkbox-color` variable so per-state variants (done/cancelled/deferred/important → accent/red/cyan/amber) just reassign that one variable rather than restyling the control. This is the cleanest way to expose stateful color. +- **Scrollbars:** thin (10px), transparent track, thumb = `text-faint` @ ~46% with a transparent border via background-clip so it reads as inset. + +--- + +## 6. Both modes are mandatory + +Every token above has a dark and light value. Design and verify in both. Common pitfalls this theme hit and fixed: + +- A dark-mode accent usually must **darken** (not lighten) for light mode to keep contrast. +- Layered surfaces need enough luminance gap in *both* modes — light mode is where panels tend to collapse into the page. +- If the platform applies its own dark-mode filter to embedded content (Obsidian pixel-inverts Mermaid, for example), account for it rather than fighting it with a counter-filter. + +Provide `color-scheme: dark` / `light` (or the platform equivalent) so native controls (scrollbars, form widgets) match. + +--- + +## 7. What to hand a tool + +When asking another system to "make this theme," give it: + +1. **Section 1** (philosophy) verbatim — it resolves ambiguous judgment calls. +2. **Section 2** color tables — the token→value map for both modes. +3. **Section 3** the three font roles + the manifest label idiom. +4. **Sections 4–5** for shape/motion and the component behaviors relevant to that platform. +5. A note on which surfaces exist in the target (a terminal has far fewer than an editor) so it maps tokens to what's actually there. + +The deliverable from any consumer should be checkable against Section 6: does it work in both modes, with adequate contrast, quiet chrome, and color spent only on signal? diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..e1a70fc --- /dev/null +++ b/docs/index.html @@ -0,0 +1,291 @@ + + + + + + Terminal Workbench — an Obsidian theme + + + + + +
+
+ Terminal Workbench + +
+
+ +
+
+

$ terminal-workbench

+

+ A modern terminal-inspired theme for Obsidian. Not retro green-on-black nostalgia — + a calm, dense, high-contrast working surface: graphite backgrounds, crisp typography, + restrained ANSI-style accents, and readable code in both dark and light modes. +

+ + +
+
+
+ gym tracker + web server + + +
+ +
+
+ Pentesting/File Transfer/Python/Web Server +
+
+

Web Server

+

Spin up a quick file transfer endpoint, watch the logs, and keep + #latency and #errors in view during warmup.

+
The theme should feel like a serious terminal setup: crisp, fast, readable, and good at 2am.
+
Serve the directory
+
+
>_python
+
import http.server
+
+PORT = 8000
+handler = http.server.SimpleHTTPRequestHandler
+with socketserver.TCPServer(("", PORT), handler) as httpd:
+    httpd.serve_forever()
+
+
Checklist
+
    +
  • Open command palette
  • +
  • Verify active task styling
  • +
  • Cancelled task
  • +
  • Deferred task
  • +
  • Important task
  • +
+
+
+
+ +
+ Palette +
+
+ +
+ Features +
+
Two deliberate modes

Dark and light are separate palettes, not an inversion. Accents darken in light mode to hold contrast for small text.

+
Terminal manifest idiom

Monospace micro-labels unify properties, code block headers, tab titles, and breadcrumbs into one visual system.

+
Framed code blocks

A header band with language label and consistent framing in both editing and reading views.

+
Task states

Done, cancelled, deferred, and important tasks each get a distinct checkbox color driven by native Obsidian variables.

+
Respects your settings

Your accent color, fonts, and font size flow through the theme instead of being overridden.

+
Style Settings support

Accents per mode, fonts, line width, radius, compact mode, soft neon, and a terminal prompt marker.

+
+
+ +
+ Install +
    +
  1. Open Settings > Appearance in Obsidian.
  2. +
  3. Under Themes, select Manage and search for Terminal Workbench (once accepted into the community directory).
  4. +
  5. Or install manually: copy theme.css and manifest.json from the latest release into .obsidian/themes/Terminal Workbench/.
  6. +
+
+ + +
+ + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..611c616 --- /dev/null +++ b/manifest.json @@ -0,0 +1,6 @@ +{ + "name": "Terminal Workbench", + "version": "1.1.1", + "minAppVersion": "1.5.0", + "author": "Matt and Codex" +} diff --git a/theme.css b/theme.css new file mode 100644 index 0000000..34c706e --- /dev/null +++ b/theme.css @@ -0,0 +1,1711 @@ +/* @settings + +name: Terminal Workbench +id: terminal-workbench +settings: + - id: ta-colors + title: Colors + type: heading + level: 1 + - id: ta-accent + title: Primary accent + description: Main prompt, active tab, and link color. Follows your Obsidian accent color until overridden here. + type: variable-themed-color + format: hex + default-light: '#007a4d' + default-dark: '#63f2ab' + - id: ta-accent-alt + title: Secondary accent + description: Used for sidebars, metadata, and quiet highlights. + type: variable-themed-color + format: hex + default-light: '#006f9e' + default-dark: '#6bdcff' + - id: ta-warm + title: Warm accent + description: Used for warnings, highlights, and subtle attention. + type: variable-themed-color + format: hex + default-light: '#a46600' + default-dark: '#f0c674' + - id: ta-layout + title: Layout + type: heading + level: 1 + - id: ta-editor-line-width + title: Editor line width + description: Reading and editing width in pixels. + type: variable-number-slider + format: px + default: 780 + min: 620 + max: 1040 + step: 20 + - id: ta-ui-radius + title: UI radius + description: Corner radius for controls and panes. + type: variable-number-slider + format: px + default: 6 + min: 0 + max: 8 + step: 1 + - id: ta-compact + title: Compact workspace + description: Tightens sidebars, tabs, and headers. + type: class-toggle + default: false + - id: ta-soft-neon + title: Soft neon highlights + description: Adds a restrained glow to active elements. + type: class-toggle + default: false + - id: ta-terminal-prompts + title: Active-line prompt marker + description: Shows a small terminal prompt beside the active editor line. + type: class-toggle + default: false + - id: ta-fonts + title: Fonts + type: heading + level: 1 + - id: ta-font-editor + title: Editor font + type: variable-text + default: '"Berkeley Mono", "JetBrains Mono", "Cascadia Code", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace' + - id: ta-font-ui + title: UI font + type: variable-text + default: '"Inter", "SF Pro Text", "Segoe UI", system-ui, sans-serif' + - id: ta-font-code + title: Code font + type: variable-text + default: '"Berkeley Mono", "JetBrains Mono", "Cascadia Code", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace' + +*/ + +body { + --ta-accent: hsl(var(--accent-h), var(--accent-s), var(--accent-l)); + --ta-accent-alt: #6bdcff; + --ta-warm: #f0c674; + --ta-red: #ff6e7a; + --ta-orange: #f7a35c; + --ta-violet: #b78cff; + --ta-font-editor: "Berkeley Mono", "JetBrains Mono", "Cascadia Code", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace; + --ta-font-ui: "Inter", "SF Pro Text", "Segoe UI", system-ui, sans-serif; + --ta-font-code: "Berkeley Mono", "JetBrains Mono", "Cascadia Code", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace; + --ta-editor-line-width: 780px; + --ta-ui-radius: 6px; + --ta-border-width: 1px; + --ta-pane-shadow: 0 20px 60px rgba(0, 0, 0, 0.22); + --ta-glow: 0 0 0 transparent; + + --font-interface-theme: var(--ta-font-ui); + --font-text-theme: var(--ta-font-editor); + --font-monospace-theme: var(--ta-font-code); + --font-ui-small: 12px; + --font-ui-smaller: 11px; + --font-ui-medium: 13px; + --font-ui-large: 15px; + --line-height-normal: 1.7; + --line-height-tight: 1.45; + --icon-color: var(--text-soft); + --icon-color-hover: var(--text-normal); + --icon-color-active: var(--ta-accent); + --icon-color-focused: var(--text-normal); + --icon-opacity: 1; + --icon-opacity-hover: 1; + --icon-opacity-active: 1; + --icon-stroke: 2px; + + --radius-s: calc(var(--ta-ui-radius) - 2px); + --radius-m: var(--ta-ui-radius); + --radius-l: calc(var(--ta-ui-radius) + 2px); + --input-radius: var(--ta-ui-radius); + --tab-radius-active: var(--ta-ui-radius); + --checkbox-radius: 4px; + --checkbox-color: var(--ta-accent); + --checkbox-border-color: var(--background-modifier-border-hover); + + --tag-radius: var(--radius-s); + --tag-border-width: var(--ta-border-width); + --tag-color: var(--ta-accent); + --tag-color-hover: var(--text-on-accent); + --tag-background: color-mix(in srgb, var(--ta-accent) 13%, transparent); + --tag-background-hover: var(--ta-accent); + --tag-border-color: color-mix(in srgb, var(--ta-accent) 28%, transparent); + --tag-border-color-hover: var(--ta-accent); + --tag-size: 0.82em; + --tag-weight: 650; + --tag-padding-x: 0.5em; + --tag-padding-y: 0.12em; + --toggle-radius: 999px; + --toggle-thumb-radius: 999px; + --slider-thumb-radius: 999px; + + --file-line-width: var(--ta-editor-line-width); + --line-width: var(--ta-editor-line-width); + --line-width-adaptive: var(--ta-editor-line-width); +} + +body.theme-dark { + color-scheme: dark; + --accent-h: 150; + --accent-s: 85%; + --accent-l: 67%; + --ta-bg-0: #090c0d; + --ta-bg-1: #0e1214; + --ta-bg-2: #13191c; + --ta-bg-3: #182024; + --ta-bg-4: #202a2f; + --ta-border: #2a363d; + --ta-border-strong: #39484f; + --ta-selection: color-mix(in srgb, var(--ta-accent) 20%, transparent); + --ta-active-line: color-mix(in srgb, var(--ta-accent-alt) 7.5%, transparent); + --ta-text: #dce4df; + --ta-text-soft: #b4c3bd; + --ta-muted: #879994; + --ta-faint: #63736f; + --ta-inverted: #07100d; + --ta-mermaid-node-bg: #102022; + --ta-mermaid-node-border: #35d8c3; + --ta-mermaid-cluster-bg: #0d1618; + --ta-mermaid-edge: #5d746f; + + --background-primary: var(--ta-bg-0); + --background-primary-alt: var(--ta-bg-1); + --background-secondary: var(--ta-bg-1); + --background-secondary-alt: var(--ta-bg-2); + --background-modifier-border: var(--ta-border); + --background-modifier-border-hover: var(--ta-border-strong); + --background-modifier-border-focus: var(--ta-accent); + --background-modifier-hover: rgba(255, 255, 255, 0.045); + --background-modifier-active-hover: color-mix(in srgb, var(--ta-accent) 12%, transparent); + --background-modifier-form-field: var(--ta-bg-1); + --background-modifier-form-field-highlighted: var(--ta-bg-2); + --background-modifier-box-shadow: rgba(0, 0, 0, 0.45); + --background-modifier-success: color-mix(in srgb, var(--ta-accent) 18%, transparent); + --background-modifier-error: color-mix(in srgb, var(--ta-red) 18%, transparent); + --background-modifier-error-hover: color-mix(in srgb, var(--ta-red) 28%, transparent); + + --text-normal: var(--ta-text); + --text-soft: var(--ta-text-soft); + --text-muted: var(--ta-muted); + --text-faint: var(--ta-faint); + --text-on-accent: var(--ta-inverted); + --text-on-accent-inverted: var(--ta-bg-0); + --text-accent: var(--ta-accent); + --text-accent-hover: color-mix(in srgb, var(--ta-accent) 76%, white); + --text-selection: var(--ta-selection); + --text-highlight-bg: color-mix(in srgb, var(--ta-warm) 22%, transparent); + --text-highlight-bg-active: color-mix(in srgb, var(--ta-warm) 32%, transparent); + --text-error: var(--ta-red); + --text-success: var(--ta-accent); + --caret-color: var(--ta-accent); + + --interactive-normal: var(--ta-bg-2); + --interactive-hover: var(--ta-bg-3); + --interactive-accent: var(--ta-accent); + --interactive-accent-hover: color-mix(in srgb, var(--ta-accent) 86%, white); + + --titlebar-background: var(--ta-bg-1); + --titlebar-background-focused: var(--ta-bg-0); + --titlebar-text-color: var(--ta-muted); + --titlebar-text-color-focused: var(--ta-text-soft); + --ribbon-background: var(--ta-bg-1); + --tab-container-background: var(--ta-bg-1); + --tab-background-active: var(--ta-bg-0); + --tab-text-color: var(--ta-muted); + --tab-text-color-focused: var(--ta-text-soft); + --tab-text-color-focused-active: var(--ta-text); + --tab-outline-color: var(--ta-border); + --divider-color: var(--ta-border); + --status-bar-background: var(--ta-bg-1); + --modal-background: var(--ta-bg-1); + --prompt-border-color: var(--ta-border-strong); + + --nav-item-color: var(--ta-muted); + --nav-item-color-hover: var(--ta-text); + --nav-item-color-active: var(--ta-accent); + --nav-item-background-hover: rgba(255, 255, 255, 0.04); + --nav-item-background-active: color-mix(in srgb, var(--ta-accent) 10.5%, transparent); + + --link-color: var(--ta-accent-alt); + --link-color-hover: color-mix(in srgb, var(--ta-accent-alt) 70%, white); + --link-external-color: var(--ta-accent-alt); + --link-external-color-hover: color-mix(in srgb, var(--ta-accent-alt) 70%, white); + --link-unresolved-color: var(--ta-warm); + --link-unresolved-opacity: 0.82; + + --ta-code-header-bg: #0c1113; + --code-background: #0f1517; + --code-normal: var(--ta-text-soft); + --code-comment: #6f807b; + --code-function: var(--ta-accent-alt); + --code-important: var(--ta-red); + --code-keyword: var(--ta-violet); + --code-operator: var(--ta-accent); + --code-property: var(--ta-warm); + --code-punctuation: var(--ta-muted); + --code-string: var(--ta-accent); + --code-tag: var(--ta-red); + --code-value: var(--ta-orange); + + --blockquote-border-color: var(--ta-accent); + --blockquote-background-color: color-mix(in srgb, var(--ta-accent) 7%, transparent); + --table-header-background: var(--ta-bg-2); + --table-row-alt-background: rgba(255, 255, 255, 0.025); + --table-border-color: var(--ta-border); +} + +body.theme-light { + color-scheme: light; + --accent-h: 158; + --accent-s: 100%; + --accent-l: 24%; + --ta-bg-0: #f5f7f4; + --ta-bg-1: #edf2ee; + --ta-bg-2: #e2eae5; + --ta-bg-3: #d6e1db; + --ta-bg-4: #c8d5cf; + --ta-border: #bfcbc5; + --ta-border-strong: #9daea7; + --ta-selection: color-mix(in srgb, var(--ta-accent) 17%, transparent); + --ta-active-line: color-mix(in srgb, var(--ta-accent-alt) 7.5%, transparent); + --ta-text: #17201d; + --ta-text-soft: #34443f; + --ta-muted: #60706a; + --ta-faint: #81918a; + --ta-accent-alt: #006f9e; + --ta-mermaid-node-bg: #ddebe6; + --ta-mermaid-node-border: #007e73; + --ta-mermaid-cluster-bg: #edf4f1; + --ta-mermaid-edge: #6b8078; + --ta-warm: #a46600; + --ta-red: #c8324c; + --ta-orange: #b65800; + --ta-violet: #7357b8; + --ta-inverted: #f9fbf8; + + --background-primary: var(--ta-bg-0); + --background-primary-alt: var(--ta-bg-1); + --background-secondary: var(--ta-bg-1); + --background-secondary-alt: var(--ta-bg-2); + --background-modifier-border: var(--ta-border); + --background-modifier-border-hover: var(--ta-border-strong); + --background-modifier-border-focus: var(--ta-accent); + --background-modifier-hover: rgba(23, 32, 29, 0.055); + --background-modifier-active-hover: color-mix(in srgb, var(--ta-accent) 12%, transparent); + --background-modifier-form-field: #ffffff; + --background-modifier-form-field-highlighted: var(--ta-bg-1); + --background-modifier-box-shadow: rgba(23, 32, 29, 0.18); + --background-modifier-success: color-mix(in srgb, var(--ta-accent) 15%, transparent); + --background-modifier-error: color-mix(in srgb, var(--ta-red) 14%, transparent); + --background-modifier-error-hover: color-mix(in srgb, var(--ta-red) 21%, transparent); + + --text-normal: var(--ta-text); + --text-soft: var(--ta-text-soft); + --text-muted: var(--ta-muted); + --text-faint: var(--ta-faint); + --text-on-accent: var(--ta-inverted); + --text-on-accent-inverted: var(--ta-bg-0); + --text-accent: var(--ta-accent); + --text-accent-hover: #006a43; + --text-selection: var(--ta-selection); + --text-highlight-bg: color-mix(in srgb, var(--ta-warm) 16%, transparent); + --text-highlight-bg-active: color-mix(in srgb, var(--ta-warm) 23%, transparent); + --text-error: var(--ta-red); + --text-success: var(--ta-accent); + --caret-color: var(--ta-accent); + + --interactive-normal: var(--ta-bg-2); + --interactive-hover: var(--ta-bg-3); + --interactive-accent: var(--ta-accent); + --interactive-accent-hover: #00794d; + + --titlebar-background: var(--ta-bg-1); + --titlebar-background-focused: var(--ta-bg-0); + --titlebar-text-color: var(--ta-muted); + --titlebar-text-color-focused: var(--ta-text-soft); + --ribbon-background: var(--ta-bg-1); + --tab-container-background: var(--ta-bg-1); + --tab-background-active: var(--ta-bg-0); + --tab-text-color: var(--ta-muted); + --tab-text-color-focused: var(--ta-text-soft); + --tab-text-color-focused-active: var(--ta-text); + --tab-outline-color: var(--ta-border); + --divider-color: var(--ta-border); + --status-bar-background: var(--ta-bg-1); + --modal-background: var(--ta-bg-0); + --prompt-border-color: var(--ta-border-strong); + + --nav-item-color: var(--ta-muted); + --nav-item-color-hover: var(--ta-text); + --nav-item-color-active: var(--ta-accent); + --nav-item-background-hover: rgba(23, 32, 29, 0.055); + --nav-item-background-active: color-mix(in srgb, var(--ta-accent) 11%, transparent); + + --link-color: var(--ta-accent-alt); + --link-color-hover: #00577b; + --link-external-color: var(--ta-accent-alt); + --link-external-color-hover: #00577b; + --link-unresolved-color: var(--ta-warm); + --link-unresolved-opacity: 0.86; + + --ta-code-header-bg: #d6e1db; + --code-background: #e2eae5; + --code-normal: var(--ta-text-soft); + --code-comment: #75847e; + --code-function: var(--ta-accent-alt); + --code-important: var(--ta-red); + --code-keyword: var(--ta-violet); + --code-operator: var(--ta-accent); + --code-property: var(--ta-warm); + --code-punctuation: var(--ta-muted); + --code-string: var(--ta-accent); + --code-tag: var(--ta-red); + --code-value: var(--ta-orange); + + --blockquote-border-color: var(--ta-accent); + --blockquote-background-color: color-mix(in srgb, var(--ta-accent) 7.5%, transparent); + --table-header-background: var(--ta-bg-2); + --table-row-alt-background: rgba(23, 32, 29, 0.032); + --table-border-color: var(--ta-border); +} + +body.ta-soft-neon.theme-dark { + --ta-glow: 0 0 18px color-mix(in srgb, var(--ta-accent) 28%, transparent); +} + +body.ta-soft-neon.theme-light { + --ta-glow: 0 0 14px color-mix(in srgb, var(--ta-accent) 16%, transparent); +} + +.app-container, +.horizontal-main-container, +.workspace, +.workspace-split.mod-root { + background: var(--background-primary); +} + +.mod-root .workspace-leaf-content, +.workspace-tabs .workspace-leaf { + background: var(--background-primary); +} + +.workspace-split.mod-left-split, +.workspace-split.mod-right-split, +.workspace-ribbon { + background: var(--background-secondary); + border-color: var(--background-modifier-border); +} + +.workspace-ribbon { + border-right: var(--ta-border-width) solid var(--background-modifier-border); +} + +.workspace-ribbon.mod-right { + border-left: var(--ta-border-width) solid var(--background-modifier-border); + border-right: 0; +} + +.side-dock-ribbon-action, +.workspace-ribbon-collapse-btn, +.nav-action-button, +.clickable-icon { + color: var(--text-soft); + border-radius: var(--radius-s); + opacity: 0.96; +} + +.side-dock-ribbon-action:hover, +.workspace-ribbon-collapse-btn:hover, +.nav-action-button:hover, +.clickable-icon:hover { + color: var(--text-normal); + background: var(--background-modifier-hover); + opacity: 1; +} + +.side-dock-ribbon-action.is-active, +.nav-action-button.is-active, +.clickable-icon.is-active { + color: var(--ta-accent); + background: var(--nav-item-background-active); + box-shadow: var(--ta-glow); +} + +/* With the hidden window frame, Obsidian renders .titlebar as a transparent + click-through overlay on top of the tab bar; painting it would hide the + tabs beneath. Only style it when it is a real bar. */ +body:not(.is-hidden-frameless) .titlebar, +body:not(.is-hidden-frameless) .titlebar-inner { + background: var(--titlebar-background); + color: var(--titlebar-text-color); + border-color: var(--background-modifier-border); +} + +body.is-focused:not(.is-hidden-frameless) .titlebar, +body.is-focused:not(.is-hidden-frameless) .titlebar-inner { + background: var(--titlebar-background-focused); + color: var(--titlebar-text-color-focused); +} + +.titlebar-text, +.titlebar-button, +.titlebar-button-container, +.titlebar .clickable-icon { + color: var(--titlebar-text-color-focused); + opacity: 0.98; +} + +.is-focused .titlebar-text, +.is-focused .titlebar-button, +.is-focused .titlebar-button-container, +.is-focused .titlebar .clickable-icon { + color: var(--text-soft); + opacity: 1; +} + +.titlebar-button:hover, +.titlebar .clickable-icon:hover { + color: var(--text-normal); + background: var(--background-modifier-hover); +} + +.titlebar-button.mod-close:hover { + color: var(--ta-red); +} + +.workspace-tab-header-container { + background: var(--tab-container-background); + border-bottom: var(--ta-border-width) solid var(--tab-outline-color); +} + +/* --header-height also sizes the frameless titlebar overlay, view headers, + and the ribbon corner, so set the variable instead of raw heights. */ +body:not(.is-mobile) { + --header-height: 38px; +} + +.workspace-tab-header { + color: var(--tab-text-color); + border-radius: var(--radius-s); + margin: 4px 2px; + min-width: 0; +} + +.workspace-tab-header::before, +.workspace-tab-header::after { + display: none; +} + +.workspace-tab-header-inner { + padding: 0 10px; +} + +.workspace-tab-header-inner-title { + font-family: var(--font-monospace); + font-size: 10.5px; + font-weight: 600; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.workspace-tab-header:hover { + background: var(--background-modifier-hover); + color: var(--tab-text-color-focused); +} + +/* tmux-style solid block for the active main-area tab; scoped to .mod-top + so sidebar tabs keep Obsidian's compact icon styling. */ +.workspace-tabs.mod-top .workspace-tab-header.is-active { + background: var(--ta-bg-3); + color: var(--ta-accent); + box-shadow: var(--ta-glow); +} + +.workspace-tabs.mod-top .workspace-tab-header.is-active .workspace-tab-header-inner-title { + color: var(--ta-accent); +} + +.workspace-tab-container-before, +.workspace-tab-container-after { + background: transparent; +} + +.view-header { + background: var(--background-primary); + border-bottom: var(--ta-border-width) solid var(--background-modifier-border); + color: var(--text-muted); +} + +.view-header-title { + color: var(--text-normal); + font-family: var(--font-monospace); + font-size: 11.5px; + font-weight: 500; + opacity: 1; +} + +.view-header-title-parent, +.view-header-breadcrumb { + font-family: var(--font-monospace); + font-size: 11.5px; + color: var(--text-muted); +} + +.view-header-breadcrumb-separator { + color: var(--text-faint); +} + +.view-header-title-container, +.view-header-nav-buttons .clickable-icon, +.view-actions .clickable-icon, +.view-header .clickable-icon { + color: var(--text-soft); + opacity: 0.98; +} + +.workspace-leaf.mod-active .view-header-title { + color: var(--text-normal); +} + +.view-header:hover .view-header-title, +.view-header-title-container:not(.mod-at-start):before { + color: var(--text-normal); +} + +.view-header .clickable-icon:hover, +.view-header-nav-buttons .clickable-icon:hover, +.view-actions .clickable-icon:hover { + color: var(--text-normal); + opacity: 1; +} + +.status-bar { + background: var(--status-bar-background); + color: var(--text-faint); + border: var(--ta-border-width) solid var(--background-modifier-border); + border-right: 0; + border-bottom: 0; + border-radius: var(--radius-s) 0 0 0; + font-family: var(--font-interface); + font-size: 11px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.025); +} + +.status-bar-item:hover { + color: var(--text-normal); +} + +.nav-header { + padding: 10px 12px 7px; +} + +.nav-buttons-container { + gap: 4px; +} + +.nav-files-container { + padding: 2px 8px 12px; +} + +.workspace-leaf-content[data-type="file-explorer"] .nav-folder-children { + margin-left: 7px; + padding-left: 9px; + border-left: var(--ta-border-width) solid color-mix(in srgb, var(--background-modifier-border) 82%, transparent); +} + +.workspace-leaf-content[data-type="file-explorer"] .nav-folder.mod-root > .nav-folder-children { + margin-left: 0; + padding-left: 0; + border-left: 0; +} + +.tree-item-self, +.nav-file-title, +.nav-folder-title { + color: var(--nav-item-color); + border-radius: var(--radius-s); + min-height: 27px; + margin: 1px 0; + padding-top: 3px; + padding-bottom: 3px; +} + +.tree-item-self:hover, +.nav-file-title:hover, +.nav-folder-title:hover { + color: var(--nav-item-color-hover); + background: var(--nav-item-background-hover); +} + +.tree-item-self.is-active, +.nav-file-title.is-active, +.nav-folder-title.is-active { + color: var(--nav-item-color-active); + background: var(--nav-item-background-active); + box-shadow: inset 2px 0 0 var(--ta-accent); + font-weight: 650; +} + +.nav-file-title-content, +.nav-folder-title-content, +.tree-item-inner { + font-family: var(--font-interface); + font-size: 12.5px; +} + +.nav-folder.mod-root > .nav-folder-title, +.tree-item-self.mod-root { + color: var(--text-faint); + text-transform: uppercase; + letter-spacing: 0.08em; + font-size: 10px; + font-weight: 700; +} + +.workspace-leaf-content[data-type="file-explorer"] .nav-file-tag { + color: var(--ta-warm); + background: transparent; +} + +.search-input-container input, +.prompt-input, +input[type="text"], +input[type="search"], +input[type="email"], +input[type="password"], +textarea { + background: var(--background-modifier-form-field); + color: var(--text-normal); + border: var(--ta-border-width) solid var(--background-modifier-border); + border-radius: var(--input-radius); + box-shadow: none; +} + +.search-input-container input:focus, +.prompt-input:focus, +input[type="text"]:focus, +input[type="search"]:focus, +textarea:focus { + border-color: var(--background-modifier-border-focus); + box-shadow: 0 0 0 2px color-mix(in srgb, var(--ta-accent) 18%, transparent); +} + +button, +.mod-cta { + border-radius: var(--input-radius); + box-shadow: none; +} + +button.mod-cta, +.mod-cta { + background: var(--interactive-accent); + color: var(--text-on-accent); + font-weight: 650; +} + +button.mod-cta:hover, +.mod-cta:hover { + background: var(--interactive-accent-hover); +} + +.menu, +.suggestion-container, +.prompt, +.modal, +.popover, +.popover.hover-popover { + background: var(--modal-background); + border: var(--ta-border-width) solid var(--background-modifier-border); + border-radius: var(--radius-m); + box-shadow: var(--ta-pane-shadow); +} + +.menu-item, +.suggestion-item { + border-radius: var(--radius-s); + color: var(--text-muted); +} + +.menu-item:hover, +.suggestion-item.is-selected { + color: var(--text-normal); + background: var(--nav-item-background-active); +} + +.markdown-source-view.mod-cm6, +.markdown-reading-view, +.markdown-preview-view { + background: var(--background-primary); +} + +.markdown-source-view.mod-cm6 .cm-editor, +.markdown-source-view.mod-cm6 .cm-scroller, +.markdown-preview-view { + font-family: var(--font-text); + color: var(--text-normal); + line-height: var(--line-height-normal); +} + +.markdown-source-view.mod-cm6 .cm-content, +.markdown-preview-view .markdown-preview-sizer { + max-width: var(--file-line-width); +} + +.markdown-source-view.mod-cm6.is-readable-line-width .cm-content, +.markdown-preview-view.is-readable-line-width .markdown-preview-sizer { + max-width: var(--file-line-width); +} + +.markdown-source-view.mod-cm6 .cm-line { + caret-color: var(--caret-color); +} + +.markdown-source-view.mod-cm6 .cm-line.cm-active { + background: linear-gradient(90deg, var(--ta-active-line), transparent 72%); + box-shadow: inset 2px 0 0 color-mix(in srgb, var(--ta-accent-alt) 50%, transparent); +} + +.cm-gutters, +.markdown-source-view.mod-cm6 .cm-gutters { + background: var(--background-primary); + border-right: var(--ta-border-width) solid var(--background-modifier-border); + color: var(--text-faint); +} + +.cm-lineNumbers .cm-gutterElement { + font-family: var(--font-monospace); + font-size: 11px; +} + +.markdown-rendered, +.markdown-source-view.mod-cm6 .cm-line { + font-size: var(--font-text-size); +} + +.markdown-rendered p, +.markdown-rendered ul, +.markdown-rendered ol { + margin-block-start: 0.85em; + margin-block-end: 0.85em; +} + +.inline-title, +.markdown-rendered h1, +.markdown-rendered h2, +.markdown-rendered h3, +.markdown-rendered h4, +.markdown-rendered h5, +.markdown-rendered h6, +.HyperMD-header, +.cm-header { + font-family: var(--font-text); + letter-spacing: 0; +} + +.inline-title { + color: var(--text-normal); + font-size: 2.1em; + font-weight: 760; + line-height: 1.18; + margin-bottom: 0.75em; +} + +.markdown-rendered h1, +.HyperMD-header-1, +.cm-header-1 { + color: var(--text-normal); + font-size: 1.72em; + font-weight: 760; + line-height: 1.22; +} + +.markdown-rendered h2, +.HyperMD-header-2, +.cm-header-2 { + color: var(--ta-accent); + font-size: 1.38em; + font-weight: 740; + line-height: 1.28; +} + +.markdown-rendered h3, +.HyperMD-header-3, +.cm-header-3 { + color: var(--ta-accent-alt); + font-size: 1.16em; + font-weight: 720; +} + +.markdown-rendered h4, +.HyperMD-header-4, +.cm-header-4 { + color: var(--ta-warm); + font-size: 1.04em; + font-weight: 700; +} + +.markdown-rendered h5, +.HyperMD-header-5, +.cm-header-5, +.markdown-rendered h6, +.HyperMD-header-6, +.cm-header-6 { + color: var(--text-muted); + font-size: 0.95em; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.07em; +} + +.cm-formatting-header { + color: var(--text-faint); + font-weight: 500; +} + +.markdown-rendered h1::after, +.markdown-rendered h2::after { + content: ""; + display: block; + height: 1px; + margin-top: 0.38em; + background: linear-gradient(90deg, color-mix(in srgb, currentColor 42%, transparent), transparent); +} + +.markdown-rendered a, +.cm-hmd-internal-link, +.cm-link, +.internal-link, +.external-link { + color: var(--link-color); + text-decoration: none; +} + +.markdown-rendered a:hover, +.internal-link:hover, +.external-link:hover { + color: var(--link-color-hover); + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} + +.markdown-rendered mark, +.cm-highlight { + color: var(--text-normal); + background: var(--text-highlight-bg); + border-radius: 3px; + padding: 0.05em 0.2em; +} + +.markdown-rendered strong, +.cm-strong { + color: var(--text-normal); + font-weight: 760; +} + +.markdown-rendered em, +.cm-em { + color: var(--text-soft, var(--text-normal)); +} + +.markdown-rendered hr { + border: 0; + height: 1px; + background: linear-gradient(90deg, transparent, var(--background-modifier-border), transparent); + margin: 2em 0; +} + +.markdown-rendered blockquote { + border-left: 2px solid var(--blockquote-border-color); + background: var(--blockquote-background-color); + border-radius: 0 var(--radius-s) var(--radius-s) 0; + margin: 1em 0; + padding: 0.7em 1em; + color: var(--text-soft, var(--text-normal)); +} + +.markdown-rendered blockquote p:first-child { + margin-top: 0; +} + +.markdown-rendered blockquote p:last-child { + margin-bottom: 0; +} + +.markdown-rendered blockquote::before { + content: ">"; + color: var(--ta-accent); + font-family: var(--font-monospace); + font-weight: 700; + margin-right: 0.5em; +} + +.markdown-rendered code, +.cm-inline-code { + font-family: var(--font-monospace); + font-size: 0.92em; + color: var(--code-normal); + background: var(--code-background); + border: var(--ta-border-width) solid var(--background-modifier-border); + border-radius: var(--radius-s); + padding: 0.12em 0.34em; +} + +.markdown-rendered pre { + position: relative; + background: var(--code-background); + border: var(--ta-border-width) solid var(--background-modifier-border); + border-radius: var(--radius-m); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035); + padding: 0; + overflow: hidden; +} + +/* Header band; the ">_" glyph is language-neutral because reading view + does not expose the code block language. */ +.markdown-rendered pre::before { + content: ">_"; + display: block; + background: var(--ta-code-header-bg); + border-bottom: var(--ta-border-width) solid color-mix(in srgb, var(--background-modifier-border) 70%, transparent); + padding: 5px 12px; + font-family: var(--font-monospace); + font-size: 9.5px; + font-weight: 700; + letter-spacing: 0.09em; + line-height: 1.5; + color: var(--text-faint); +} + +.markdown-rendered pre code { + display: block; + padding: 0.9em 1.2em 1.1em; + border: 0; + background: transparent; + color: var(--code-normal); + line-height: 1.62; + overflow-x: auto; +} + +.markdown-rendered button.copy-code-button { + margin: 2px 6px; + padding: 3px 8px; + font-family: var(--font-monospace); + font-size: 9.5px; + font-weight: 700; + letter-spacing: 0.09em; + text-transform: uppercase; + color: var(--text-faint); + border-radius: var(--radius-s); +} + +.markdown-rendered button.copy-code-button:hover { + color: var(--ta-accent); + background: var(--background-modifier-hover); +} + +.HyperMD-codeblock, +.cm-line.HyperMD-codeblock { + font-family: var(--font-monospace); + color: var(--code-normal); + background: var(--code-background); + border-left: var(--ta-border-width) solid var(--background-modifier-border); + border-right: var(--ta-border-width) solid var(--background-modifier-border); +} + +.cm-line.HyperMD-codeblock-begin { + background: var(--ta-code-header-bg); + border-top: var(--ta-border-width) solid var(--background-modifier-border); + border-bottom: var(--ta-border-width) solid color-mix(in srgb, var(--background-modifier-border) 70%, transparent); + border-top-left-radius: var(--radius-m); + border-top-right-radius: var(--radius-m); +} + +.cm-line.HyperMD-codeblock-end { + border-bottom: var(--ta-border-width) solid var(--background-modifier-border); + border-bottom-left-radius: var(--radius-m); + border-bottom-right-radius: var(--radius-m); +} + +.markdown-source-view.mod-cm6 .code-block-flair { + font-family: var(--font-monospace); + font-size: 9.5px; + font-weight: 700; + letter-spacing: 0.09em; + text-transform: uppercase; + color: var(--text-muted); +} + +.token.comment { + color: var(--code-comment); +} + +.token.keyword, +.cm-keyword { + color: var(--code-keyword); +} + +.token.string, +.cm-string { + color: var(--code-string); +} + +.token.function, +.cm-def, +.cm-variable-2 { + color: var(--code-function); +} + +.token.property, +.cm-property { + color: var(--code-property); +} + +.token.number, +.cm-number { + color: var(--code-value); +} + +.token.operator, +.cm-operator { + color: var(--code-operator); +} + +.token.punctuation { + color: var(--code-punctuation); +} + +.markdown-rendered table { + border-collapse: separate; + border-spacing: 0; + width: 100%; + margin: 1.25em 0; + overflow: hidden; + border: var(--ta-border-width) solid var(--table-border-color); + border-radius: var(--radius-m); +} + +.markdown-rendered th, +.markdown-rendered td { + border: 0; + border-bottom: var(--ta-border-width) solid var(--table-border-color); + border-right: var(--ta-border-width) solid var(--table-border-color); + padding: 0.62em 0.75em; +} + +.markdown-rendered tr:last-child td { + border-bottom: 0; +} + +.markdown-rendered th:last-child, +.markdown-rendered td:last-child { + border-right: 0; +} + +.markdown-rendered th { + background: var(--table-header-background); + color: var(--text-normal); + font-weight: 720; +} + +.markdown-rendered tr:nth-child(even) td { + background: var(--table-row-alt-background); +} + +.markdown-rendered tbody tr:hover td { + background: color-mix(in srgb, var(--ta-accent-alt) 7%, transparent); +} + +/* Tag shape and color come from the native --tag-* variables (set on body), + which also drive the begin/end hashtag merge in the editor and the + Properties tag pills. Only the font needs a rule. */ +.tag, +.cm-hashtag { + font-family: var(--font-interface); +} + +input[type="checkbox"] { + border-radius: var(--checkbox-radius); + border-color: var(--checkbox-border-color); + background: var(--background-primary-alt); +} + +input[type="checkbox"]:checked { + border-color: var(--checkbox-color); + background: var(--checkbox-color); + box-shadow: 0 0 0 2px color-mix(in srgb, var(--checkbox-color) 14%, transparent); +} + +.task-list-item-checkbox { + margin-inline-end: 0.55em; +} + +.markdown-rendered .task-list-item.is-checked, +.cm-line.HyperMD-task-line[data-task="x"] { + color: var(--text-faint); + text-decoration-color: var(--text-faint); +} + +.markdown-rendered .task-list-item[data-task="-"], +.cm-line.HyperMD-task-line[data-task="-"] { + --checkbox-color: var(--ta-red); + --checkbox-color-hover: var(--ta-red); + --checkbox-border-color: var(--ta-red); + --checkbox-border-color-hover: var(--ta-red); + --checkbox-marker-color: var(--ta-inverted); + color: color-mix(in srgb, var(--ta-red) 72%, var(--text-muted)); + text-decoration: line-through; + text-decoration-thickness: 1px; + text-decoration-color: color-mix(in srgb, var(--ta-red) 68%, transparent); +} + +.markdown-rendered .task-list-item[data-task=">"], +.cm-line.HyperMD-task-line[data-task=">"] { + --checkbox-color: var(--ta-accent-alt); + --checkbox-color-hover: var(--ta-accent-alt); + --checkbox-border-color: var(--ta-accent-alt); + --checkbox-border-color-hover: var(--ta-accent-alt); + --checkbox-marker-color: var(--ta-inverted); + color: var(--ta-accent-alt); +} + +.markdown-rendered .task-list-item[data-task="!"], +.cm-line.HyperMD-task-line[data-task="!"] { + --checkbox-color: var(--ta-warm); + --checkbox-color-hover: var(--ta-warm); + --checkbox-border-color: var(--ta-warm); + --checkbox-border-color-hover: var(--ta-warm); + --checkbox-marker-color: var(--ta-inverted); + color: var(--ta-warm); + font-weight: 700; +} + +.math, +.math-block, +.markdown-rendered .math, +.markdown-rendered .math-block, +.cm-math, +.cm-formatting-math { + color: var(--text-soft); +} + +.markdown-rendered .math-block, +.mjx-container[jax="CHTML"][display="true"] { + background: color-mix(in srgb, var(--ta-accent-alt) 4%, transparent); + border-radius: var(--radius-s); + padding: 0.6em 0.8em; +} + +.mjx-container, +.MathJax { + font-size: 0.98em; +} + +.cm-formatting-math { + color: var(--ta-accent-alt); + opacity: 0.75; +} + +.footnotes { + margin-top: 2.2em; + padding-top: 1em; + border-top: var(--ta-border-width) solid var(--background-modifier-border); + color: var(--text-muted); + font-size: 0.92em; +} + +.footnotes ol, +.markdown-rendered .footnotes ol { + padding-left: 1.45em; +} + +.footnotes li, +.markdown-rendered .footnotes li { + padding-left: 0.25em; + color: var(--text-soft); +} + +.footnotes li::marker, +.markdown-rendered .footnotes li::marker { + color: var(--ta-accent-alt); + font-family: var(--font-monospace); + font-size: 0.84em; +} + +.footnote-ref, +.footnote-link, +.footnote-backref, +.cm-footref, +.cm-hmd-footnote { + color: var(--ta-accent-alt); + font-family: var(--font-monospace); + font-size: 0.84em; + text-decoration: none; +} + +.markdown-rendered sup { + color: var(--ta-accent-alt); + line-height: 0; +} + +.footnote-definition, +.markdown-rendered .footnote-definition { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + align-items: start; + column-gap: 0.7em; + margin: 0.45em 0; + color: var(--text-muted); +} + +.footnote-definition-label, +.markdown-rendered .footnote-definition-label { + color: var(--ta-accent-alt); + background: color-mix(in srgb, var(--ta-accent-alt) 10%, transparent); + border: var(--ta-border-width) solid color-mix(in srgb, var(--ta-accent-alt) 22%, transparent); + border-radius: var(--radius-s); + padding: 0.08em 0.38em; + font-family: var(--font-monospace); + font-size: 0.78em; + line-height: 1.55; +} + +.footnote-definition p, +.markdown-rendered .footnote-definition p { + margin: 0; + color: var(--text-soft); +} + +.cm-comment, +.cm-formatting-comment, +.markdown-source-view.mod-cm6 .cm-comment { + color: color-mix(in srgb, var(--code-comment) 82%, var(--background-primary)); + font-style: normal; +} + +.markdown-embed, +.file-embed { + border: var(--ta-border-width) solid var(--background-modifier-border); + border-radius: var(--radius-m); + background: var(--background-primary-alt); +} + +.markdown-embed-title, +.file-embed-title { + color: var(--ta-accent-alt); + font-family: var(--font-interface); + font-size: 0.86em; + font-weight: 700; +} + +.markdown-embed-link, +.file-embed-link { + color: var(--ta-accent); +} + +.embed-error { + color: var(--text-muted); + background: var(--background-primary-alt); + border: var(--ta-border-width) dashed var(--background-modifier-border); + border-radius: var(--radius-m); + font-family: var(--font-monospace); +} + +.mermaid { + display: flex; + justify-content: center; + margin: 1.2em 0; + padding: 1em; + border: var(--ta-border-width) solid var(--background-modifier-border); + border-radius: var(--radius-m); + background: color-mix(in srgb, var(--ta-accent-alt) 4%, var(--background-primary)); +} + +.mermaid svg { + max-width: 100%; + height: auto; +} + +/* In dark mode Obsidian pixel-inverts Mermaid SVGs (invert + hue-rotate), + which would flip the palette below. Disable the filter only for diagram + types this theme fully restyles; pie, gantt, and other types keep the + invert treatment that makes their stock colors dark-friendly. */ +body.theme-dark .mermaid > svg:is( + [aria-roledescription="flowchart-v2"], + [aria-roledescription="flowchart"], + [aria-roledescription="stateDiagram"], + [aria-roledescription="stateDiagram-v2"], + [aria-roledescription="class"], + [aria-roledescription="classDiagram"], + [aria-roledescription="sequence"]) { + filter: none; +} + +/* Readability net for diagram text this theme does not explicitly style, + in the unfiltered diagram types above. */ +body.theme-dark .mermaid > svg:is( + [aria-roledescription="flowchart-v2"], + [aria-roledescription="flowchart"], + [aria-roledescription="stateDiagram"], + [aria-roledescription="stateDiagram-v2"], + [aria-roledescription="class"], + [aria-roledescription="classDiagram"], + [aria-roledescription="sequence"]) text { + fill: var(--text-normal); +} + +/* Mermaid injects a per-diagram