/* ═══════════════════════════════════════════════════
   LucID — Bespoke 2026 Modern Design System & Layout
   Inspired by Matte Metallic Surfaces & Gold Accents
   ═══════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════
   FONTS — four locally-vendored sets (latin, woff2), synced from @fontsource
   packages by scripts/vendor.js. Only the active set's files are downloaded
   by the browser; declaring all four costs nothing at runtime.
   ═══════════════════════════════════════════════════ */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/geist/geist-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/geist/geist-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/geist/geist-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/geist/geist-latin-700-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/geist-mono/geist-mono-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/geist-mono/geist-mono-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/ibm-plex-sans/ibm-plex-sans-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/ibm-plex-sans/ibm-plex-sans-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/ibm-plex-sans/ibm-plex-sans-latin-600-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/ibm-plex-sans/ibm-plex-sans-latin-700-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/ibm-plex-mono/ibm-plex-mono-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/ibm-plex-mono/ibm-plex-mono-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/source-sans-3/source-sans-3-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/source-sans-3/source-sans-3-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/source-sans-3/source-sans-3-latin-600-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/source-sans-3/source-sans-3-latin-700-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Source Code Pro";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/source-code-pro/source-code-pro-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Source Code Pro";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/source-code-pro/source-code-pro-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/inter/inter-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/inter/inter-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/inter/inter-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/inter/inter-latin-700-normal.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/jetbrains-mono/jetbrains-mono-latin-500-normal.woff2")
    format("woff2");
}

@font-face {
  font-family: "Inconsolata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/inconsolata/inconsolata-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Inconsolata";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/inconsolata/inconsolata-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Inconsolata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/inconsolata/inconsolata-latin-600-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Inconsolata";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/inconsolata/inconsolata-latin-700-normal.woff2")
    format("woff2");
}

@font-face {
  font-family: "Cascadia Code";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/cascadia-code/cascadia-code-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Cascadia Code";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/cascadia-code/cascadia-code-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Cascadia Code";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/cascadia-code/cascadia-code-latin-600-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Cascadia Code";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/cascadia-code/cascadia-code-latin-700-normal.woff2")
    format("woff2");
}

@font-face {
  font-family: "Nunito";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/nunito/nunito-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Nunito";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/nunito/nunito-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Nunito";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/nunito/nunito-latin-600-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Nunito";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/nunito/nunito-latin-700-normal.woff2")
    format("woff2");
}

@font-face {
  font-family: "Roboto Slab";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/fonts/roboto-slab/roboto-slab-latin-400-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Roboto Slab";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/roboto-slab/roboto-slab-latin-500-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Roboto Slab";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/fonts/roboto-slab/roboto-slab-latin-600-normal.woff2")
    format("woff2");
}
@font-face {
  font-family: "Roboto Slab";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("vendor/fonts/roboto-slab/roboto-slab-latin-700-normal.woff2")
    format("woff2");
}

/* ═══════════════════════════════════════════════════
   DESIGN TOKENS — single source of truth
   Colour model: oklch only (perceptually uniform, so
   tints/shades and dark↔light pairs derive systematically).
   No rgba, no scattered hex. Every colour is named once
   and referenced by name via var(--token).
   ═══════════════════════════════════════════════════ */

/* ─── THEME-AGNOSTIC SCALES (never change per theme) ─── */
:root {
  /* Spacing ramp — relational rem, no raw px */
  --space-3xs: 0.125rem; /* 2px  */
  --space-2xs: 0.25rem; /* 4px  */
  --space-xs: 0.375rem; /* 6px  */
  --space-sm: 0.5rem; /* 8px  */
  --space-md: 0.75rem; /* 12px */
  --space-lg: 1rem; /* 16px */
  --space-xl: 1.5rem; /* 24px */
  --space-2xl: 2rem; /* 32px */

  /* Corner radii */
  --radius-xs: 0.25rem;
  --radius-sm: 0.375rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --radius-xl: 1rem;
  --radius-pill: 62.5rem;
  --radius-round: 50%;

  /* Elevation ladder — one scale, no magic 9999/10000 */
  --z-raised: 10;
  --z-overlay: 1000;
  --z-modal: 2000;
  --z-toast: 3000;

  /* Motion tokens */
  --motion-fast: 0.12s;
  --motion-base: 0.2s;
  --motion-slow: 0.35s;
  --ease-standard: cubic-bezier(0.16, 1, 0.3, 1);

  /* Typography — the sans/mono tokens are assigned per font set in the
     FONT SETS block after the theme scopes (user-selectable, Geist default) */

  /* Type scale (rem) */
  --text-2xs: 0.6875rem; /* 11px — count badges only */
  --text-xs: 0.75rem; /* 12px — badges, fine print */
  --text-sm: 0.8125rem; /* 13px — UI text */
  --text-base: 0.9375rem; /* 15px — body / editor / preview */
  --text-lg: 1.125rem; /* 18px */
  --text-xl: 1.375rem; /* 22px */
  --text-2xl: 1.75rem; /* 28px */
  --text-3xl: 2.25rem; /* 36px */

  /* Hairline width */
  --hairline: 0.0625rem; /* 1px */
}

