@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@import "@fontsource-variable/inter";
@import "./code-highlight.css";

/* Bundled Nerd Font for the terminal. Ensures oh-my-zsh / Powerlevel10k /
 * Starship glyphs render out of the box even when the host OS has no Nerd
 * Font installed. `swap` so the prompt isn't blank during the ~100ms it
 * takes the woff2 to land - xterm refits when the family resolves. */
@font-face {
  font-family: "JetBrainsMono Nerd Font Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/JetBrainsMonoNerdFontMono-Regular.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrainsMono Nerd Font Mono";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/JetBrainsMonoNerdFontMono-Bold.woff2") format("woff2");
}

@source "../../node_modules/streamdown/dist/index.js";

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@custom-variant dark (&:is(.dark *));

@theme inline {
  --font-heading: var(--font-sans);
  --font-sans: "Inter Variable", sans-serif;
  --color-sidebar-ring: var(--sidebar-ring);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar: var(--sidebar);
  --color-chart-5: var(--chart-5);
  --color-chart-4: var(--chart-4);
  --color-chart-3: var(--chart-3);
  --color-chart-2: var(--chart-2);
  --color-chart-1: var(--chart-1);
  --color-ring: var(--ring);
  --color-input: var(--input);
  --color-border: var(--border);
  --color-destructive: var(--destructive);
  --color-accent-foreground: var(--accent-foreground);
  --color-accent: var(--accent);
  --color-muted-foreground: var(--muted-foreground);
  --color-muted: var(--muted);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-secondary: var(--secondary);
  --color-primary-foreground: var(--primary-foreground);
  --color-primary: var(--primary);
  --color-popover-foreground: var(--popover-foreground);
  --color-popover: var(--popover);
  --color-card-foreground: var(--card-foreground);
  --color-card: var(--card);
  --color-foreground: var(--foreground);
  --color-background: var(--background);
  --color-diff-added: var(--tedi-diff-added);
  --color-diff-removed: var(--tedi-diff-removed);
  --color-info: var(--tedi-info);
  --color-icon-working: var(--tedi-icon-working);
  --color-icon-idle: var(--tedi-icon-idle);
  --color-icon-blocked: var(--tedi-icon-blocked);
  /* Smooth "breathing" pulse for the active AI CLI (working / blocking) icon.
   * Gentler and more continuous than Tailwind's default animate-pulse. */
  --animate-ai-breathe: ai-breathe 1.8s ease-in-out infinite;
  --radius-sm: 0px;
  --radius-md: 0px;
  --radius-lg: 0px;
  --radius-xl: 0px;
  --radius-2xl: 0px;
  --radius-3xl: 0px;
  --radius-4xl: 0px;
}

/* Gentle opacity breathe for the active AI CLI icon. Defined at top level so it
 * is always available to the `--animate-ai-breathe` utility. Honors
 * prefers-reduced-motion via the global reset above. */
@keyframes ai-breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}