/* ─── THEME: Dusk Ember (dark) — also the :root default ─── */
:root,
[data-theme="dusk-ember"] {
  color-scheme: dark;

  --bg-base: oklch(0.239 0.014 267);
  --bg-surface: oklch(0.277 0.019 268);
  --bg-elevated: oklch(0.321 0.025 266);
  --bg-input: oklch(0.212 0.013 267); /* was referenced but undefined */
  --bg-hover: oklch(0.773 0.14 78.6 / 0.12);
  --bg-active: oklch(0.773 0.14 78.6 / 0.2);
  --bg-drop: oklch(
    0.773 0.14 78.6 / 0.32
  ); /* drag drop target — must clear hover AND active */
  --surface-hover: oklch(0.321 0.025 266);

  --accent: oklch(0.773 0.14 78.6);
  --accent-hover: oklch(0.718 0.138 76.7);
  --accent-subtle: oklch(0.773 0.14 78.6 / 0.15);
  --on-accent: oklch(0.239 0.014 267); /* readable text ON accent */

  --text-primary: oklch(0.967 0.006 264);
  --text-secondary: oklch(0.8 0.006 264);
  --text-muted: oklch(0.69 0.006 264); /* AA on base AND elevated surfaces */

  --border: oklch(0.967 0.006 264 / 0.1);
  --border-hover: oklch(0.967 0.006 264 / 0.2);
  --shadow: 0 0.25rem 1rem oklch(0 0 0 / 0.35);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.25);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.28);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.4);
  --scrim: oklch(0 0 0 / 0.65);
  --accent-glow: oklch(0.773 0.14 78.6 / 0.45);
  --on-danger: oklch(
    0.22 0.02 25
  ); /* dark label — the dark-theme danger is a LIGHT coral */

  /* State feedback — belongs to the theme, not raw red/green.
     Positive == the theme accent; negative == the theme danger hue. */
  --danger: oklch(0.71 0.16 22.8);
  --save-ok: var(--accent);
  --success: var(--accent); /* "matched / ready" reads on-brand */
  --success-glow: oklch(0.773 0.14 78.6 / 0.32);
  --danger-subtle: oklch(0.71 0.16 22.8 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── THEME: Warm Linen (light) ─── */
[data-theme="warm-linen"] {
  color-scheme: light;

  --bg-base: oklch(0.976 0.026 92.4);
  --bg-surface: oklch(0.949 0.03 92.3);
  --bg-elevated: oklch(0.951 0.04 88.2);
  --bg-input: oklch(0.985 0.018 92.4);
  --bg-hover: oklch(0.747 0.046 83.8 / 0.15);
  --bg-active: oklch(0.747 0.046 83.8 / 0.22);
  --bg-drop: oklch(
    0.747 0.046 83.8 / 0.36
  ); /* drag drop target — must clear hover AND active */
  --surface-hover: oklch(0.951 0.04 88.2);

  --accent: oklch(0.643 0.055 81.4);
  --accent-hover: oklch(0.579 0.053 81.1);
  --accent-subtle: oklch(0.643 0.055 81.4 / 0.15);
  --on-accent: oklch(
    0.2 0.015 84.5
  ); /* dark text ON accent — AA on the muted-brown accent */

  --text-primary: oklch(0.267 0.019 84.5);
  --text-secondary: oklch(0.42 0.017 84.5);
  --text-muted: oklch(0.5 0.015 84.5); /* darkened to pass AA (was 2.66:1) */

  --border: oklch(0.267 0.019 84.5 / 0.12);
  --border-hover: oklch(0.267 0.019 84.5 / 0.24);
  --shadow: 0 0.125rem 0.5rem oklch(0 0 0 / 0.06);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.08);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.1);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.16);
  --scrim: oklch(0 0 0 / 0.45);
  --accent-glow: oklch(0.643 0.055 81.4 / 0.45);
  --on-danger: oklch(0.985 0.005 92);

  --danger: oklch(0.543 0.174 29.7);
  --save-ok: var(--accent);
  --success: var(--accent);
  --success-glow: oklch(0.643 0.055 81.4 / 0.35);
  --danger-subtle: oklch(0.543 0.174 29.7 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── THEME: Amber Hour (twilight) ───
   The in-between: mid-dark, not a midpoint — bg L≈0.40 keeps light text at AA
   while reading warmer and softer than dusk. Hue pulled to bronze (70-72);
   accent sits between dusk's bright gold and linen's muted brown-gold. */
[data-theme="amber-hour"] {
  color-scheme: dark;

  --bg-base: oklch(0.395 0.018 70);
  --bg-surface: oklch(0.43 0.021 71);
  --bg-elevated: oklch(0.468 0.024 72);
  --bg-input: oklch(0.37 0.016 70);
  --bg-hover: oklch(0.74 0.11 80 / 0.14);
  --bg-active: oklch(0.74 0.11 80 / 0.22);
  --bg-drop: oklch(0.74 0.11 80 / 0.34);
  --surface-hover: oklch(0.468 0.024 72);

  --accent: oklch(0.74 0.11 80);
  --accent-hover: oklch(0.69 0.108 79);
  --accent-subtle: oklch(0.74 0.11 80 / 0.15);
  --on-accent: oklch(0.28 0.02 75);

  --text-primary: oklch(0.955 0.008 85);
  --text-secondary: oklch(0.845 0.01 85);
  --text-muted: oklch(0.755 0.012 85);

  --border: oklch(0.955 0.008 85 / 0.14);
  --border-hover: oklch(0.955 0.008 85 / 0.26);
  --shadow: 0 0.25rem 1rem oklch(0 0 0 / 0.22);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.16);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.18);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.28);
  --scrim: oklch(0 0 0 / 0.55);
  --accent-glow: oklch(0.74 0.11 80 / 0.4);
  --on-danger: oklch(0.22 0.02 25);

  --danger: oklch(0.64 0.168 26);
  --save-ok: var(--accent);
  --success: var(--accent);
  --success-glow: oklch(0.74 0.11 80 / 0.32);
  --danger-subtle: oklch(0.64 0.168 26 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── THEME: Dracula (dark) ─── */
[data-theme="dracula-official"] {
  color-scheme: dark;

  --bg-base: oklch(0.268 0.027 277.5);
  --bg-surface: oklch(0.23 0.025 277.5);
  --bg-elevated: oklch(0.37 0.032 277.5);
  --bg-input: oklch(0.21 0.023 277.5);
  --bg-hover: oklch(0.724 0.145 298.5 / 0.14);
  --bg-active: oklch(0.724 0.145 298.5 / 0.22);
  --bg-drop: oklch(0.724 0.145 298.5 / 0.34);
  --surface-hover: oklch(0.37 0.032 277.5);

  --accent: oklch(0.724 0.145 298.5);
  --accent-hover: oklch(0.67 0.14 298);
  --accent-subtle: oklch(0.724 0.145 298.5 / 0.15);
  --on-accent: oklch(0.268 0.027 277.5);

  --text-primary: oklch(0.978 0.005 106.8);
  --text-secondary: oklch(0.7 0.14 290);
  --text-muted: oklch(0.535 0.065 264.8);

  --border: oklch(0.978 0.005 106.8 / 0.12);
  --border-hover: oklch(0.978 0.005 106.8 / 0.24);
  --shadow: 0 0.25rem 1rem oklch(0 0 0 / 0.35);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.25);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.28);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.4);
  --scrim: oklch(0 0 0 / 0.65);
  --accent-glow: oklch(0.724 0.145 298.5 / 0.45);
  --on-danger: oklch(0.22 0.02 25);

  --danger: oklch(0.655 0.22 22.4);
  --save-ok: var(--accent);
  --success: var(--accent);
  --success-glow: oklch(0.724 0.145 298.5 / 0.32);
  --danger-subtle: oklch(0.655 0.22 22.4 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── THEME: Catppuccin Mocha (dark) ─── */
[data-theme="catppuccin-mocha"] {
  color-scheme: dark;

  --bg-base: oklch(0.254 0.021 268.4);
  --bg-surface: oklch(0.222 0.02 268.2);
  --bg-elevated: oklch(0.185 0.018 268);
  --bg-input: oklch(0.2 0.019 268.1);
  --bg-hover: oklch(0.781 0.124 302.1 / 0.14);
  --bg-active: oklch(0.781 0.124 302.1 / 0.22);
  --bg-drop: oklch(0.781 0.124 302.1 / 0.34);
  --surface-hover: oklch(0.222 0.02 268.2);

  --accent: oklch(0.781 0.124 302.1);
  --accent-hover: oklch(0.73 0.12 302);
  --accent-subtle: oklch(0.781 0.124 302.1 / 0.15);
  --on-accent: oklch(0.185 0.018 268);

  --text-primary: oklch(0.885 0.024 256.3);
  --text-secondary: oklch(0.78 0.02 256);
  --text-muted: oklch(0.745 0.018 255.5);

  --border: oklch(0.885 0.024 256.3 / 0.12);
  --border-hover: oklch(0.885 0.024 256.3 / 0.24);
  --shadow: 0 0.25rem 1rem oklch(0 0 0 / 0.35);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.25);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.28);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.4);
  --scrim: oklch(0 0 0 / 0.65);
  --accent-glow: oklch(0.781 0.124 302.1 / 0.45);
  --on-danger: oklch(0.22 0.02 25);

  --danger: oklch(0.732 0.142 16.5);
  --save-ok: var(--accent);
  --success: var(--accent);
  --success-glow: oklch(0.781 0.124 302.1 / 0.32);
  --danger-subtle: oklch(0.732 0.142 16.5 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── THEME: Catppuccin Macchiato (dark) ─── */
[data-theme="catppuccin-macchiato"] {
  color-scheme: dark;

  --bg-base: oklch(0.282 0.024 268);
  --bg-surface: oklch(0.245 0.022 268);
  --bg-elevated: oklch(0.208 0.02 268);
  --bg-input: oklch(0.225 0.021 268);
  --bg-hover: oklch(0.77 0.122 302 / 0.14);
  --bg-active: oklch(0.77 0.122 302 / 0.22);
  --bg-drop: oklch(0.77 0.122 302 / 0.34);
  --surface-hover: oklch(0.245 0.022 268);

  --accent: oklch(0.77 0.122 302);
  --accent-hover: oklch(0.72 0.118 302);
  --accent-subtle: oklch(0.77 0.122 302 / 0.15);
  --on-accent: oklch(0.208 0.02 268);

  --text-primary: oklch(0.875 0.023 256);
  --text-secondary: oklch(0.775 0.019 255);
  --text-muted: oklch(0.74 0.018 255);

  --border: oklch(0.875 0.023 256 / 0.12);
  --border-hover: oklch(0.875 0.023 256 / 0.24);
  --shadow: 0 0.25rem 1rem oklch(0 0 0 / 0.35);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.25);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.28);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.4);
  --scrim: oklch(0 0 0 / 0.65);
  --accent-glow: oklch(0.77 0.122 302 / 0.45);
  --on-danger: oklch(0.22 0.02 25);

  --danger: oklch(0.715 0.14 16);
  --save-ok: var(--accent);
  --success: var(--accent);
  --success-glow: oklch(0.77 0.122 302 / 0.32);
  --danger-subtle: oklch(0.715 0.14 16 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── THEME: Catppuccin Frappé (dark) ─── */
[data-theme="catppuccin-frappe"] {
  color-scheme: dark;

  --bg-base: oklch(0.325 0.025 268);
  --bg-surface: oklch(0.285 0.023 268);
  --bg-elevated: oklch(0.245 0.021 268);
  --bg-input: oklch(0.265 0.022 268);
  --bg-hover: oklch(0.76 0.118 302 / 0.14);
  --bg-active: oklch(0.76 0.118 302 / 0.22);
  --bg-drop: oklch(0.76 0.118 302 / 0.34);
  --surface-hover: oklch(0.285 0.023 268);

  --accent: oklch(0.76 0.118 302);
  --accent-hover: oklch(0.71 0.114 302);
  --accent-subtle: oklch(0.76 0.118 302 / 0.15);
  --on-accent: oklch(0.245 0.021 268);

  --text-primary: oklch(0.865 0.022 256);
  --text-secondary: oklch(0.765 0.018 255);
  --text-muted: oklch(0.74 0.018 255);

  --border: oklch(0.865 0.022 256 / 0.12);
  --border-hover: oklch(0.865 0.022 256 / 0.24);
  --shadow: 0 0.25rem 1rem oklch(0 0 0 / 0.35);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.25);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.28);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.4);
  --scrim: oklch(0 0 0 / 0.65);
  --accent-glow: oklch(0.76 0.118 302 / 0.45);
  --on-danger: oklch(0.22 0.02 25);

  --danger: oklch(0.695 0.135 16);
  --save-ok: var(--accent);
  --success: var(--accent);
  --success-glow: oklch(0.76 0.118 302 / 0.32);
  --danger-subtle: oklch(0.695 0.135 16 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── THEME: Catppuccin Latte (light) ─── */
[data-theme="catppuccin-latte"] {
  color-scheme: light;

  --bg-base: oklch(0.965 0.008 256);
  --bg-surface: oklch(0.94 0.01 256);
  --bg-elevated: oklch(0.915 0.012 256);
  --bg-input: oklch(0.975 0.006 256);
  --bg-hover: oklch(0.55 0.22 302 / 0.15);
  --bg-active: oklch(0.55 0.22 302 / 0.22);
  --bg-drop: oklch(0.55 0.22 302 / 0.36);
  --surface-hover: oklch(0.915 0.012 256);

  --accent: oklch(0.55 0.22 302);
  --accent-hover: oklch(0.48 0.21 302);
  --accent-subtle: oklch(0.55 0.22 302 / 0.15);
  --on-accent: oklch(0.99 0 0);

  --text-primary: oklch(0.41 0.025 256);
  --text-secondary: oklch(0.47 0.022 256);
  --text-muted: oklch(0.53 0.02 256);

  --border: oklch(0.41 0.025 256 / 0.12);
  --border-hover: oklch(0.41 0.025 256 / 0.24);
  --shadow: 0 0.125rem 0.5rem oklch(0 0 0 / 0.06);
  --shadow-sm: 0 0.0625rem 0.1875rem oklch(0 0 0 / 0.08);
  --shadow-md: 0 0.125rem 0.5rem oklch(0 0 0 / 0.1);
  --shadow-lg: 0 0.5rem 1.5rem oklch(0 0 0 / 0.16);
  --scrim: oklch(0 0 0 / 0.45);
  --accent-glow: oklch(0.55 0.22 302 / 0.45);
  --on-danger: oklch(0.985 0.005 92);

  --danger: oklch(0.52 0.21 16);
  --save-ok: var(--accent);
  --success: var(--accent);
  --success-glow: oklch(0.55 0.22 302 / 0.35);
  --danger-subtle: oklch(0.52 0.21 16 / 0.12);

  --scrollbar-track: var(--bg-base);
  --scrollbar-thumb: var(--bg-elevated);
}

/* ─── FONT SETS — user-selectable, mirrors the theme mechanism ───
   The picker in the sidebar footer sets data-fontset; each set assigns the
   two font tokens. Geist is the out-of-the-box default (:root). */
:root,
[data-fontset="geist"] {
  --font-sans: "Geist", system-ui, -apple-system, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, monospace;
}
[data-fontset="plex"] {
  --font-sans: "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;
}
[data-fontset="source"] {
  --font-sans: "Source Sans 3", system-ui, -apple-system, sans-serif;
  --font-mono: "Source Code Pro", ui-monospace, monospace;
}
[data-fontset="inter"] {
  --font-sans: "Inter", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
}
[data-fontset="terminal"] {
  --font-sans: "Inconsolata", ui-monospace, monospace;
  --font-mono: "Inconsolata", ui-monospace, monospace;
}
[data-fontset="cascadia"] {
  --font-sans: "Cascadia Code", ui-monospace, monospace;
  --font-mono: "Cascadia Code", ui-monospace, monospace;
}
[data-fontset="nunito"] {
  --font-sans: "Nunito", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
}
[data-fontset="slab"] {
  --font-sans: "Roboto Slab", Georgia, serif;
  --font-mono: "Source Code Pro", ui-monospace, monospace;
}

/* ─── RESETS & BASE ────────────────────────────── */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 100%;
  height: 100%;
  width: 100%;
  /* Firefox scrollbar theming; the ::-webkit rules below cover the rest */
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}

body {
  height: 100%;
  width: 100%;
  max-width: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  font-family: var(--font-sans);
  background: var(--bg-base);
  color: var(--text-primary);
  line-height: 1.5;
  transition:
    background var(--motion-base) var(--ease-standard),
    color var(--motion-base) var(--ease-standard);
}

.icon-svg {
  width: 1.125rem;
  height: 1.125rem;
  display: inline-block;
  vertical-align: middle;
  flex-shrink: 0;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-miterlimit: 10;
}

::selection {
  background: var(--accent-subtle);
  color: var(--text-primary);
}

/* ─── THEME-ADAPTIVE SCROLLBARS (webkit; firefox on html above) ── */
::-webkit-scrollbar {
  width: 0.375rem;
  height: 0.375rem;
}

::-webkit-scrollbar-track {
  background: var(--scrollbar-track);
}

::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: var(--radius-xs);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--accent);
}

/* ─── 3-PANE CONTAINER ──────────────────────────── */
.app-container {
  display: flex;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
  background: var(--bg-base);
}
/* The app is hidden while the vault is locked. A class rather than an inline style,
   so the display value lives here with the rule that defines it. */
.app-container.hidden {
  display: none;
}

/* ─── SIDEBAR RESIZERS ──────────────────────────── */
.sidebar-resizer {
  width: 0.25rem;
  background: transparent;
  cursor: col-resize;
  flex-shrink: 0;
  z-index: var(--z-raised);
  transition: background var(--motion-fast);
}
.sidebar-resizer:hover,
.sidebar-resizer.resizing {
  background: var(--accent);
}

/* ─── TOP BAR (3.25rem) ─────────────────────────── */
.brand-header,
.top-bar {
  height: 3.25rem;
  min-height: 3.25rem;
  max-height: 3.25rem;
  padding: 0 var(--space-2xl);
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: var(--hairline) solid var(--border);
  background: var(--bg-surface);
  flex-shrink: 0;
}

.brand-header {
  /* No dividing border: the header blends into the sidebar as one continuous
     surface, the way the footer does. Only the CENTRE pane closes its band with a
     line, because that is the edge the content sits under. */
  border-bottom: none;
  border-right: none;
  padding-left: var(--space-md);
  padding-right: var(--space-md);
}

.top-bar {
  /* Center column is one continuous surface: the top-bar shares the editor's
     background and drops the dividing line, so only the view-tabs pill reads
     as a floating control — matching how the sidebar header blends. */
  background: var(--bg-base);
  border-bottom: none;
}

.brand-logo {
  display: flex;
  align-items: center;
}
.brand-logo-img {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-md);
  object-fit: cover;
  box-shadow: var(--shadow-sm);
}

.top-bar-left {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  flex: 1;
  min-width: 0;
}
.top-bar-right {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  flex-shrink: 0;
}

/* DOCKED EXPAND SIDEBAR BUTTON IN TOP BAR */
.docked-expand-btn {
  margin-right: var(--space-2xs);
  /* offset the icon button's own left padding so the glyph optically aligns
     with the editor content inset, not sitting 6px to its right */
  margin-left: calc(-1 * var(--space-xs));
}
.docked-expand-btn.hidden {
  display: none;
}

/* right-side mirror: glyph optically aligns to the inspector edge */
.docked-expand-btn.dock-right {
  margin-left: var(--space-2xs);
  margin-right: calc(-1 * var(--space-xs));
}

/* UN-CRAMPED VIEW MODE TABS (NO SUFFOCATING BORDERS) */
.view-tabs {
  display: flex;
  background: var(--bg-surface);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-lg);
  /* Matches the explorer pill container's inset: an active tab sits the same
     distance inside its container as an active pill does, which is what makes the
     two toolbars read as the same component family. */
  padding: var(--space-2xs) var(--space-xs);
  gap: var(--space-3xs);
}
.view-tab {
  font-size: var(--text-sm);
  font-weight: 500;
  padding: var(--space-2xs) var(--space-lg);
  border-radius: var(--radius-md);
  border: var(--hairline) solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  transition:
    color var(--motion-base) var(--ease-standard),
    background var(--motion-base) var(--ease-standard),
    box-shadow var(--motion-base) var(--ease-standard);
  white-space: nowrap;
}
.view-tab:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
}
.view-tab.active {
  background: var(--bg-elevated);
  color: var(--accent);
  border-color: transparent;
  box-shadow: var(--shadow-md);
  font-weight: 600;
}