:root {
  /* AI CLI status colors. Themable via Settings > Theme. Defaults match the
   * pre-existing emerald/yellow/red pill the codebase shipped with so the
   * out-of-box look is unchanged. */
  --tedi-icon-idle: #059669;
  --tedi-icon-working: #ca8a04;
  --tedi-icon-blocked: #dc2626;
  /* Semantic diff colors (git +/-, SCM status). Themable. Kept distinct
   * from --destructive so destructive remains an actionable-danger token
   * and diff removed stays a "kind of change" indicator. */
  --tedi-diff-added: #16a34a;
  --tedi-diff-removed: #dc2626;
  /* Semantic "info" / neutral status color (toasts, renamed/copied SCM
   * rows, SSH info pills). Themable. */
  --tedi-info: #0284c7;
  /* Solid base colour for the terminal/editor canvas and the glass surface
   * tint. `customTheme.applyBackground` sets it to the theme's background
   * colour; the glass layer mixes it with `--tedi-app-opacity`. */
  --tedi-canvas-bg: #ffffff;
  /* Whole-app transparency (0..1). 1 = solid (default), 0 = fully see-through.
   * The single opacity control: `appOpacity.ts` writes it + toggles
   * `data-tedi-glass`, consumed by the `html[data-tedi-glass="on"]` rules and
   * the terminal canvas. */
  --tedi-app-opacity: 1;
  /* Tab focus / active stripe color per tab kind. Themable via Settings
   * > Theme. Defaults mirror the hard-coded palette `TabBar.tsx` used
   * before the tokens existed. */
  --tedi-tab-terminal: #10b981;
  --tedi-tab-ssh: #0ea5e9;
  --tedi-tab-editor: #0057fe;
  --tedi-tab-preview: #06b6d4;
  --tedi-tab-ai-diff: #8b5cf6;
  --tedi-tab-git-diff: #f59e0b;
  /* Drag-to-resize divider between split panes. Themable via Settings. */
  --tedi-resize-handle: #e5e7eb;
  /* ANSI 16 palette for the terminal. Themable per preset. Light-mode
   * defaults are slightly muted; dark variants below brighten them. */
  --tedi-ansi-black: #3f3f46;
  --tedi-ansi-red: #dc2626;
  --tedi-ansi-green: #16a34a;
  --tedi-ansi-yellow: #ca8a04;
  --tedi-ansi-blue: #2563eb;
  --tedi-ansi-magenta: #9333ea;
  --tedi-ansi-cyan: #0891b2;
  --tedi-ansi-white: #e4e4e7;
  --tedi-ansi-bright-black: #71717a;
  --tedi-ansi-bright-red: #ef4444;
  --tedi-ansi-bright-green: #22c55e;
  --tedi-ansi-bright-yellow: #eab308;
  --tedi-ansi-bright-blue: #3b82f6;
  --tedi-ansi-bright-magenta: #a855f7;
  --tedi-ansi-bright-cyan: #06b6d4;
  --tedi-ansi-bright-white: #fafafa;
  --background: oklch(1 0 0);
  --foreground: oklch(0.148 0.004 228.8);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.148 0.004 228.8);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.148 0.004 228.8);
  --primary: #0057fe;
  --primary-foreground: #ffffff;
  --secondary: oklch(0.963 0.002 197.1);
  --secondary-foreground: oklch(0.218 0.008 223.9);
  --muted: oklch(0.963 0.002 197.1);
  --muted-foreground: oklch(0.56 0.021 213.5);
  --accent: #dbe5ff;
  --accent-foreground: oklch(0.218 0.008 223.9);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.925 0.005 214.3);
  --input: oklch(0.925 0.005 214.3);
  --ring: #0057fe;
  --chart-1: oklch(0.872 0.007 219.6);
  --chart-2: oklch(0.56 0.021 213.5);
  --chart-3: oklch(0.45 0.017 213.2);
  --chart-4: oklch(0.378 0.015 216);
  --chart-5: oklch(0.275 0.011 216.9);
  --radius: 0px;
  --sidebar: oklch(0.987 0.002 197.1);
  --sidebar-foreground: oklch(0.148 0.004 228.8);
  --sidebar-primary: #0057fe;
  --sidebar-primary-foreground: #ffffff;
  --sidebar-accent: #dbe5ff;
  --sidebar-accent-foreground: oklch(0.218 0.008 223.9);
  --sidebar-border: oklch(0.925 0.005 214.3);
  --sidebar-ring: #0057fe;
}

/* VSCode Dark+ (Default Dark Modern) palette, re-tinted to the TEDI logo blue.
 * Editor bg #1E1E1E, sidebar/activity-bar #181818, panel border #2B2B2B,
 * focus/brand #0057FE (logo blue), fg #CCCCCC. Hex kept as-is (sRGB) so the
 * result matches VSCode's pixel feel rather than drifting through OKLCH. */