/* ICON BUTTONS (ANIMATES ICON ITSELF — NO HARSH HOVER BACKGROUND BOX) */
.icon-btn {
  background: transparent;
  border: none;
  box-shadow: none;
  cursor: pointer;
  padding: var(--space-xs);
  border-radius: var(--radius-sm);
  font-size: var(--text-base);
  opacity: 0.75;
  transition:
    transform var(--motion-base) var(--ease-standard),
    opacity var(--motion-base) var(--ease-standard),
    filter var(--motion-base) var(--ease-standard),
    color var(--motion-base) var(--ease-standard);
  color: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.icon-btn:hover {
  opacity: 1;
  background: transparent;
  transform: translateY(-0.125rem) scale(1.15);
  color: var(--accent);
}

/* ─── SIDEBARS ──────────────────────────────────── */
.sidebar {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  user-select: none;
  transition:
    width var(--motion-fast) var(--ease-standard),
    opacity var(--motion-base) var(--ease-standard);
  background: var(--bg-surface);
}

.left-pane {
  width: var(
    --left-w,
    20rem
  ); /* default shows labels with comfortable margin */
  min-width: 15rem; /* Six icon buttons in one pill measure 205px of content;
                            with the sidebar body's 12px insets that needs a 229px
                            pane, so 13rem (208px) clipped. Measured, not guessed:
                            240px leaves 11px of slack. Was 13rem when the toolbar
                            held two pills of three buttons and needed only 180px. */
  max-width: 30rem;
  flex-shrink: 0;
}

.right-pane {
  width: var(--right-w, 16rem);
  min-width: 12rem;
  max-width: 25rem;
  flex-shrink: 0;
  overflow: hidden;
  background: var(--bg-surface);
  display: flex;
  flex-direction: column;
}

/* Inspector header — same 3.25rem band as the top-bar/brand-header so the
   collapse button lines up with the top-bar controls. Button sits at the
   left edge, adjacent to the center divider (mirror of the left panel). */
.inspector-header {
  height: 3.25rem;
  min-height: 3.25rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  padding: 0 var(--space-md);
}
.inspector-collapse-btn {
  /* offset the icon button's own padding so the glyph optically aligns with
     the inspector body's content column below it */
  margin-left: calc(-1 * var(--space-2xs));
}
.inspector-body {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0 var(--space-lg) var(--space-lg);
}

.sidebar.collapsed {
  width: 0;
  min-width: 0;
  padding: 0;
  overflow: hidden;
  border: none;
  opacity: 0;
  pointer-events: none;
}

/* ─── LEFT SIDEBAR BODY & STREAMLINED EXPLORER TOOLBAR ─ */
.sidebar-body {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  /* Top inset chosen to put the pill row the same distance BELOW the band line as
     the toolbar contents sit above it. It used to be 18px against their 1px. */
  padding: var(--space-sm) var(--space-md) 0.875rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

/* ─── INLINE SEARCH THAT MORPHS OVER THE TOOLBAR ─── */
.toolbar-cluster {
  position: relative; /* the search overlay fills this exact box */
  display: flex;
  align-items: center;
  flex: 1 1 auto; /* spans the row so the pill inside it can too, which is
                           what makes the left and right insets equal */
  min-width: 0;
  gap: var(--space-sm);
}
.explorer-search {
  position: absolute;
  inset: 0; /* 1:1 with the pills' combined box (width AND height) at any panel size */
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 0 var(--space-sm);
  background: var(--bg-surface);
  border: var(--hairline) solid var(--accent);
  border-radius: var(--radius-lg);
  box-shadow: 0 0 0 0.125rem var(--accent-subtle);
  opacity: 0;
  visibility: hidden;
  transform: scale(0.98);
  transition:
    opacity var(--motion-base) var(--ease-standard),
    transform var(--motion-base) var(--ease-standard),
    visibility var(--motion-base) var(--ease-standard);
}
.explorer-search .search-lead {
  flex-shrink: 0;
  color: var(--text-muted);
}
.explorer-search .search-input {
  flex: 1;
  min-width: 0;
  width: auto;
  border: none;
  background: transparent;
  box-shadow: none;
  border-radius: 0;
  padding: var(--space-2xs) 0;
  font-size: var(--text-sm);
  color: var(--text-primary);
  outline: none;
}
.search-close {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition:
    color var(--motion-fast) var(--ease-standard),
    background var(--motion-fast) var(--ease-standard);
}
.search-close:hover {
  color: var(--accent);
  background: var(--bg-hover);
}

/* Morph: the toolbar gives way to the search field */
.explorer-toolbar-pill {
  transition: opacity var(--motion-base) var(--ease-standard);
}
.tree-header-row.searching .explorer-toolbar-pill {
  opacity: 0;
  pointer-events: none;
}
.tree-header-row.searching .explorer-search {
  opacity: 1;
  visibility: visible;
  transform: scale(1);
}

/* EXPLORER STREAMLINED TOOLBAR ROW (ANCHORED SIDE-BY-SIDE WITH FIXED GAP) */
.tree-header-row {
  position: relative; /* positioning context for the inline search overlay */
  display: flex;
  align-items: center;
  justify-content: flex-start; /* both pills anchored left so they DON'T slide when the sidebar resizes */
  padding: var(--space-2xs) 0;
  gap: var(--space-sm);
  flex-wrap: nowrap;
  width: 100%;
  overflow: hidden;
}

/* One container holds all six controls: three views, a divider, three actions.
   Fixed to the left edge of the sidebar body; the row it sits in supplies the
   right inset, so the gap to the panel edge is the same on both sides at every
   width. Icons only — six labelled buttons cannot fit in any sidebar width the
   panel allows, and trying was what made the cluster clip. */
.explorer-toolbar-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: 1 1 auto; /* fills the row, so the inset to the sidebar edge is the
                          same on the left and the right at every panel width */
  min-width: 0;
  height: 2.25rem;
  background: var(--bg-surface);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-2xs);
  gap: var(--space-3xs);
}
.toolbar-divider {
  width: var(--hairline);
  align-self: stretch;
  margin: var(--space-2xs) var(--space-2xs);
  background: var(--border);
  flex-shrink: 0;
}

.explorer-pill-btn {
  flex: 0 0 auto;
  height: 100%;
  width: 1.875rem;
  padding: 0;
  border-radius: var(--radius-md);
  border: var(--hairline) solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  transition:
    color var(--motion-base) var(--ease-standard),
    background var(--motion-base) var(--ease-standard),
    border-color var(--motion-base) var(--ease-standard);
}
.explorer-pill-btn:hover {
  color: var(--accent);
  background: var(--bg-hover);
}
.explorer-pill-btn:hover .icon-svg {
  transform: scale(1.15);
  transition: transform var(--motion-fast) var(--ease-standard);
}
.explorer-pill-btn.active {
  background: var(--bg-elevated);
  color: var(--accent);
  border-color: transparent;
  box-shadow: var(--shadow-sm);
  font-weight: 600;
}

/* FIXED CONFINEMENT & ALIGNMENT FOR ACTION PILL BUTTONS */
.action-pill-btn {
  height: 100%;
  width: 1.875rem;
  padding: 0;
  margin: 0;
  border-radius: var(--radius-md);
  border: var(--hairline) solid transparent;
  background: transparent;
  color: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transform: none; /* PREVENT translateY(-2px) MISALIGNMENT */
  transition:
    background var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard);
}
.action-pill-btn:hover {
  transform: none; /* KEEP OUTER HOVER BOX STRICTLY FLUSH AND ALIGNED */
  color: var(--accent);
  background: var(--bg-hover);
  opacity: 1;
}
.action-pill-btn:hover .icon-svg {
  transform: scale(
    1.15
  ); /* SCALE ICON ITSELF SMOOTHLY WITHOUT SHIFTING OUTER CONFINEMENT BOX */
  transition: transform var(--motion-fast) var(--ease-standard);
}

/* ─── FOLDER & NOTE TREE HIERARCHY INDENTATION & SPACING ──── */
.folder-tree,
.tag-tree {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.folder-tree.hidden,
.tag-tree.hidden {
  display: none;
}

.tree-folder-header {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xs) var(--space-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-secondary);
  transition:
    background var(--motion-fast),
    color var(--motion-fast);
  position: relative;
}
.tree-folder-header:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
/* Containing folder of the open note: emphasised (brighter text+icon), NOT a selection chip.
   Emphasis is via text-primary only — accent isn't used here because its lightness
   relative to the default icon flips between themes and would invert the hierarchy. */
.tree-folder-header.active {
  color: var(--text-primary);
}
/* Disclosure caret — closed/open are two authentic glyphs (lin-arrow-right-1 /
   lin-arrow-down) swapped in JS, same pattern as the folder icon pair. */
.tree-caret-blank {
  width: 0.875rem;
  height: 0.875rem;
  flex-shrink: 0;
}
.tree-caret {
  width: 0.875rem;
  height: 0.875rem;
  color: var(--text-muted);
  flex-shrink: 0;
}
.tree-folder-header .count-badge {
  margin-left: auto;
  font-size: var(--text-2xs);
  color: var(--text-muted);
  background: var(--bg-base);
  padding: var(--space-3xs) var(--space-xs);
  border-radius: var(--radius-xl);
}

/* GENEROUS PROPER SPACING BETWEEN HEADER AND FIRST NESTED NOTE UNDERNEATH */
.tree-notes {
  margin-left: var(--space-lg);
  margin-top: var(--space-xs);
  padding-left: var(--space-sm);
  padding-top: var(--space-2xs);
  border-left: var(--hairline) solid var(--border);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  overflow: hidden;
  transition: max-height var(--motion-slow) var(--ease-standard);
}
.tree-notes.collapsed {
  max-height: 0;
  margin-top: 0;
  padding-top: 0;
}