.dark {
  /* Brighter defaults for the AI CLI status icons under dark mode. */
  --tedi-icon-idle: #34d399;
  --tedi-icon-working: #facc15;
  --tedi-icon-blocked: #f87171;
  /* Brighter diff + info colors for dark mode. */
  --tedi-diff-added: #4ade80;
  --tedi-diff-removed: #f87171;
  --tedi-info: #38bdf8;
  /* Dark base for the terminal/editor canvas. */
  --tedi-canvas-bg: #1e1e1e;
  /* Slightly brighter tab stripes for dark mode. */
  --tedi-tab-terminal: #34d399;
  --tedi-tab-ssh: #38bdf8;
  --tedi-tab-editor: #5b8bff;
  --tedi-tab-preview: #22d3ee;
  --tedi-tab-ai-diff: #a78bfa;
  --tedi-tab-git-diff: #fbbf24;
  --tedi-resize-handle: #2b2b2b;
  /* Brighter ANSI palette for dark mode (matches the previous hardcoded
   * Tailwind defaults the codebase shipped with). */
  --tedi-ansi-black: #18181b;
  --tedi-ansi-red: #ef4444;
  --tedi-ansi-green: #22c55e;
  --tedi-ansi-yellow: #eab308;
  --tedi-ansi-blue: #3b82f6;
  --tedi-ansi-magenta: #a855f7;
  --tedi-ansi-cyan: #06b6d4;
  --tedi-ansi-white: #e4e4e7;
  --tedi-ansi-bright-black: #52525b;
  --tedi-ansi-bright-red: #f87171;
  --tedi-ansi-bright-green: #4ade80;
  --tedi-ansi-bright-yellow: #facc15;
  --tedi-ansi-bright-blue: #60a5fa;
  --tedi-ansi-bright-magenta: #c084fc;
  --tedi-ansi-bright-cyan: #22d3ee;
  --tedi-ansi-bright-white: #fafafa;
  --background: #1e1e1e;
  --foreground: #cccccc;
  --card: #1f1f1f;
  --card-foreground: #cccccc;
  --popover: #1f1f1f;
  --popover-foreground: #cccccc;
  --primary: #0057fe;
  --primary-foreground: #ffffff;
  --secondary: #2a2d2e;
  --secondary-foreground: #cccccc;
  --muted: #252526;
  --muted-foreground: #9d9d9d;
  --accent: #0a2870;
  --accent-foreground: #ffffff;
  --destructive: #f14c4c;
  --border: #2b2b2b;
  --input: #313131;
  --ring: #0057fe;
  --chart-1: #5a8aff;
  --chart-2: #c586c0;
  --chart-3: #dcdcaa;
  --chart-4: #9cdcfe;
  --chart-5: #ce9178;
  --sidebar: #181818;
  --sidebar-foreground: #cccccc;
  --sidebar-primary: #0057fe;
  --sidebar-primary-foreground: #ffffff;
  --sidebar-accent: #2a2d2e;
  --sidebar-accent-foreground: #ffffff;
  --sidebar-border: #2b2b2b;
  --sidebar-ring: #0057fe;
}

@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
    margin: 0;
    overflow: hidden;
  }
  html,
  body,
  #root {
    height: 100%;
  }
  html {
    @apply font-sans;
  }

  /* Squarify everything globally - Tailwind's `rounded` (no suffix) and
   * `rounded-full` use literal values not derived from --radius-*, so the
   * @theme overrides above don't reach them. Force-zero every border-radius
   * to guarantee a fully boxed UI. */
  *,
  *::before,
  *::after {
    border-radius: 0 !important;
  }

  /* Default pointer for every interactive button. The shadcn `<Button>`
   * component already declares `cursor-pointer` in its cva base, but the
   * codebase also uses raw `<button>` elements (tabs, statusbar pills,
   * close buttons, etc.) - giving them a pointer here keeps the feel
   * consistent without having to remember the utility class at each call
   * site. Disabled buttons opt out so they read as inactive. */
  button:not(:disabled),
  [role="button"]:not([aria-disabled="true"]) {
    cursor: pointer;
  }

  /* Kill the webview's native image-drag gesture. Icons (favicons, file-type
   * glyphs) are <img> elements, draggable by default; grabbing a tab or pane
   * over one hijacks our pointer-based (dnd-kit) drag and shows an ugly native
   * favicon thumbnail - which even ignores the squarify rule above - instead
   * of the custom icon+label drag overlay. Disable it everywhere so dnd-kit
   * owns every drag. */
  img {
    -webkit-user-drag: none;
    user-select: none;
  }
}

/* Editor + terminal canvas transparency under the single "App opacity"
 * glass mode (`data-tedi-glass`). Only `.cm-editor` carries the alpha tint;
 * inner scrollers, content, and gutters go fully transparent so the layers
 * don't stack. The `@uiw` themes set `.cm-editor` background via a class with
 * specificity (0,2,0); this selector is (0,2,1) and `!important` wins. */
html[data-tedi-glass="on"] .cm-editor {
  background-color: color-mix(
    in srgb,
    var(--tedi-canvas-bg) calc(var(--tedi-app-opacity) * 100%),
    transparent
  ) !important;
}
html[data-tedi-glass="on"] .cm-scroller,
html[data-tedi-glass="on"] .cm-content,
html[data-tedi-glass="on"] .cm-gutters {
  background-color: transparent !important;
}
html[data-tedi-glass="on"] .cm-activeLine,
html[data-tedi-glass="on"] .cm-activeLineGutter {
  background-color: color-mix(in srgb, var(--tedi-canvas-bg) 18%, transparent) !important;
}
/* xterm WebGL renderer needs `allowTransparency: true` (set in
 * `useTerminalSession.ts`) so the canvas itself accepts an rgba clear
 * color. The DOM wrappers around the canvas go fully transparent; the
 * actual tint is computed in `buildTerminalTheme()` and passed as
 * `theme.background = rgba(...)`. */
html[data-tedi-glass="on"] .xterm,
html[data-tedi-glass="on"] .xterm .xterm-screen,
html[data-tedi-glass="on"] .xterm .xterm-viewport {
  background-color: transparent !important;
}

/* Custom window chrome (Linux/Windows): the OS gives us a transparent
 * borderless window, and we paint the rounded corners + border + shadow
 * ourselves so the app doesn't look naked on GNOME/KDE/Hyprland. */
html[data-chrome="borderless"],
html[data-chrome="borderless"] body {
  background: transparent !important;
}
html[data-chrome="borderless"] #root,
html[data-chrome="borderless"] #settings-root {
  height: 100%;
  border-radius: 0;
  overflow: hidden;
  /* `outline` + negative offset instead of `border`: WebView2 on Windows with
   * `transparent: true` + `decorations: false` drops the rightmost physical
   * pixel after a horizontal resize, so a real 1px border at the edge goes
   * missing. Outline doesn't take layout space (no box-sizing math) and
   * `outline-offset: -1px` paints it one pixel inside the element box, so
   * the visible line sits at [W-2, W-1] and survives the edge clipping. */
  outline: 1px solid var(--border);
  outline-offset: -1px;
  background: var(--background);
}

/* Settings window reads as a modal floating over the main app, so it gets
 * the brand `--primary` accent outline + rounded corners. `overflow: hidden`
 * inherited from the rule above clips header/main children to the curve,
 * so the inner React root does NOT need its own border/rounded classes. */
html[data-chrome="borderless"] #settings-root {
  outline-color: var(--primary);
  border-radius: 0.5rem;
}

/* ===== App transparency (single "App opacity" control) =====
 *
 * The OS window is already transparent (src-tauri/src/lib.rs builds it with
 * `transparent: true`); the app only looks solid because surfaces paint
 * opaque colours. When the Theme → Background "Opacity" slider lowers
 * `--tedi-app-opacity` below 1, `appOpacity.ts` sets `data-tedi-glass="on"`
 * and we fade surfaces toward whatever sits behind the window: the wallpaper
 * image when one is set, else the desktop. That covers the shell, sidebar,
 * header, tabs, status bar, panels, popovers / dropdowns / menus, the editor's
 * find panel, and the editor / terminal canvases — plus extensions (e.g. SQL
 * Explorer) since they paint with these same tokens.
 *
 * LEGIBILITY: only the content canvas (`--background`, the editor `.cm-editor`
 * tint, and the terminal rgba) follows the slider all the way to fully
 * transparent. Every text/icon-bearing chrome surface is FLOORED so it never
 * drops below a readable backing: cards/sidebar/secondary/muted ride
 * `--tedi-glass-surface` (0.5..1), the header rides `--tedi-glass-header`
 * (0.5..1), and floating menus ride `--tedi-glass-menu` (0.82..1). So text,
 * icons, and buttons stay clearly visible at any opacity.
 *
 * `!important` beats the inline `--background` / `--card` a custom theme sets
 * on `<html>`. Left solid on purpose: text/borders (legibility), `--accent` /
 * `--sidebar-accent` (active tab, selected rows, terminal selection), and
 * `--primary` / `--destructive` (buttons stay crisp). Main window only; the
 * settings window opts out for readability (see `appOpacity.ts`). */