.tree-note {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xs) var(--space-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  transition:
    background var(--motion-fast),
    color var(--motion-fast);
}
.tree-note:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
/* The ONE open note: clean filled selection + readable bold text */
.tree-note.active {
  background: var(--bg-active);
  color: var(--text-primary);
  font-weight: 600;
}

/* Pinned marker. Hangs at the right of the row where the folder count badge sits,
   so it reads as state on the row rather than a control to press. */
.pin-marker {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  color: var(--accent);
  flex-shrink: 0;
}
.pin-marker .icon-svg {
  width: 0.875rem;
  height: 0.875rem;
}

/* Keyboard focus ring for tree navigation (arrow keys / Tab) */
.tree-folder-header:focus-visible,
.tree-note:focus-visible {
  outline: 0.125rem solid var(--accent);
  outline-offset: -0.125rem;
}

/* A-01: keyboard focus must be visible on every interactive control, not just
   tree items. :focus-visible means mouse users never see a ring — only keyboard
   users do. Matches the accent outline already used by the tree. */
button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: 0.125rem solid var(--accent);
  outline-offset: 0.125rem;
  border-radius: var(--radius-sm);
}

/* ─── RIGHT-CLICK TREE CONTEXT MENU ─────────────── */
.context-menu {
  position: fixed;
  z-index: var(--z-overlay);
  background: var(--bg-elevated);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-xs);
  min-width: 11rem;
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
.context-menu.hidden {
  display: none;
}
.context-menu.sub-context-menu {
  min-width: max-content;
  white-space: nowrap;
}

.context-menu-item {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xs) var(--space-sm);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--text-primary);
  cursor: pointer;
  border: none;
  background: transparent;
  width: 100%;
  text-align: left;
  transition: background var(--motion-fast);
}
.context-menu-item:hover {
  background: var(--bg-hover);
  color: var(--accent);
}
.context-menu-item.danger:hover {
  background: var(--danger-subtle);
  color: var(--danger);
}
/* Membership toggles in a menu (tag picker): the accent means applied, muted
   means available. Colour carries the state, the knob position carries it too —
   never colour alone (WCAG 1.4.1). */
.context-menu-item .menu-toggle.on {
  color: var(--accent);
}
.context-menu-item .menu-toggle.off {
  color: var(--text-muted);
}
.context-menu-item:hover .menu-toggle.off {
  color: var(--text-secondary);
}

.context-menu-divider {
  height: var(--hairline);
  background: var(--border);
  margin: var(--space-2xs) 0;
  flex-shrink: 0;
}

/* ─── TRASH ROW & PANEL ─────────────────────────── */
.trash-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  width: 100%;
  padding: var(--space-xs) var(--space-md);
  background: var(--bg-surface);
  border: none;
  border-top: var(--hairline) solid var(--border);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition:
    background var(--motion-fast),
    color var(--motion-fast);
}
/* The trashcan is the trashcan, not the whole row: hover and drag feedback live
   on the glyph alone (color + lid swap in JS); the row never fills. */
.trash-row:hover {
  color: var(--text-primary);
}
.trash-row:hover .icon-svg {
  color: var(--accent);
  transform: scale(1.15);
  transition: transform var(--motion-fast) var(--ease-standard);
}
.trash-row.open {
  color: var(--accent);
}
.trash-row.drop-target {
  color: var(--text-primary);
}
.trash-row.drop-target .icon-svg {
  color: var(--accent);
  transform: scale(1.15);
}
.trash-panel {
  background: var(--bg-surface);
  border-top: var(--hairline) solid var(--border);
  max-height: 14rem;
  overflow-y: auto;
  padding: var(--space-sm) var(--space-md);
}
.trash-panel[hidden] {
  display: none;
}
.trash-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* ─── SIDEBAR FOOTER, E2EE, SYNC BADGE & LOCK ACTION ─── */
.sidebar-footer {
  padding: var(--space-md);
  margin-top: auto;
  border-top: none;
  background: var(--bg-surface);
}

.e2ee-card {
  padding: 0.625rem var(--space-md);
  border-radius: 0.625rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  background: var(--bg-elevated);
  box-shadow: var(--shadow);
}
.e2ee-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-primary);
}
/* Comfort controls — theme, font, auto-lock. One family, one glyph scale
   (INC-42: the old 0.9375rem override died with the text line it balanced). */
.footer-pref-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition:
    color var(--motion-fast) var(--ease-standard),
    background-color var(--motion-fast) var(--ease-standard);
}
.footer-pref-btn:hover {
  color: var(--accent);
  background: var(--surface-hover);
}
.menu-icon-blank {
  display: inline-block;
  width: 0.875rem;
  height: 0.875rem;
}
/* E2EE state is a glyph, not a sentence: the shield carries the state, the
   tooltip carries the detail — same control family as the sync/runtime badges. */
/* The lock button is the security corner now: one control that both reports the
   vault's posture and acts on it. Trash joins it here later (see HANDOFF). */
.lock-glyph {
  display: inline-flex;
  align-items: center;
}
.lock-glyph .icon-svg {
  transition: color var(--motion-fast) var(--ease-standard);
}
.lock-action-btn.is-warning {
  color: var(--danger);
}
.footer-security-cluster {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.footer-actions-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-top: var(--space-2xs);
  border-top: none;
}

/* Status text is present for assistive technology but not painted: the glyph
   carries the state visually, the tooltip carries the detail. */
.visually-hidden {
  position: absolute;
  width: var(--hairline);
  height: var(--hairline);
  margin: calc(-1 * var(--hairline));
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Sync and runtime read as one control family with the repository link beside
   them: same box, same hover, same accent. */
.sync-status-badge,
.runtime-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  transition:
    color var(--motion-fast) var(--ease-standard),
    background-color var(--motion-fast) var(--ease-standard);
}
/* Sync and runtime are CLICKABLE (INC-43b: sync now / recheck health) — the
   hover they always had is now an honest affordance. The shield stays a pure
   status and paints no hover. */
.sync-status-badge:hover,
.runtime-badge:hover {
  color: var(--accent);
  background: var(--surface-hover);
}
.sync-status-badge,
.runtime-badge {
  cursor: pointer;
}
.sync-status-badge:focus-visible,
.runtime-badge:focus-visible {
  outline: var(--hairline) solid var(--accent);
  outline-offset: 0.125rem;
}
.sync-status-badge.saving {
  color: var(--accent);
  animation: pulse-sync 1.2s infinite var(--ease-standard);
}
.sync-status-badge.error,
.runtime-badge.error {
  color: var(--danger);
}
@keyframes pulse-sync {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
  100% {
    opacity: 1;
  }
}

.lock-action-btn {
  font-size: var(--text-xs);
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-sm);
  border: var(--hairline) solid var(--border);
  background: var(--bg-base);
  color: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  cursor: pointer;
  transition:
    color var(--motion-fast) var(--ease-standard),
    background var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard);
}
/* Hover like everything else: the surface tints and the colour shifts. It used to
   light the whole border accent instead, and since this is the only footer control
   with a resting border, hovering lit the brightest, largest outline on the page —
   louder than any ACTIVE state elsewhere, for a mere hover. The border stays at
   --border: it is this button's resting identity as the one action among
   indicators, not a hover channel. No glyph scale either, unlike the icon-only
   pills: this button has a label beside the glyph, and growing one would shove the
   other. */
.lock-action-btn:hover {
  background: var(--bg-hover);
  color: var(--accent);
}

/* ─── CENTER PANE & 100% AUTO-FIT EDITOR ─────────── */
.center-pane {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg-base);
}

/* 100% AUTO-FIT EDITOR/PREVIEW CONTAINER */
.editor-split {
  flex: 1 1 100%;
  height: calc(100% - 3.25rem);
  width: 100%;
  display: flex;
  overflow: hidden;
  min-height: 0;
  background: var(--bg-base);
  /* The content area draws the same hairline the tree's indent guide draws, so the
     whole middle section has a real top edge at the 3.25rem band boundary — the one
     horizontal line every other pane's edge can be measured against. */
  border-top: var(--hairline) solid var(--border);
}

/* MODE 1: EDITOR ONLY */
.editor-split.mode-editor .editor-pane {
  flex: 1 1 100%;
  width: 100%;
  height: 100%;
  display: flex;
}
.editor-split.mode-editor .preview-pane,
.editor-split.mode-editor .split-handle {
  display: none;
}

/* MODE 2: PREVIEW ONLY */
.editor-split.mode-preview .preview-pane {
  flex: 1 1 100%;
  width: 100%;
  height: 100%;
  display: flex;
}
.editor-split.mode-preview .editor-pane,
.editor-split.mode-preview .split-handle {
  display: none;
}