html[data-tedi-glass="on"] {
  /* Text- and icon-bearing chrome (cards, sidebar, secondary, muted) keeps a
   * legibility FLOOR so labels, icons, and buttons stay clearly visible over
   * the wallpaper even at the low end of the slider. The 0..1 slider maps to
   * 0.5..1 alpha here (an "acrylic/vibrancy"-style tint, ~the same floor the
   * header uses); the canvas itself (--background, editor/terminal) still goes
   * fully see-through below, so the "dissolve into the wallpaper" look is
   * preserved for the content panes while chrome never becomes unreadable. */
  --tedi-glass-surface: color-mix(
    in srgb,
    var(--tedi-canvas-bg) calc((var(--tedi-app-opacity) * 0.5 + 0.5) * 100%),
    transparent
  );
  /* Header is the drag handle: a slightly stronger floor (alpha maps 0..1 ->
   * 0.5..1) so the top bar stays clearly grabbable, while still fading. */
  --tedi-glass-header: color-mix(
    in srgb,
    var(--tedi-canvas-bg) calc((var(--tedi-app-opacity) * 0.5 + 0.5) * 100%),
    transparent
  );
  /* Floating menus (dropdowns, context menus, popovers, tooltips, command
   * palette) carry the densest small text and have NO scrim/backdrop (blur is
   * banned on Windows/WebView2, see note below), so they get the strongest
   * floor (alpha maps 0..1 -> 0.82..1). They still fade with the slider but
   * never below a clearly readable level. */
  --tedi-glass-menu: color-mix(
    in srgb,
    var(--tedi-canvas-bg) calc((var(--tedi-app-opacity) * 0.18 + 0.82) * 100%),
    transparent
  );
  /* The app canvas (shell, pane gaps, editor/terminal frames) follows the
   * slider DIRECTLY instead of snapping to fully transparent the moment glass
   * turns on. Same formula as the editor canvas (.cm-editor) below, so a 98%
   * slide reads as ~98% opaque and only the low end dissolves toward the
   * wallpaper. Chrome stays floored separately via --tedi-glass-surface, so it
   * is always at least as opaque as the canvas. */
  --background: color-mix(
    in srgb,
    var(--tedi-canvas-bg) calc(var(--tedi-app-opacity) * 100%),
    transparent
  ) !important;
  /* Panels keep a floored translucent backing (see --tedi-glass-surface) so
   * chrome and the editor/terminal text stay readable while still showing
   * what's behind. Floating menus ride the stronger --tedi-glass-menu floor.
   * The editor (.cm-editor) and terminal canvas use the raw --tedi-app-opacity
   * for their own rgba tint (see rules above + JS). */
  --card: var(--tedi-glass-surface) !important;
  --popover: var(--tedi-glass-menu) !important;
  --secondary: var(--tedi-glass-surface) !important;
  --muted: var(--tedi-glass-surface) !important;
  --sidebar: var(--tedi-glass-surface) !important;
}
/* High-traffic main-window panels that paint with a FRACTIONAL utility
 * (e.g. `bg-card/60`) would multiply a second alpha on top of the already
 * floored --card, washing their text/icons out faster than the slider value.
 * Pin them to the full floored surface under glass so the slider is the single
 * source of truth. Solid (non-glass) themes keep their original fractional
 * tint because this rule is gated on the glass attribute. */
html[data-tedi-glass="on"] .tedi-glass-panel {
  background-color: var(--tedi-glass-surface) !important;
}
/* Top header bar: more opaque than the rest (still follows the slider) so it
 * reads as a solid title/drag bar. `bg-card` makes it inherit the translucent
 * `--card` above, so override it back to the boosted header tint. */
html[data-tedi-glass="on"] [data-tedi-header] {
  background-color: var(--tedi-glass-header) !important;
}
/* Bottom status bar (the only `<footer>` in the app shell): it paints
 * `bg-card/60`, which under glass would multiply a 0.6 alpha on top of the
 * already floored `--card`, fading its cwd / git / zoom / AI text far faster
 * than the slider implies. Pin it to the floored header tint so it reads as a
 * solid-enough bar like the header, never below a readable floor. */