/* MODE 3A: SPLIT VIEW (Vertical / Top-Bottom) */
.editor-split.mode-split-vertical {
  flex-direction: column;
}
.editor-split.mode-split-vertical .editor-pane {
  flex: 0 0 var(--split-pct, 50%);
  width: 100%;
  min-height: 0;
  display: flex;
}
.editor-split.mode-split-vertical .preview-pane {
  flex: 1 1 0;
  width: 100%;
  min-height: 0;
  display: flex;
}
.editor-split.mode-split-vertical .split-handle {
  height: 0.375rem;
  width: 100%;
  cursor: row-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-base);
  border-top: var(--hairline) solid var(--border);
  border-bottom: none;
  border-left: none;
  border-right: none;
  flex-shrink: 0;
}
.editor-split.mode-split-vertical .handle-line {
  width: 2.5rem;
  height: 0.1875rem;
  border-radius: 0.125rem;
  background: var(--border-hover);
}

/* MODE 3B: SPLIT VIEW (Horizontal / Side-by-Side Left-Right) */
.editor-split.mode-split-horizontal {
  flex-direction: row;
}
.editor-split.mode-split-horizontal .editor-pane {
  flex: 0 0 var(--split-pct, 50%);
  height: 100%;
  min-width: 0;
  display: flex;
}
.editor-split.mode-split-horizontal .preview-pane {
  flex: 1 1 0;
  height: 100%;
  min-width: 0;
  display: flex;
}
.editor-split.mode-split-horizontal .split-handle {
  width: 0.375rem;
  height: 100%;
  cursor: col-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-base);
  border-left: var(--hairline) solid var(--border);
  border-right: none;
  border-top: none;
  border-bottom: none;
  flex-shrink: 0;
}
.editor-split.mode-split-horizontal .handle-line {
  height: 2.5rem;
  width: 0.1875rem;
  border-radius: 0.125rem;
  background: var(--border-hover);
}

#markdown-textarea {
  flex: 1 1 100%;
  width: 100%;
  height: 100%;
  min-height: 0;
  padding: var(--space-xl) var(--space-2xl);
  background: var(--bg-base);
  color: var(--text-primary);
  border: none;
  outline: none;
  box-shadow: none;
  resize: none;
  font-family: var(--font-mono);
  font-size: var(--editor-font-size, var(--text-base));
  line-height: 1.6;
  box-sizing: border-box;
  overflow-y: auto;
  margin: 0;
}

.preview-content {
  flex: 1 1 100%;
  width: 100%;
  height: 100%;
  padding: var(--space-xl) var(--space-2xl);
  overflow-y: auto;
  font-size: var(--editor-font-size, var(--text-base));
  line-height: 1.6;
  color: var(--text-primary);
  box-sizing: border-box;
}

/* ─── RENDERED MARKDOWN (PREVIEW CONTENT) ──────────── */
.preview-content > *:first-child {
  margin-top: 0;
}
.preview-content > *:last-child {
  margin-bottom: 0;
}

.preview-content h1,
.preview-content h2,
.preview-content h3,
.preview-content h4,
.preview-content h5,
.preview-content h6 {
  color: var(--text-primary);
  font-weight: 700;
  line-height: 1.25;
  margin: var(--space-xl) 0 var(--space-md);
}
.preview-content h1 {
  font-size: var(--text-3xl);
}
.preview-content h2 {
  font-size: var(--text-2xl);
  padding-bottom: var(--space-xs);
  border-bottom: var(--hairline) solid var(--border);
}
.preview-content h3 {
  font-size: var(--text-xl);
}
.preview-content h4 {
  font-size: var(--text-lg);
}
.preview-content h5 {
  font-size: var(--text-base);
  text-transform: uppercase;
  letter-spacing: 0.05rem;
  color: var(--text-secondary);
}
.preview-content h6 {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.preview-content p {
  margin: 0 0 var(--space-md);
}

.preview-content ul,
.preview-content ol {
  margin: 0 0 var(--space-md);
  padding-left: var(--space-xl);
}
.preview-content li {
  margin-bottom: var(--space-2xs);
}
.preview-content li > ul,
.preview-content li > ol {
  margin: var(--space-2xs) 0 0;
}

.preview-content a {
  color: var(--accent);
  text-decoration: none;
}
.preview-content a:hover {
  text-decoration: underline;
}
.preview-content strong {
  font-weight: 700;
  color: var(--text-primary);
}
.preview-content em {
  font-style: italic;
}

.preview-content code {
  font-family: var(--font-mono);
  font-size: 0.875em;
  background: var(--bg-elevated);
  padding: 0.125em 0.375em;
  border-radius: var(--radius-sm);
}
.preview-content pre {
  background: var(--bg-elevated);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-md) var(--space-lg);
  overflow-x: auto;
  margin: 0 0 var(--space-md);
}
.preview-content pre code {
  background: none;
  padding: 0;
  border-radius: 0;
  font-size: var(--text-sm);
  line-height: 1.5;
}

.preview-content blockquote {
  margin: 0 0 var(--space-md);
  padding: var(--space-2xs) var(--space-lg);
  border-left: 0.1875rem solid var(--accent);
  color: var(--text-secondary);
}

/* Task-list boxes. Drawn rather than input elements: the sanitizer forbids form
   controls in rendered markdown, and a span themes correctly. */
.preview-content .task-check {
  display: inline-block;
  position: relative;
  width: 0.875rem;
  height: 0.875rem;
  margin-right: var(--space-xs);
  vertical-align: text-top;
  border: var(--hairline) solid var(--border-hover);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
}
.preview-content .task-check.on {
  border-color: var(--accent);
  background: var(--accent-subtle);
}
.preview-content .task-check.on::after {
  content: "";
  position: absolute;
  left: 0.1875rem;
  top: 0.0625rem;
  width: 0.25rem;
  height: 0.5rem;
  border-right: 0.125rem solid var(--accent);
  border-bottom: 0.125rem solid var(--accent);
  transform: rotate(45deg);
}
.preview-content hr {
  border: none;
  border-top: var(--hairline) solid var(--border);
  margin: var(--space-xl) 0;
}

.preview-content table {
  border-collapse: collapse;
  width: 100%;
  margin: 0 0 var(--space-md);
  font-size: var(--text-sm);
}
.preview-content th,
.preview-content td {
  border: var(--hairline) solid var(--border);
  padding: var(--space-xs) var(--space-md);
  text-align: left;
}
.preview-content th {
  background: var(--bg-surface);
  font-weight: 600;
}

.preview-content img {
  max-width: 100%;
  border-radius: var(--radius-md);
}

/* Task-list checkboxes */
.preview-content input[type="checkbox"] {
  margin-right: var(--space-2xs);
  accent-color: var(--accent);
}

/* ─── RIGHT INSPECTOR PANE & METRICS FORMATTING ─── */
.right-pane section {
  margin-bottom: var(--space-xl);
}
.tags-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-md);
}
.tags-header h6 {
  margin-bottom: 0;
}
.right-pane h6 {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08rem;
  color: var(--text-muted);
  text-transform: uppercase;
  margin-bottom: var(--space-sm);
}

.btn-tag-add {
  font-size: var(--text-base);
  font-weight: 600;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: var(--radius-round);
  border: var(--hairline) solid var(--border);
  background: var(--bg-base);
  color: var(--accent);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--motion-fast);
}
.btn-tag-add:hover {
  background: var(--accent);
  color: var(--on-accent);
}

.toc-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}
.toc-item {
  font-size: var(--text-sm);
  padding: var(--space-xs) var(--space-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-secondary);
  transition:
    color var(--motion-fast),
    background var(--motion-fast),
    border-color var(--motion-fast);
}
.toc-item:hover {
  color: var(--accent);
  background: var(--bg-hover);
}
.toc-item.toc-h2 {
  padding-left: var(--space-lg);
}
.toc-item.toc-h3 {
  padding-left: var(--space-xl);
  font-size: var(--text-xs);
}

.empty-state {
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-style: italic;
}
/* J-04: these replace hardcoded inline px styles previously injected from app.js */
.empty-state-pane {
  padding: var(--space-2xl);
  text-align: center;
  font-style: normal;
}
.empty-state-preview {
  padding: var(--space-lg);
}
/* S-05: a note that could not be decrypted — shown read-only, never editable */
.locked-note {
  padding: var(--space-lg);
  color: var(--danger);
  font-style: normal;
  line-height: 1.5;
}

.tags-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}
.tag-chip {
  font-size: var(--text-xs);
  background: var(--accent-subtle);
  color: var(--accent);
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-xl);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
}
.tag-del-btn {
  font-size: var(--text-xs);
  font-weight: 700;
  cursor: pointer;
  opacity: 0.7;
}
.tag-del-btn:hover {
  opacity: 1;
  color: var(--danger);
}

/* METRICS GRID SPACING */
.metrics-grid {
  display: grid;
  /* responsive: 3 across when wide, reflow to 2 then 1 as the pane narrows —
     cards never overflow/clip */
  grid-template-columns: repeat(auto-fit, minmax(4rem, 1fr));
  gap: var(--space-sm);
}
.metric {
  padding: var(--space-sm) var(--space-xs);
  border-radius: var(--radius-md);
  text-align: center;
  background: var(--bg-elevated);
  border: var(--hairline) solid var(--border);
  box-shadow: var(--shadow-sm);
}
.metric strong {
  display: block;
  font-size: var(--text-lg);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  line-height: 1.2;
}
.metric small {
  display: block;
  margin-top: var(--space-2xs);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05rem;
}

/* ─── IN-APP MODALS ──────────────────────────────── */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--scrim);
  backdrop-filter: blur(0.25rem);
}
.modal-backdrop.hidden {
  display: none;
}

.modal-card {
  width: min(90vw, 22rem);
  padding: var(--space-xl);
  background: var(--bg-surface);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  text-align: center;
}

.modal-icon {
  margin-bottom: var(--space-md);
  color: var(--accent);
  display: flex;
  justify-content: center;
}
.modal-warning-svg,
.modal-prompt-svg {
  width: 2.75rem;
  height: 2.75rem;
}

.modal-card h3 {
  font-size: var(--text-lg);
  margin-bottom: var(--space-xs);
  color: var(--text-primary);
}
.modal-card p {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin-bottom: var(--space-lg);
  line-height: 1.4;
}

.modal-input {
  width: 100%;
  display: block;
  padding: var(--space-sm) var(--space-md);
  font-size: var(--text-base);
  background: var(--bg-base);
  color: var(--text-primary);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-sm);
  outline: none;
  margin-bottom: var(--space-lg);
}
.modal-input:focus {
  border-color: var(--accent);
}

.modal-actions {
  display: flex;
  gap: var(--space-sm);
}

.btn-modal-secondary,
.btn-modal-primary,
.btn-modal-danger {
  flex: 1;
  padding: var(--space-sm) var(--space-md);
  font-size: var(--text-sm);
  font-weight: 600;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: opacity var(--motion-fast);
}

.btn-modal-secondary {
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: var(--hairline) solid var(--border);
}
.btn-modal-secondary:hover {
  background: var(--bg-hover);
}

.btn-modal-primary {
  background: var(--accent);
  color: var(--on-accent);
  border: none;
}
.btn-modal-primary:hover {
  opacity: 0.9;
}

.btn-modal-danger {
  background: var(--danger);
  color: var(--on-danger);
  border: none;
}
.btn-modal-danger:hover {
  opacity: 0.9;
}

/* ─── MANDATORY E2EE LOCK SCREEN ────────────────── */
.lock-screen {
  position: fixed;
  inset: 0;
  z-index: var(--z-toast);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-base);
}
.lock-screen.hidden {
  display: none;
}

.lock-card {
  width: min(90vw, 26rem);
  padding: var(--space-2xl);
  text-align: center;
  background: var(--bg-surface);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
.lock-icon {
  margin-bottom: var(--space-lg);
  display: flex;
  justify-content: center;
}
.lock-logo-img {
  width: 9rem;
  height: 9rem;
  border-radius: var(--radius-lg);
  object-fit: cover;
  box-shadow: var(--shadow-lg);
}
/* A refused passphrase shakes the field instead of pushing a line into the card:
   nothing moves except the input itself, so the button stays where the cursor
   already is. Six keyframes, no JS animation loop.
   The message still exists for screen readers (role=alert), just visually hidden,
   and prefers-reduced-motion trades the shake back for the visible line, because
   without motion the red edge alone would be colour-only signalling. */
@keyframes lock-shake {
  0%,
  100% {
    transform: translateX(0);
  }
  20% {
    transform: translateX(-0.375rem);
  }
  40% {
    transform: translateX(0.375rem);
  }
  60% {
    transform: translateX(-0.25rem);
  }
  80% {
    transform: translateX(0.125rem);
  }
}
.lock-input.shake {
  animation: lock-shake var(--motion-slow) var(--ease-standard);
}

@media (prefers-reduced-motion: reduce) {
  .lock-input.shake {
    animation: none;
  }
  .lock-error.visually-hidden {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
}

/* Fixed-height row for failure messages. Reserved so the card cannot shift under
   the cursor when one appears. */
.lock-msg-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0.75rem;
  margin-bottom: 0;
}
.lock-msg-slot .lock-error {
  margin-bottom: 0;
}
.lock-inputs-group.hidden,
.lock-footer.hidden {
  display: none;
}
.lock-inputs-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  width: 100%;
  /* No bottom margin: the reserved message row below IS the separation from the
     button. Stacking both put 3rem of dead air under the fields. */
  margin-bottom: 0;
}
.lock-input {
  width: 100%;
  min-height: 2.5rem;
  padding: var(--space-sm) var(--space-md);
  margin-bottom: 0;
  font-size: var(--text-sm);
  font-family: var(--font-mono);
  background: var(--bg-input);
  color: var(--text-primary);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-md);
  outline: none;
  text-align: center;
  letter-spacing: 0.125rem;
  transition:
    color var(--motion-base) var(--ease-standard),
    background var(--motion-base) var(--ease-standard),
    border-color var(--motion-base) var(--ease-standard);
}
.lock-input.hidden {
  display: none;
}

/* "Vault locked" cue (unlock mode only) */
.lock-status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0 auto var(--space-md);
  padding: var(--space-3xs) var(--space-sm);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--bg-elevated);
  border-radius: var(--radius-pill);
}
.lock-status svg {
  width: 0.875rem;
  height: 0.875rem;
  color: inherit;
}
.lock-status {
  color: var(--accent);
}
.lock-status.bad {
  color: var(--danger);
}
.lock-status.hidden {
  display: none;
}

/* Show/hide passphrase toggle */
.lock-input-wrap {
  position: relative;
  display: block;
  width: 100%;
}
.lock-input-wrap .lock-input {
  padding-left: var(--space-2xl);
  padding-right: var(--space-2xl);
}
.lock-reveal {
  position: absolute;
  right: var(--space-sm);
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color var(--motion-fast) var(--ease-standard);
}
.lock-reveal:hover {
  color: var(--accent);
}
.lock-reveal svg {
  width: 1.125rem;
  height: 1.125rem;
}
.lock-reveal .icon-eye,
.lock-reveal .icon-eye-slash {
  display: inline-flex;
  align-items: center;
}
.lock-reveal .icon-eye-slash {
  display: none;
}
.lock-reveal.revealed .icon-eye {
  display: none;
}
.lock-reveal.revealed .icon-eye-slash {
  display: inline-flex;
}

/* Caps Lock heads-up */
/* Caps Lock lives INSIDE the field, opposite the reveal eye: a warning that
   appears where the typing happens, and never moves the card. No counterpart for
   the off state — the absence of the flag is the off state. */
.lock-caps-flag {
  position: absolute;
  left: var(--space-md);
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  color: var(--accent);
  pointer-events: none;
}
.lock-caps-flag svg {
  width: 0.9375rem;
  height: 0.9375rem;
}
.lock-caps-flag.hidden {
  display: none;
}
.lock-input::placeholder {
  font-family: var(--font-sans);
  letter-spacing: normal;
  font-size: var(--text-sm);
  color: var(--text-muted);
  opacity: 0.7;
}
/* ONE LINE, EVER. A text field already draws one line: its own edge. Focus
   recolours that edge and does nothing else. It used to recolour the edge AND add
   a 0.1875rem ring hugging it AND inherit the app-wide :focus-visible outline at a
   0.125rem offset, so clicking a passphrase box drew three concentric rings for
   one fact. Browsers match :focus-visible on text inputs even for mouse clicks,
   so this hit every user, not just keyboard ones. */
.lock-input:focus {
  border-color: var(--accent);
}
/* The detached outline is the right indicator for buttons and tree rows, which
   have no caret and often no edge of their own. A text field has both, so here it
   is a second ring saying what the edge already says. Specificity 0,2,0 beats the
   global input:focus-visible at 0,1,1 — no !important needed. */
.lock-input:focus-visible,
.modal-input:focus-visible {
  outline: none;
}
/* matched = gold (the app's success/accent colour), by design */
/* Two channels, never doubled: FOCUS owns the outer ring (where you are), STATE
   owns the edge and the fill (what the app thinks of what you typed). Before
   this, a focused matched field carried a ring, a tint and a coloured edge at
   once, which read as glow on glow. */
/* A refused passphrase. Same single line as focus and state, held for exactly as
   long as the shake plays: colour says WHAT happened, motion says THAT it
   happened, and neither survives into the next attempt. No fill, because the box
   is empty by then and a wash over nothing reads as a stain rather than a state. */