html[data-tedi-glass="on"] footer {
  background-color: var(--tedi-glass-header) !important;
}

/* SQL Explorer (first-party extension) renders into a `.tsql-host` container
 * whose BASE paints `--background`, the same token we force fully transparent
 * under glass for the editor/terminal canvas. That made the WHOLE panel (schema
 * tree, grid rows, query box, gaps) dissolve into the wallpaper instead of
 * staying a readable surface like the file-tree sidebar does. Floor the host to
 * the chrome surface (`--tedi-glass-surface`, the same 0.5..1 floor that
 * cards/sidebar ride) so the tool stays translucent but legible: data + tree
 * keep a readable backing while the panel still shows the wallpaper through it.
 * The chrome bars below ride `--card` (also floored) and stack on top for the
 * usual header/body depth. */
html[data-tedi-glass="on"] .tsql-host {
  background: var(--tedi-glass-surface) !important;
}
/* SQL Explorer's STICKY bars (table header, result toolbar, schema-tree head)
 * paint `--card`; under glass that lets the rows / tree scrolling beneath them
 * bleed through. Pin those sticky bars to the SOLID canvas colour so they read
 * as clean header bars (the rows/tree themselves stay glass). The hover tint
 * mixes against the same solid. Non-sticky SQL surfaces keep translucent `--card`. */
html[data-tedi-glass="on"] .tsql-grid thead th,
html[data-tedi-glass="on"] .tsql-meta--sticky,
html[data-tedi-glass="on"] .tsql-tree-head {
  background: var(--tedi-canvas-bg) !important;
}
html[data-tedi-glass="on"] .tsql-grid thead th.tsql-grid-th:hover {
  background: color-mix(in srgb, var(--foreground) 6%, var(--tedi-canvas-bg)) !important;
}
/* The floating connection-form modal also hard-codes the `--background` canvas,
 * so under glass it went fully see-through while floating OVER the tree/grid,
 * colliding the form fields with the rows behind it. Floor it to the
 * floating-menu surface (`--popover`, same as `.tsql-dialog`) so the form that
 * the user has to read and type into stays legible. */
html[data-tedi-glass="on"] .tsql-conn-modal {
  background: var(--popover) !important;
}
/* The conversation "jump to message" pin is sticky over the scrolling message
 * list. Its `bg-background` dissolves under glass at the low end of the slider
 * (`--background` tracks the opacity), letting messages bleed through it. Unlike the
 * header (which only sits over the wallpaper), this pin sits over scrolling
 * message TEXT, so a floored-but-translucent tint still lets text collide
 * through it. Pin it to the SOLID canvas colour (same as the SQL sticky bars
 * above) so the jump label is always readable; drop its backdrop blur (dark
 * fill on Windows). It is a single sticky row, so solid costs no transparency
 * the user cares about. */
html[data-tedi-glass="on"] .tedi-chat-pin {
  background-color: var(--tedi-canvas-bg) !important;
  backdrop-filter: none !important;
}
/* No `backdrop-filter` under glass: over a transparent window WebView2
 * (Windows) renders the blurred backdrop as an opaque dark fill, which made
 * floating chrome look black instead of see-through. Strip it from EVERY
 * element while glass is on so nothing (find panel, composer/mention/snippet
 * pickers, scheduler pill, scroll-to-bottom button, drag ghosts, plan-review
 * overlay, modal scrims) can reintroduce the artifact. Components still request
 * `backdrop-blur` for the solid-window case; this only fires when the window is
 * see-through. The frosted-glass look instead comes from the wallpaper's own
 * "Blur" slider (it blurs the image layer directly), so the transparency stays
 * clean and predictable on every platform. Scrims keep their dark tint (just
 * without the blur), which still dims fine. */