.lock-input.is-refused {
  border-color: var(--danger);
}
.lock-input.is-matched {
  border-color: var(--success);
  background: var(--accent-subtle);
}
.lock-input.is-mismatch {
  border-color: var(--danger);
  background: var(--danger-subtle);
}
/* Focus and state share the single line, and state wins while it lasts: these
   rules come later at equal specificity, so a mismatched field keeps its red edge
   when you click into it instead of trading the error away for a focus colour.
   The fill is state's second voice — a wash, not a line, so it cannot read as a
   second border. */
.lock-error {
  font-size: var(--text-sm);
  color: var(--danger);
  margin-bottom: var(--space-md);
  font-weight: 500;
}
.lock-error.hidden {
  display: none;
}

.lock-btn {
  width: 100%;
  display: block;
  min-height: 2.5rem;
  padding: var(--space-sm) var(--space-lg);
  font-size: var(--text-sm);
  font-weight: 600;
  font-family: inherit;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;
  margin-bottom: var(--space-lg);
  transition:
    color var(--motion-base) var(--ease-standard),
    background var(--motion-base) var(--ease-standard),
    border-color var(--motion-base) var(--ease-standard);
}
.lock-btn:hover:not(:disabled) {
  opacity: 0.92;
  transform: translateY(-0.0625rem);
}
.lock-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.lock-btn.is-ready {
  background: var(--success);
  color: var(--on-accent);
  opacity: 1;
  cursor: pointer;
  box-shadow: 0 0.25rem 1rem var(--success-glow);
}
.lock-footer {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.5;
}

/* ─── FOOTER GITHUB / VERSION INDICATOR ───────────── */
/* lives in the left sidebar footer, grouped with sync + lock;
   uses the native title tooltip like its neighbours (no bespoke tooltip) */
.footer-status-cluster {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}
.footer-github-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  transition:
    color var(--motion-fast) var(--ease-standard),
    background-color var(--motion-fast) var(--ease-standard);
}
.footer-github-link:hover {
  color: var(--accent);
  background: var(--surface-hover);
}
/* Update available: awareness, not a rave — a faint slow breath (INC-45).
   Self-hosted means this can stay on screen for days; it must whisper. */
.footer-github-link.update-available {
  color: var(--accent);
  animation: pulse-update 4s infinite var(--ease-standard);
}
@keyframes pulse-update {
  0% {
    transform: scale(1);
    filter: drop-shadow(0 0 0.0625rem var(--accent));
  }
  50% {
    transform: scale(1.04);
    filter: drop-shadow(0 0 0.25rem var(--accent));
  }
  100% {
    transform: scale(1);
    filter: drop-shadow(0 0 0.0625rem var(--accent));
  }
}

/* Dragging a note onto a folder header moves it there. The dragged row fades;
   the folder under the cursor fills with --bg-drop. Tree items signal state by
   fill, so no ring here — box-shadow rings belong to inputs. --bg-drop sits
   above --bg-active so the target stays legible while hover is also applied,
   and text is --text-primary, never accent, per the note above
   .tree-folder-header.active. */
.tree-note[draggable="true"] {
  cursor: grab;
}
.tree-note.dragging {
  opacity: 0.4;
  cursor: grabbing;
}
.tree-folder-header.drop-target {
  background: var(--bg-drop);
  color: var(--text-primary);
}

/* Two indicators now signal state through motion. Users who have asked the OS
   to reduce motion keep the colour and glyph change and lose only the movement. */
@media (prefers-reduced-motion: reduce) {
  .footer-github-link.update-available,
  .sync-status-badge.saving {
    animation: none;
  }
}

/* ─── RESPONSIVE BREAKPOINTS ─────────────────────── */
@media (max-width: 60rem) {
  .right-pane {
    display: none;
  }
  .sidebar-resizer {
    display: none;
  }
}
@media (max-width: 40rem) {
  .left-pane {
    width: 0;
    min-width: 0;
    overflow: hidden;
    border: none;
  }
}

/* One glyph turned four ways for the pane toggles: lin-grid-4's line marks which
   side the pane occupies, so hide/show and left/right are all the same drawing at
   90-degree steps. Same trick as the split tab's rotated centre line. */
.icon-svg.pane-hide-left {
  transform: rotate(0deg);
}
.icon-svg.pane-show-left {
  transform: rotate(180deg);
}
.icon-svg.pane-hide-right {
  transform: rotate(180deg);
}
.icon-svg.pane-show-right {
  transform: rotate(0deg);
}
.icon-svg.turn-90 {
  transform: rotate(90deg);
}

/* Menus mark the current entry by colour, keeping each entry's own glyph. A tick
   replacing the glyph told you which one was chosen but hid WHAT it was. */
.context-menu-item.active {
  color: var(--accent);
}
.context-menu-item .icon-svg {
  width: 0.875rem;
  height: 0.875rem;
}

/* Copy control on fenced code blocks. Present but quiet until the block is hovered
   or the button focused, so it never competes with the code it sits on. */
.preview-content pre {
  position: relative;
}
.preview-content .code-copy {
  position: absolute;
  top: var(--space-xs);
  right: var(--space-xs);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: var(--text-muted);
  cursor: pointer;
  opacity: 0;
  transition:
    opacity var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard);
}
.preview-content pre:hover .code-copy,
.preview-content .code-copy:focus-visible {
  opacity: 1;
}
.preview-content .code-copy:hover {
  color: var(--accent);
  border-color: var(--accent);
}
.preview-content .code-copy.done {
  opacity: 1;
  color: var(--save-ok);
  border-color: var(--save-ok);
}
.preview-content .code-copy svg {
  width: 0.875rem;
  height: 0.875rem;
}

/* ─── FOCUS MODE ────────────────────────────────────
   Real fullscreen (Fullscreen API) with both side panes out of the way. The class
   is applied by the fullscreenchange handler, never by the click, so Escape and
   the browser's own exit keep the UI honest. Specificity beats .sidebar's own
   display rule without reaching for !important. */
body.focus-mode .app-container > .sidebar,
body.focus-mode .app-container > .sidebar-resizer,
body.focus-mode .app-container > .center-pane .docked-expand-btn {
  display: none;
}
#btn-focus.active {
  color: var(--accent);
  opacity: 1;
}

/* ─── PRINT ─────────────────────────────────────────
   Print the NOTE, not the application: every pane and control is hidden and the
   rendered preview is promoted to the page, whatever view mode is on screen.
   These rules sit last in the file deliberately — they match the mode-class
   selectors at equal specificity and win by order, so no !important is needed.
   Colour is forced to ink-on-paper because both themes would otherwise print
   their backgrounds. */
@media print {
  body {
    background: none;
  }
  .app-container > .sidebar,
  .app-container > .sidebar-resizer,
  .center-pane > .top-bar,
  .lock-screen,
  .modal-backdrop,
  .context-menu,
  .preview-content .code-copy {
    display: none;
  }

  /* The editor pane and the split handle must be hidden at the SAME specificity as
     the mode rules that show them, or Editor mode wins and prints the raw markdown
     above the rendered note. Equal specificity, later in the file, so order decides. */
  .editor-split.mode-editor .editor-pane,
  .editor-split.mode-preview .editor-pane,
  .editor-split.mode-split-vertical .editor-pane,
  .editor-split.mode-split-horizontal .editor-pane,
  .editor-split.mode-editor .split-handle,
  .editor-split.mode-preview .split-handle,
  .editor-split.mode-split-vertical .split-handle,
  .editor-split.mode-split-horizontal .split-handle {
    display: none;
  }

  .editor-split {
    border-top: none;
  }

  .app-container,
  .center-pane,
  .editor-split.mode-editor,
  .editor-split.mode-preview,
  .editor-split.mode-split-vertical,
  .editor-split.mode-split-horizontal {
    display: block;
    height: auto;
    overflow: visible;
  }
  .editor-split.mode-editor .preview-pane,
  .editor-split.mode-preview .preview-pane,
  .editor-split.mode-split-vertical .preview-pane,
  .editor-split.mode-split-horizontal .preview-pane {
    display: block;
    width: 100%;
    height: auto;
    flex: none;
    overflow: visible;
  }
  .preview-content {
    height: auto;
    overflow: visible;
    padding: 0;
    color: oklch(0.15 0 0);
    background: none;
  }
  .preview-content a {
    color: oklch(0.15 0 0);
    text-decoration: underline;
  }
  .preview-content h1,
  .preview-content h2,
  .preview-content h3 {
    color: oklch(0.15 0 0);
    break-after: avoid;
  }
  .preview-content pre,
  .preview-content blockquote,
  .preview-content table,
  .preview-content img {
    break-inside: avoid;
  }
  .preview-content pre,
  .preview-content code {
    color: oklch(0.15 0 0);
    background: none;
    border: var(--hairline) solid oklch(0.75 0 0);
  }
  .preview-content table th,
  .preview-content table td {
    border: var(--hairline) solid oklch(0.75 0 0);
  }
  .preview-content .task-check {
    border-color: oklch(0.35 0 0);
    background: none;
  }
  .preview-content .task-check.on::after {
    border-color: oklch(0.15 0 0);
  }
}