html[data-tedi-glass="on"] *,
html[data-tedi-glass="on"] *::before,
html[data-tedi-glass="on"] *::after {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* ===== Unified scrollbar style =====
 *
 * Every native scrollbar in the app - editor, settings, dialogs, dropdowns,
 * chat panels, terminal, file tree, anywhere `overflow:auto|scroll` is set -
 * uses the same 10px boxy appearance: `--border` thumb, `--muted-foreground`
 * on hover, transparent track, no border-radius. Applied via webkit pseudo-
 * elements on Linux/Windows (borderless chrome). macOS keeps its native
 * overlay scrollbar so the OS feel is preserved.
 *
 * IMPORTANT - do NOT set `scrollbar-width` or `scrollbar-color` on `*`.
 * In Chromium (Tauri WebView2), once either property is non-initial the
 * engine switches to the modern CSS scrollbar UI and IGNORES every
 * `::-webkit-scrollbar-*` rule below. The earlier "hide on borderless"
 * approach via `scrollbar-width: none` on `*` is exactly what made the
 * editor's scrollbars vanish - keeping those properties untouched here
 * is what lets the rest of these rules actually take effect.
 *
 * Opt out per-region with `.no-scrollbar` (single element) or
 * `.no-scrollbar-deep` (cascades to descendants). The Radix `<ScrollArea>`
 * primitive renders its own custom thumb on top of an `overflow:scroll`
 * viewport; the override at the bottom of this section keeps that
 * viewport's native bar hidden so we don't get double scrollbars.
 */
html[data-chrome="borderless"] *::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
html[data-chrome="borderless"] *::-webkit-scrollbar-track {
  background: transparent;
}
html[data-chrome="borderless"] *::-webkit-scrollbar-thumb {
  background: var(--border);
  border: 0;
  background-clip: padding-box;
}
html[data-chrome="borderless"] *::-webkit-scrollbar-thumb:hover {
  background: var(--muted-foreground);
  background-clip: padding-box;
}
html[data-chrome="borderless"] *::-webkit-scrollbar-corner {
  background: transparent;
}

/* Radix ScrollArea: viewport already gets `overflow:scroll` from the
 * primitive and a custom thumb is rendered on top. The global rule above
 * wins on specificity, so without these overrides every Radix scroll area
 * would show TWO scrollbars (native + custom).
 *
 * Both axes are belt-and-braces: `scrollbar-width: none` hides the native
 * bar under the modern CSS scrollbar UI that WebView2 falls back to in
 * some HiDPI/zoom states (where `::-webkit-scrollbar { display: none }`
 * is silently ignored), and the webkit rule covers the legacy path. We
 * scope `scrollbar-width` to this single element so it does NOT trip the
 * "switches the engine to modern UI globally" footgun described above. */
[data-radix-scroll-area-viewport] {
  scrollbar-width: none !important;
}
[data-radix-scroll-area-viewport]::-webkit-scrollbar {
  display: none !important;
  width: 0 !important;
  height: 0 !important;
}

/* Radix wraps Viewport children in an inner `<div style="display:table;
 * min-width:100%">`. With `display:table`, the wrapper shrinks-to-fit
 * its widest descendant, so long unbreakable content (paths, hit lines)
 * pushes it wider than the viewport and triggers horizontal scroll -
 * which breaks `truncate` and `break-all` on inner rows. Every
 * ScrollArea in this app is a vertical-only list, so coerce the wrapper
 * to a block that respects the viewport's width and lets children
 * truncate/wrap normally. */
[data-radix-scroll-area-viewport] > div {
  display: block !important;
  width: 100% !important;
  min-width: 0 !important;
}

/* `react-resizable-panels` wraps every Panel's children in an internal
 * <div style="overflow: auto"> (so consumers don't have to think about
 * runaway content). In this app every panel handles its own scroll via
 * an inner Radix `<ScrollArea>`, so that wrapper's `overflow:auto` is
 * dead weight — but sub-pixel rounding at scroll extremes (e.g. when
 * the file explorer is scrolled to the bottom) gives the wrapper a
 * 1-2px overflow and it paints a native scrollbar right next to the
 * Radix custom one. Result: a phantom second scrollbar. The selector
 * targets the panel's immediate child (the library always renders
 * exactly one wrapper there) and uses `!important` to beat the inline
 * style. */
[data-slot="resizable-panel"] > div {
  overflow: hidden !important;
}

/* xterm renders its own canvas-based scrollbar via add-ons; we only need to
 * clean up the focus outline on the host element. */
.xterm,
.xterm-screen,
.xterm:focus,
.xterm.focus {
  outline: none !important;
}

/* @codemirror/merge's default architecture is "outer .cm-mergeView scrolls
 * vertically; each .cm-editor has height: auto so both panes render their
 * full content and stay in sync naturally." Side effect: horizontal scroll
 * lives on .cm-scroller, whose height grows with content, so the per-pane
 * horizontal scrollbar always sits at the BOTTOM of the document (= below
 * the viewport for any file longer than the visible area). Users never see
 * it.
 *
 * Fix: flip to per-pane scrolling. Force each .cm-editor to fill its flex
 * cell, give each .cm-scroller `overflow: auto` on both axes, and disable
 * the outer vertical scroll. Vertical sync between the two panes is
 * reattached imperatively in GitDiffPane (the merge package doesn't sync
 * scrollTop itself — its design relied on a single outer scroll container).
 *
 * .cm-mergeViewEditors / .cm-mergeViewEditor are the package's own
 * wrappers (see node_modules/@codemirror/merge/.../index.js); we need them
 * to be `min-height: 0` so flex children can actually shrink. */
.cm-mergeView {
  height: 100% !important;
  overflow: hidden !important;
  display: flex !important;
  flex-direction: column !important;
}
.cm-mergeView .cm-mergeViewEditors {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
}
.cm-mergeView .cm-mergeViewEditor {
  min-height: 0;
  min-width: 0;
  /* Anchor for the absolutely-positioned .diff-ruler (overview ruler that
   * shows added/removed line ticks next to the native scrollbar). */
  position: relative;
}
.cm-mergeView .cm-editor {
  height: 100% !important;
  min-height: 0 !important;
}
.cm-mergeView .cm-scroller {
  overflow: auto !important;
}

/* Visible 1px divider between the two MergeView panes so the HEAD side and
 * the Working-tree side are clearly distinct. CodeMirror merge tags the
 * right-hand editor with `.cm-merge-b`; a left border there draws the line
 * without interfering with the package's own layout/scroll wiring. */
.cm-mergeView .cm-merge-b {
  border-left: 1px solid var(--border);
}

/* Overview ruler — VSCode-style scrollbar annotations for GitDiffPane.
 * The ruler is laid right on top of the native scrollbar track (right: 0)
 * and sized in JS to match the scrollbar's width; the thumb floats above
 * the ticks the same way it does in VSCode. Container is pointer-events:
 * none so dragging the scrollbar thumb keeps working; .diff-ruler-mark
 * children opt back into pointer events to remain clickable for jump-to-
 * line. z-index sits below the scrollbar thumb (which the browser paints
 * at its own native layer) but above .cm-content. */
.diff-ruler {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  pointer-events: none;
  z-index: 4;
}
.diff-ruler-mark {
  position: absolute;
  right: 0;
  width: 100%;
  pointer-events: auto;
  cursor: pointer;
  opacity: 0.85;
  border-radius: 1px;
  /* Reset browser <button> chrome — the element is a button now (so it
   * gets styled tooltip + keyboard focus) but the visual is the colored
   * tick, not a button surface. */
  padding: 0;
  border: 0;
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  color: inherit;
  transition: opacity 80ms ease;
}
.diff-ruler-mark:hover,
.diff-ruler-mark:focus-visible {
  opacity: 1;
  outline: none;
}
.diff-ruler-added {
  background: var(--tedi-diff-added);
}
.diff-ruler-removed {
  background: var(--tedi-diff-removed);
}

/* ===== Opt-out classes =====
 * `.no-scrollbar` hides the scrollbar on a single element; the deep variant
 * cascades to every descendant. Both win against the global webkit rules
 * above via `!important`. Used for command palettes / dropdowns where a
 * visible scrollbar would clutter the menu. */
.no-scrollbar {
  scrollbar-width: none !important;
  -ms-overflow-style: none !important;
}
.no-scrollbar::-webkit-scrollbar {
  width: 0 !important;
  height: 0 !important;
  display: none !important;
}

.no-scrollbar-deep,
.no-scrollbar-deep * {
  scrollbar-width: none !important;
  -ms-overflow-style: none !important;
}
.no-scrollbar-deep::-webkit-scrollbar,
.no-scrollbar-deep *::-webkit-scrollbar {
  width: 0 !important;
  height: 0 !important;
  display: none !important;
}
