joplock/public/styles.css
igor cc0511c007 fix(mobile): phones in landscape keep the mobile layout and clear the notch
A phone in landscape is 812-956px wide, past the 768px breakpoint, so it
got the desktop layout (sidebar and all) in ~390px of height, and every
rotation flipped the shell and reloaded the page.

The mobile shell now also covers a touch device whose PHYSICAL screen
has a short side <= 500px (JS: _isPhoneScreen; CSS: device-width /
device-height clauses on the four former max-width:768px blocks). It
must not use the window height: a soft keyboard shrinks the window (iOS
home-screen apps even shrink innerHeight), which would flip an iPad to
the phone layout and reload it while typing; tests cover that case.

- .mobile-app, the FAB, its menu and the context sheet keep clear of
  env(safe-area-inset-left/right) (landscape notch / Dynamic Island;
  there were no left/right insets anywhere)
- short windows tighten the title bar and toolbar; with the keyboard up
  in landscape the editor's title bar steps aside (not the search header)
- guide: the 'Tablet behavior' paragraph was wrong; replaced with the
  real rule
- joplin-items spec: bound the in-page fetch and the reloads so a stall
  names its step (that test hung to the 90s limit in ~3 of ~25 full runs;
  never reproduced in 11 consecutive attempts)

Unit tests (real iPhone/iPad/Pixel numbers) and Playwright tests for the
landscape phone, the squashed iPad and a short desktop window. Full
mobile and desktop suites pass.
2026-10-13 16:02:56 +13:00

4536 lines
108 KiB
CSS

/* ===== Self-hosted monospace font ===== */
@font-face {
font-family: 'Cascadia Mono';
src: url('/fonts/CascadiaMono-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Cascadia Mono';
src: url('/fonts/CascadiaMono-Bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
/* ===== Theme: Matrix (black & green) ===== */
.theme-matrix {
--bg: #080c08;
--theme-color: #08110b;
--bg-side: #0d140d;
--bg-list: #0b120b;
--bg-editor: #050905;
--bg-elevated: rgba(255,255,255,0.02);
--bg-input: rgba(50,255,112,0.06);
--bg-hover: rgba(50,255,112,0.08);
--bg-active: rgba(50,255,112,0.16);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.25);
--text: #e8fbe8;
--text-dim: #6a9a6a;
--text-muted: #6a9a6a;
--text-heading: #e0ffe0;
--text-on-accent: #041006;
--accent: #32ff70;
--border: rgba(50,255,112,0.12);
--border-focus: rgba(50,255,112,0.4);
--danger: #ff5555;
--toolbar-bg: #0d140d;
--scrollbar: rgba(50,255,112,0.15);
--statusbar-bg: #060a06;
color-scheme: dark;
}
/* ===== Theme: Matrix Blue ===== */
.theme-matrix-blue {
--bg: #06090d;
--theme-color: #071019;
--bg-side: #0b1220;
--bg-list: #09101a;
--bg-editor: #04070b;
--bg-elevated: rgba(255,255,255,0.02);
--bg-input: rgba(84,172,255,0.07);
--bg-hover: rgba(84,172,255,0.09);
--bg-active: rgba(84,172,255,0.17);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.25);
--text: #e6f5ff;
--text-dim: #6b91aa;
--text-muted: #6b91aa;
--text-heading: #dff4ff;
--text-on-accent: #041019;
--accent: #54acff;
--border: rgba(84,172,255,0.14);
--border-focus: rgba(84,172,255,0.42);
--danger: #ff6b6b;
--toolbar-bg: #0b1220;
--scrollbar: rgba(84,172,255,0.18);
--statusbar-bg: #050910;
color-scheme: dark;
}
/* ===== Theme: Matrix Purple ===== */
.theme-matrix-purple {
--bg: #09070d;
--theme-color: #100815;
--bg-side: #130d1d;
--bg-list: #100a18;
--bg-editor: #06040a;
--bg-elevated: rgba(255,255,255,0.02);
--bg-input: rgba(184,92,255,0.07);
--bg-hover: rgba(184,92,255,0.09);
--bg-active: rgba(184,92,255,0.17);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.25);
--text: #f5e9ff;
--text-dim: #9a72b4;
--text-muted: #9a72b4;
--text-heading: #f4e2ff;
--text-on-accent: #14081b;
--accent: #b85cff;
--border: rgba(184,92,255,0.14);
--border-focus: rgba(184,92,255,0.42);
--danger: #ff6b8a;
--toolbar-bg: #130d1d;
--scrollbar: rgba(184,92,255,0.18);
--statusbar-bg: #09060f;
color-scheme: dark;
}
/* ===== Theme: Matrix Amber ===== */
.theme-matrix-amber {
--bg: #0d0a05;
--theme-color: #130d06;
--bg-side: #1a1309;
--bg-list: #151007;
--bg-editor: #090602;
--bg-elevated: rgba(255,255,255,0.02);
--bg-input: rgba(255,191,64,0.07);
--bg-hover: rgba(255,191,64,0.09);
--bg-active: rgba(255,191,64,0.17);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.25);
--text: #fff5dd;
--text-dim: #b39355;
--text-muted: #b39355;
--text-heading: #ffefc7;
--text-on-accent: #171002;
--accent: #ffbf40;
--border: rgba(255,191,64,0.14);
--border-focus: rgba(255,191,64,0.42);
--danger: #ff7a45;
--toolbar-bg: #1a1309;
--scrollbar: rgba(255,191,64,0.18);
--statusbar-bg: #0c0803;
color-scheme: dark;
}
/* ===== Theme: Matrix Orange ===== */
.theme-matrix-orange {
--bg: #0d0805;
--theme-color: #140a06;
--bg-side: #1b1009;
--bg-list: #160d07;
--bg-editor: #090502;
--bg-elevated: rgba(255,255,255,0.02);
--bg-input: rgba(255,138,61,0.07);
--bg-hover: rgba(255,138,61,0.09);
--bg-active: rgba(255,138,61,0.17);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.25);
--text: #fff0e6;
--text-dim: #b98465;
--text-muted: #b98465;
--text-heading: #ffe4d1;
--text-on-accent: #180c05;
--accent: #ff8a3d;
--border: rgba(255,138,61,0.14);
--border-focus: rgba(255,138,61,0.42);
--danger: #ff6b5e;
--toolbar-bg: #1b1009;
--scrollbar: rgba(255,138,61,0.18);
--statusbar-bg: #0c0703;
color-scheme: dark;
}
/* ===== Theme: Dark Grey ===== */
.theme-dark-grey {
--bg: #090909;
--theme-color: #0b0b0b;
--bg-side: #141414;
--bg-list: #101010;
--bg-editor: #060606;
--bg-elevated: rgba(255,255,255,0.03);
--bg-input: rgba(255,255,255,0.06);
--bg-hover: rgba(255,255,255,0.08);
--bg-active: rgba(255,255,255,0.14);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.25);
--text: #ededed;
--text-dim: #9a9a9a;
--text-muted: #8d8d8d;
--text-heading: #f6f6f6;
--text-on-accent: #101010;
--accent: #b8b8b8;
--border: rgba(255,255,255,0.12);
--border-focus: rgba(255,255,255,0.35);
--danger: #ff6b6b;
--toolbar-bg: #121212;
--scrollbar: rgba(255,255,255,0.15);
--statusbar-bg: #070707;
color-scheme: dark;
}
/* ===== Theme: Grey ===== */
.theme-grey {
--bg: #222222;
--theme-color: #0d0d0d;
--bg-side: #0d0d0d;
--bg-list: #0d0d0d;
--bg-editor: #222222;
--bg-elevated: rgba(255,255,255,0.05);
--bg-input: rgba(255,255,255,0.06);
--bg-hover: rgba(255,255,255,0.08);
--bg-active: rgba(255,255,255,0.12);
--overlay: rgba(0,0,0,0.5);
--shadow: rgba(0,0,0,0.3);
--text: #e0e0e0;
--text-dim: #8a8a8a;
--text-muted: #7a7a7a;
--text-heading: #ffffff;
--text-on-accent: #ffffff;
--accent: #4a6572;
--border: rgba(255,255,255,0.10);
--border-focus: rgba(255,255,255,0.30);
--danger: #ef5350;
--toolbar-bg: #222222;
--scrollbar: rgba(255,255,255,0.12);
--statusbar-bg: #0d0d0d;
color-scheme: dark;
}
/* ===== Theme: Fruit (Apple Notes) ===== */
.theme-fruit {
--bg: #f5f5f0;
--theme-color: #f5f5f0;
--bg-side: #f0f0eb;
--bg-list: #ffffff;
--bg-editor: #ffffff;
--bg-elevated: rgba(0,0,0,0.03);
--bg-input: rgba(0,0,0,0.04);
--bg-hover: rgba(0,0,0,0.04);
--bg-active: rgba(0,0,0,0.06);
--overlay: rgba(0,0,0,0.2);
--shadow: rgba(0,0,0,0.08);
--text: #1c1c1e;
--text-dim: #6e6e73;
--text-muted: #8e8e93;
--text-heading: #000000;
--text-on-accent: #ffffff;
--accent: #c8a02e;
--border: rgba(0,0,0,0.08);
--border-focus: rgba(0,0,0,0.20);
--danger: #ff3b30;
--toolbar-bg: #f0f0eb;
--scrollbar: rgba(0,0,0,0.12);
--statusbar-bg: #e8e8e3;
color-scheme: light;
}
/* ===== Theme: Dark Fruit (Apple Notes dark) ===== */
.theme-dark-fruit {
--bg: #000000;
--theme-color: #000000;
--bg-side: #1c1c1e;
--bg-list: #2c2c2e;
--bg-editor: #000000;
--bg-elevated: rgba(255,255,255,0.05);
--bg-input: rgba(255,255,255,0.06);
--bg-hover: rgba(255,255,255,0.06);
--bg-active: rgba(255,255,255,0.10);
--overlay: rgba(0,0,0,0.5);
--shadow: rgba(0,0,0,0.4);
--text: #e5e5e5;
--text-dim: #8e8e93;
--text-muted: #6e6e73;
--text-heading: #ffffff;
--text-on-accent: #000000;
--accent: #c8a02e;
--border: rgba(255,255,255,0.08);
--border-focus: rgba(255,255,255,0.25);
--danger: #ff453a;
--toolbar-bg: #1c1c1e;
--scrollbar: rgba(255,255,255,0.12);
--statusbar-bg: #000000;
color-scheme: dark;
}
/* ===== Theme: Dark Red ===== */
.theme-dark-red {
--bg: #0b0607;
--theme-color: #0d0708;
--bg-side: #170d0e;
--bg-list: #130b0c;
--bg-editor: #080505;
--bg-elevated: rgba(255,255,255,0.03);
--bg-input: rgba(220,80,70,0.08);
--bg-hover: rgba(220,80,70,0.10);
--bg-active: rgba(220,80,70,0.18);
--overlay: rgba(0,0,0,0.5);
--shadow: rgba(0,0,0,0.3);
--text: #f0e0dc;
--text-dim: #b07070;
--text-muted: #966060;
--text-heading: #ffe4e0;
--text-on-accent: #1a0808;
--accent: #e05555;
--border: rgba(220,80,70,0.16);
--border-focus: rgba(220,80,70,0.40);
--danger: #ff6b6b;
--toolbar-bg: #150d0d;
--scrollbar: rgba(220,80,70,0.18);
--statusbar-bg: #0b0606;
color-scheme: dark;
}
/* ===== Theme: Dark (blue-gray) ===== */
.theme-dark {
--bg: #1d2024;
--theme-color: #1d2024;
--bg-side: #263238;
--bg-list: #2c3540;
--bg-editor: #1d2024;
--bg-elevated: rgba(255,255,255,0.02);
--bg-input: rgba(255,255,255,0.06);
--bg-hover: rgba(255,255,255,0.06);
--bg-active: rgba(100,149,237,0.25);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.25);
--text: #cdd8e0;
--text-dim: #8a9baa;
--text-muted: #8a9baa;
--text-heading: #e0e8f0;
--text-on-accent: #ffffff;
--accent: #6c9eff;
--border: rgba(255,255,255,0.08);
--border-focus: rgba(100,149,237,0.5);
--danger: #ff5555;
--toolbar-bg: #263238;
--scrollbar: rgba(255,255,255,0.1);
--statusbar-bg: #1a1e22;
color-scheme: dark;
}
/* ===== Theme: Light ===== */
.theme-light {
--bg: #ffffff;
--theme-color: #f0f4f8;
--bg-side: #f0f4f8;
--bg-list: #ffffff;
--bg-editor: #ffffff;
--bg-elevated: rgba(0,0,0,0.03);
--bg-input: rgba(0,0,0,0.04);
--bg-hover: rgba(0,0,0,0.04);
--bg-active: rgba(100,149,237,0.15);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.18);
--text: #32363a;
--text-dim: #6c757d;
--text-muted: #6c757d;
--text-heading: #1d2024;
--text-on-accent: #ffffff;
--accent: #0066cc;
--border: rgba(0,0,0,0.09);
--border-focus: rgba(0,102,204,0.4);
--danger: #dc3545;
--toolbar-bg: #f7f7f7;
--scrollbar: rgba(0,0,0,0.12);
--statusbar-bg: #e8ecf0;
color-scheme: light;
}
/* ===== Theme: Joplin OLED Dark ===== */
.theme-oled-dark {
--bg: #000000;
--theme-color: #000000;
--bg-side: #0f2051;
--bg-list: #000000;
--bg-editor: #000000;
--bg-elevated: rgba(255,255,255,0.02);
--bg-input: rgba(255,255,255,0.06);
--bg-hover: rgba(255,255,255,0.06);
--bg-active: rgba(120,139,195,0.22);
--overlay: rgba(0,0,0,0.55);
--shadow: rgba(0,0,0,0.35);
--text: #dddddd;
--text-dim: #777777;
--text-muted: #777777;
--text-heading: #ffffff;
--text-on-accent: #ffffff;
--accent: #788bc3;
--border: #3d444e;
--border-focus: #788bc3;
--danger: #ff4444;
--toolbar-bg: #0f2051;
--scrollbar: rgba(255,255,255,0.12);
--statusbar-bg: #000000;
color-scheme: dark;
}
/* ===== Theme: Joplin Solarized Light ===== */
.theme-solarized-light {
--bg: #fdf6e3;
--theme-color: #fdf6e3;
--bg-side: #002b36;
--bg-list: #fdf6e3;
--bg-editor: #fdf6e3;
--bg-elevated: #eee8d5;
--bg-input: rgba(0,43,54,0.06);
--bg-hover: rgba(38,139,210,0.08);
--bg-active: #eee8d5;
--overlay: rgba(0,43,54,0.35);
--shadow: rgba(0,43,54,0.18);
--text: #657b83;
--text-dim: #839496;
--text-muted: #839496;
--text-heading: #073642;
--text-on-accent: #ffffff;
--accent: #268bd2;
--border: #eee8d5;
--border-focus: #268bd2;
--danger: #dc322f;
--toolbar-bg: #eee8d5;
--scrollbar: rgba(101,123,131,0.18);
--statusbar-bg: #eee8d5;
color-scheme: light;
}
/* ===== Theme: Joplin Solarized Dark ===== */
.theme-solarized-dark {
--bg: #002b36;
--theme-color: #002b36;
--bg-side: #073642;
--bg-list: #002b36;
--bg-editor: #002b36;
--bg-elevated: #073642;
--bg-input: rgba(147,161,161,0.08);
--bg-hover: rgba(42,161,152,0.14);
--bg-active: #073642;
--overlay: rgba(0,43,54,0.55);
--shadow: rgba(0,0,0,0.28);
--text: #839496;
--text-dim: #657b83;
--text-muted: #657b83;
--text-heading: #93a1a1;
--text-on-accent: #002b36;
--accent: #268bd2;
--border: #586e75;
--border-focus: #2aa198;
--danger: #dc322f;
--toolbar-bg: #073642;
--scrollbar: rgba(131,148,150,0.18);
--statusbar-bg: #012732;
color-scheme: dark;
}
/* ===== Theme: Joplin Nord ===== */
.theme-nord {
--bg: #2e3440;
--theme-color: #2e3440;
--bg-side: #434c5e;
--bg-list: #2e3440;
--bg-editor: #2e3440;
--bg-elevated: #434c5e;
--bg-input: rgba(216,222,233,0.08);
--bg-hover: rgba(129,161,193,0.12);
--bg-active: #81a1c1;
--overlay: rgba(46,52,64,0.55);
--shadow: rgba(46,52,64,0.32);
--text: #e5e9f0;
--text-dim: #d8dee9;
--text-muted: #d8dee9;
--text-heading: #eceff4;
--text-on-accent: #2e3440;
--accent: #88c0d0;
--border: rgba(129,161,193,0.20);
--border-focus: #81a1c1;
--danger: #bf616a;
--toolbar-bg: #3b4252;
--scrollbar: rgba(216,222,233,0.18);
--statusbar-bg: #3b4252;
color-scheme: dark;
}
/* ===== Theme: Joplin Dracula ===== */
.theme-dracula {
--bg: #282a36;
--theme-color: #282a36;
--bg-side: #21222c;
--bg-list: #282a36;
--bg-editor: #282a36;
--bg-elevated: #44475a;
--bg-input: rgba(248,248,242,0.06);
--bg-hover: rgba(189,147,249,0.12);
--bg-active: #44475a;
--overlay: rgba(40,42,54,0.55);
--shadow: rgba(0,0,0,0.3);
--text: #f8f8f2;
--text-dim: #6272a4;
--text-muted: #6272a4;
--text-heading: #f8f8f2;
--text-on-accent: #282a36;
--accent: #8be9fd;
--border: rgba(189,147,249,0.18);
--border-focus: #bd93f9;
--danger: #ff5555;
--toolbar-bg: #21222c;
--scrollbar: rgba(248,248,242,0.18);
--statusbar-bg: #21222c;
color-scheme: dark;
}
/* ===== Theme: Swamp Thing ===== */
.theme-swamp-thing {
--bg: #1a1e1a;
--theme-color: #1a1e1a;
--bg-side: #141814;
--bg-list: #1a1e1a;
--bg-editor: #1a1e1a;
--bg-elevated: #2a332a;
--bg-input: rgba(105,255,148,0.06);
--bg-hover: rgba(105,255,148,0.12);
--bg-active: #2a332a;
--overlay: rgba(26,30,26,0.55);
--shadow: rgba(0,0,0,0.3);
--text: #f0f5f0;
--text-dim: #627a64;
--text-muted: #627a64;
--text-heading: #f0f5f0;
--text-on-accent: #1a1e1a;
--accent: #69ff94;
--border: rgba(105,255,148,0.12);
--border-focus: rgba(105,255,148,0.40);
--danger: #ff5555;
--toolbar-bg: #141814;
--scrollbar: rgba(240,245,240,0.18);
--statusbar-bg: #141814;
color-scheme: dark;
}
/* ===== Theme: Fireball ===== */
.theme-fireball {
--bg: #1e1a16;
--theme-color: #1e1a16;
--bg-side: #181410;
--bg-list: #1e1a16;
--bg-editor: #1e1a16;
--bg-elevated: #332820;
--bg-input: rgba(255,140,40,0.07);
--bg-hover: rgba(255,140,40,0.12);
--bg-active: #332820;
--overlay: rgba(30,26,22,0.55);
--shadow: rgba(0,0,0,0.3);
--text: #f5f0eb;
--text-dim: #807060;
--text-muted: #807060;
--text-heading: #f5f0eb;
--text-on-accent: #1e1a16;
--accent: #ff8c28;
--border: rgba(255,140,40,0.14);
--border-focus: rgba(255,140,40,0.42);
--danger: #ff5555;
--toolbar-bg: #181410;
--scrollbar: rgba(245,240,235,0.18);
--statusbar-bg: #181410;
color-scheme: dark;
}
/* ===== Theme: Joplin Aritim Dark ===== */
.theme-aritim-dark {
--bg: #10151a;
--theme-color: #10151a;
--bg-side: #141a21;
--bg-list: #141a21;
--bg-editor: #10151a;
--bg-elevated: #141a21;
--bg-input: rgba(211,218,227,0.06);
--bg-hover: rgba(43,82,120,0.12);
--bg-active: #2b5278;
--overlay: rgba(16,21,26,0.58);
--shadow: rgba(0,0,0,0.34);
--text: #d3dae3;
--text-dim: #666a73;
--text-muted: #666a73;
--text-heading: #d3dae3;
--text-on-accent: #d3dae3;
--accent: #5a95c5;
--border: #141a21;
--border-focus: #2b5278;
--danger: #d66500;
--toolbar-bg: #141a21;
--scrollbar: rgba(211,218,227,0.16);
--statusbar-bg: #141a21;
color-scheme: dark;
}
/* ===== Theme: Earth ===== */
.theme-earth {
--bg: #1a1610;
--theme-color: #1e1a12;
--bg-side: #262018;
--bg-list: #221e16;
--bg-editor: #161310;
--bg-elevated: rgba(255,255,255,0.03);
--bg-input: rgba(180,150,90,0.08);
--bg-hover: rgba(180,150,90,0.10);
--bg-active: rgba(180,150,90,0.18);
--overlay: rgba(0,0,0,0.45);
--shadow: rgba(0,0,0,0.30);
--text: #e8dcc8;
--text-dim: #9a8b6e;
--text-muted: #8a7b5e;
--text-heading: #f0e8d8;
--text-on-accent: #1a1408;
--accent: #b4964a;
--border: rgba(180,150,90,0.14);
--border-focus: rgba(180,150,90,0.40);
--danger: #c46040;
--toolbar-bg: #262018;
--scrollbar: rgba(180,150,90,0.18);
--statusbar-bg: #141210;
color-scheme: dark;
}
/* ===== Reset ===== */
*,*::before,*::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
html.mobile-no-page-scroll,
body.mobile-no-page-scroll {
overflow: hidden !important;
height: 100dvh;
}
body {
--font-size-note: 15px;
--font-size-markdown: 14px;
--font-size-code: 12px;
--statusbar-height: 28px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
font-size: 13px;
line-height: 1.4;
color: var(--text);
background: var(--bg);
}
body.app-shell {
display: flex;
flex-direction: column;
min-height: 100vh;
min-height: 100dvh;
overflow: hidden;
}
/* While mobile shell editor is active, freeze outer page scrolling so only the
editor content scrolls. This avoids dual-scroll behavior on iOS Safari. */
body.mobile-shell-active {
overscroll-behavior: none;
overflow: hidden;
position: fixed;
inset: 0;
width: 100%;
}
body.note-body-monospace,
body.note-body-monospace .editor-preview {
font-family: 'Cascadia Mono','SF Mono',Consolas,'Liberation Mono',Menlo,monospace;
}
.editor-preview {
font-family: var(--font-family-note, inherit);
}
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; }
/* ===== 3-Column App Layout ===== */
.app {
display: flex;
flex: 1;
min-height: 0;
overflow: hidden;
}
.mobile-nav-backdrop { display: none; }
.nav-toggle-btn {
display: inline-flex;
width: 30px;
height: 30px;
align-items: center;
justify-content: center;
border-radius: 0;
background: transparent;
border: 1px solid var(--border);
color: var(--text);
font-size: 16px;
cursor: pointer;
flex-shrink: 0;
}
.nav-reopen-btn {
display: none;
position: absolute;
left: 6px;
top: 6px;
width: 30px;
height: 30px;
align-items: center;
justify-content: center;
border-radius: 0;
background: var(--bg-side);
border: 1px solid var(--border);
color: var(--text);
font-size: 16px;
cursor: pointer;
z-index: 5;
}
body.nav-collapsed .col-nav { display: none; }
body.nav-collapsed .nav-reopen-btn { display: inline-flex; }
body.nav-collapsed .editor-titlebar { padding-left: 42px; }
.col-nav {
display: flex;
flex-direction: column;
width: 320px;
min-width: 320px;
background: var(--bg-side);
border-right: 1px solid var(--border);
min-width: 0;
height: 100%;
}
.nav-panel-header {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 10px;
height: 44px;
box-sizing: border-box;
border-bottom: 1px solid var(--border);
background: var(--bg-side);
flex-shrink: 0;
}
.nav-panel-header .btn { padding: 4px 6px; }
.nav-search-form {
display: flex;
align-items: center;
gap: 6px;
flex: 1;
}
.nav-items {
flex: 1;
overflow-y: auto;
padding: 6px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-elevated);
}
.nav-folder {
margin-bottom: 2px;
border: 0;
border-radius: 0;
overflow: visible;
background: transparent;
}
.nav-folder.active {
background: var(--bg-active);
}
.nav-folder-row {
display: flex;
align-items: center;
gap: 6px;
padding: 7px 8px;
cursor: pointer;
}
/* Nested notebooks: each level indents by 14px (capped server-side at 8
* levels via --nav-depth). Every collapse/expand rule below uses the child
* combinator, because a descendant selector would let a collapsed child's
* state leak into an expanded parent (and vice versa). */
.nav-folder > .nav-folder-row {
padding-left: calc(8px + var(--nav-depth, 0) * 14px);
}
.nav-folder-children { display: block; }
/* Pinned notebooks: a small pin before the title (sidebar) / after it (mobile). */
.nav-pin-icon,
.mobile-pin-icon {
display: inline-flex;
flex-shrink: 0;
width: 12px;
height: 12px;
color: var(--accent);
opacity: 0.85;
}
.nav-pin-icon svg,
.mobile-pin-icon svg { width: 100%; height: 100%; }
.nav-pin-icon { margin-right: 2px; }
.mobile-pin-icon { width: 14px; height: 14px; }
/* Notebook order switch: shows the CURRENT order; <body data-folder-sort> decides which label. */
.sort-on-recent { display: none; }
body[data-folder-sort="recent"] .sort-on-alpha { display: none; }
body[data-folder-sort="recent"] .sort-on-recent { display: inline; }
/* The header is a fixed-width flex row: let the search box shrink so the switch and the "+" always fit. */
.nav-search-form { min-width: 0; }
.nav-search-form .notelist-search { min-width: 0; flex: 1 1 auto; }
.nav-sort-btn { flex-shrink: 0; min-width: 40px; font-size: 11px; padding-left: 5px; padding-right: 5px; white-space: nowrap; }
.mobile-sort-btn { font-size: 13px; font-weight: 600; min-width: 44px; }
/* Drag a notebook onto another to nest it (desktop). */
.nav-folder.nav-dragging > .nav-folder-row { opacity: 0.45; }
.nav-folder-row.nav-drop-target {
background: color-mix(in srgb, var(--accent) 22%, transparent);
outline: 2px solid var(--accent);
outline-offset: -2px;
}
.nav-drop-root {
display: none;
margin: 4px 8px 6px;
padding: 8px;
border: 1px dashed var(--border-focus, var(--accent));
border-radius: 4px;
font-size: 12px;
text-align: center;
color: var(--text-dim);
}
body.nav-dragging-folder.nav-drag-nested .nav-drop-root { display: block; }
.nav-drop-root.nav-drop-active {
border-style: solid;
background: color-mix(in srgb, var(--accent) 22%, transparent);
color: var(--text);
}
.nav-folder.collapsed > .nav-folder-children { display: none; }
.nav-folder-toggle {
width: 18px;
height: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--text-dim);
font-size: 14px;
transition: transform 0.12s;
flex-shrink: 0;
transform: rotate(90deg);
}
.nav-folder-toggle-placeholder { visibility: hidden; }
.nav-folder.collapsed > .nav-folder-row > .nav-folder-toggle { transform: rotate(0deg); }
.nav-folder-title {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 14px;
font-weight: 600;
color: var(--accent);
}
.nav-share-icon {
font-size: 14px;
margin-right: 4px;
opacity: 0.7;
}
.theme-matrix .nav-folder-title,
.theme-matrix .sidebar-item-name {
color: #7ee787;
}
:is(.theme-matrix, .theme-matrix-blue, .theme-matrix-purple, .theme-matrix-amber, .theme-matrix-orange) .notelist-item-title,
:is(.theme-matrix, .theme-matrix-blue, .theme-matrix-purple, .theme-matrix-amber, .theme-matrix-orange) .nav-folder .sidebar-item-icon,
:is(.theme-matrix, .theme-matrix-blue, .theme-matrix-purple, .theme-matrix-amber, .theme-matrix-orange) .sidebar-item-icon {
color: #e0ffe0;
}
.nav-folder .sidebar-item-icon {
font-size: 14px;
width: 18px;
height: 18px;
color: currentColor;
}
.nav-folder-add {
flex-shrink: 0;
width: 20px;
height: 20px;
font-size: 14px;
}
.nav-folder-notes {
padding: 0 0 4px;
border-top: 0;
}
.nav-folder.collapsed > .nav-folder-notes { display: none; }
.nav-folder-notes .notelist-item {
padding: 7px 10px 7px calc(34px + var(--nav-depth, 0) * 14px);
border-bottom: none;
background: transparent;
}
.folder-context-menu {
position: fixed;
z-index: 40;
min-width: 160px;
padding: 4px;
border: 1px solid var(--border);
border-radius: 0;
/* It floats over the sidebar AND the editor, so it must be opaque. --bg-elevated alone is
* a ~2% tint in most themes (see-through); lay it over the solid sidebar colour so the
* theme's look is kept without letting the content behind show through. */
background-color: var(--bg-side);
background-image: linear-gradient(var(--bg-elevated), var(--bg-elevated));
box-shadow: 0 10px 30px var(--shadow);
/* a very short window: scroll the menu instead of letting items fall off the screen */
max-height: calc(100vh - 16px);
max-height: calc(100dvh - 16px);
overflow-y: auto;
}
.folder-context-menu[hidden],
.folder-modal-backdrop[hidden],
.folder-modal[hidden],
.history-modal[hidden] {
display: none;
}
.folder-context-item {
display: block;
width: 100%;
padding: 8px 10px;
border-radius: 0;
text-align: left;
color: var(--text);
}
@media (hover: hover) {
.folder-context-item:hover {
background: var(--bg-hover);
}
}
/* display:block above beats the UA [hidden] rule; vault notebooks hide the
* "New sub-notebook" / "Move" entries with it. */
.folder-context-item[hidden],
.mobile-ctx-btn[hidden] { display: none; }
/* Notebook pickers (new notebook "Inside", move "Move into") */
.folder-parent-label {
display: block;
margin: 0.75rem 0 0.25rem;
font-size: 12px;
color: var(--text-muted);
}
.folder-parent-select {
width: 100%;
max-width: 100%;
text-overflow: ellipsis;
}
.folder-parent-select option:disabled { color: var(--text-muted); }
.folder-context-item.danger {
color: var(--danger);
}
.folder-modal-backdrop {
position: fixed;
inset: 0;
background: var(--overlay);
z-index: 1000;
}
.folder-modal {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
z-index: 1001;
}
.folder-modal-card {
display: grid;
gap: 12px;
width: min(360px, 100%);
padding: 16px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
box-shadow: 0 10px 30px var(--shadow);
}
.folder-modal-title {
margin: 0;
font-size: 16px;
color: var(--text-heading);
}
.folder-modal-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
/* ===== Upload Modal ===== */
.upload-modal-card {
width: min(440px, 100%);
gap: 14px;
padding: 18px;
}
.upload-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.upload-close-btn {
font-size: 18px;
padding: 2px 6px;
line-height: 1;
border-radius: 0;
color: var(--text-dim);
background: transparent;
border: none;
cursor: pointer;
}
@media (hover: hover) {
.upload-close-btn:hover { color: var(--text); background: var(--bg-hover); }
}
.upload-drop-zone {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 24px 16px;
border: 2px dashed var(--border);
border-radius: 0;
text-align: center;
transition: border-color 0.15s, background 0.15s;
background: var(--bg);
}
.upload-drop-zone.drag-over {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, var(--bg));
}
.upload-drop-icon {
font-size: 32px;
line-height: 1;
opacity: 0.7;
}
.upload-drop-text {
margin: 0;
font-size: 14px;
color: var(--text-dim);
}
.upload-drop-or {
margin: 0;
font-size: 12px;
color: var(--text-dim);
opacity: 0.6;
}
.upload-file-list {
display: flex;
flex-direction: column;
gap: 6px;
max-height: 180px;
overflow-y: auto;
}
.upload-file-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 0;
background: var(--bg);
border: 1px solid var(--border);
transition: background 0.15s;
}
.upload-file-item.done { border-color: var(--accent); }
.upload-file-item.error { border-color: var(--danger); opacity: 0.8; }
.upload-file-name {
flex: 1;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text);
}
.upload-file-size {
font-size: 11px;
color: var(--text-dim);
flex-shrink: 0;
}
.upload-file-status {
font-size: 11px;
font-weight: 600;
flex-shrink: 0;
min-width: 48px;
text-align: right;
}
.upload-file-status.ok { color: var(--accent); }
.upload-file-status.err { color: var(--danger); }
.upload-progress-bar {
width: 100%;
height: 3px;
border-radius: 0;
background: var(--border);
overflow: hidden;
margin-top: 4px;
}
.upload-progress-bar-fill {
height: 100%;
background: var(--accent);
transition: width 0.2s;
border-radius: 0;
}
.upload-file-del {
flex-shrink: 0;
width: 22px;
height: 22px;
padding: 0;
border: none;
border-radius: 0;
background: transparent;
color: var(--text-dim);
font-size: 16px;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
@media (hover: hover) {
.upload-file-del:hover { color: var(--danger); background: var(--bg-hover); }
}
.trash-folder-empty {
flex-shrink: 0;
color: var(--danger);
}
.empty-trash-warning {
margin: 0;
line-height: 1.45;
}
/* ===== Code Block Modal ===== */
/* ===== Code Modal (full-screen panel) ===== */
.code-modal-panel[hidden] { display: none; }
.code-modal-panel {
position: fixed;
inset: 0;
z-index: 50;
display: flex;
align-items: stretch;
justify-content: center;
background: var(--bg);
padding: 24px;
gap: 0;
}
.code-modal-inner {
display: flex;
flex-direction: column;
flex: 1;
max-width: 960px;
padding: 20px;
gap: 12px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
box-shadow: 0 18px 40px var(--shadow);
}
.code-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.code-modal-title {
margin: 0;
font-size: 16px;
color: var(--text-heading);
}
.code-lang-select {
width: auto;
min-width: 140px;
padding: 4px 8px;
font-size: 13px;
}
.code-input {
flex: 1;
min-height: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-editor);
overflow: hidden;
}
.code-input .cm-editor {
height: 100%;
}
.code-input .cm-scroller {
overflow: auto;
}
.code-modal-actions {
display: flex;
gap: 8px;
justify-content: flex-end;
}
/* ===== History Modal ===== */
.history-modal {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
z-index: 1001;
}
.history-modal-card {
display: flex;
flex-direction: column;
width: min(820px, 100%);
height: min(520px, 85vh);
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
box-shadow: 0 10px 40px var(--shadow);
overflow: hidden;
}
.history-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.history-modal-header .folder-modal-title {
margin: 0;
}
.history-close-btn {
font-size: 14px;
line-height: 1;
}
#history-modal-inner {
display: contents;
}
.history-body {
display: grid;
grid-template-columns: 200px 1fr;
flex: 1;
min-height: 0;
overflow: hidden;
}
.history-list {
overflow-y: auto;
border-right: 1px solid var(--border);
padding: 4px 0;
}
.history-item {
display: flex;
flex-direction: column;
width: 100%;
padding: 8px 12px;
text-align: left;
font-size: 11px;
color: var(--text-dim);
border-bottom: 1px solid var(--border);
gap: 2px;
}
@media (hover: hover) {
.history-item:hover { background: var(--bg-hover); color: var(--text); }
}
.history-item-active { background: var(--bg-active); color: var(--text); }
.history-item-title {
font-size: 10px;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.history-preview {
overflow-y: auto;
background: var(--bg-editor);
}
.history-snapshot-content {
height: 100%;
}
.history-snapshot-body {
margin: 0;
padding: 12px 16px;
font-size: 12px;
font-family: 'Cascadia Mono', monospace;
color: var(--text);
white-space: pre-wrap;
word-break: break-word;
line-height: 1.6;
}
.history-actions {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border-top: 1px solid var(--border);
flex-shrink: 0;
}
.history-selected-label {
flex: 1;
font-size: 11px;
color: var(--text-muted);
}
.history-empty,
.history-loading {
padding: 24px;
font-size: 12px;
color: var(--text-muted);
text-align: center;
}
.nav-empty {
padding: 6px 10px 8px 34px;
font-size: 11px;
}
.notelist-load-more {
display: block;
width: 100%;
padding: 6px 10px 6px 34px;
font-size: 11px;
color: var(--text-muted);
background: none;
border: none;
text-align: left;
cursor: pointer;
font-family: inherit;
}
@media (hover: hover) {
.notelist-load-more:hover { color: var(--text-primary); background: var(--bg-hover); }
}
.btn-icon-sm {
width: 22px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
font-size: 16px;
font-weight: 600;
color: var(--text-dim);
transition: background 0.1s;
}
@media (hover: hover) {
.btn-icon-sm:hover { background: var(--bg-hover); color: var(--text); }
}
/* Sidebar items */
.sidebar-item {
display: flex;
align-items: center;
gap: 6px;
width: 100%;
padding: 5px 8px;
border-radius: 0;
text-align: left;
transition: background 0.1s;
margin-bottom: 1px;
}
@media (hover: hover) {
.sidebar-item:hover { background: var(--bg-hover); }
}
.sidebar-item.active { background: var(--bg-active); }
.sidebar-item-icon {
font-size: 14px;
flex-shrink: 0;
width: 20px;
height: 20px;
text-align: center;
display: inline-flex;
align-items: center;
justify-content: center;
color: currentColor;
}
.folder-outline-icon {
width: 20px;
height: 20px;
display: block;
}
.sidebar-item-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--accent);
}
.sidebar-item-count {
font-size: 11px;
color: var(--text-dim);
flex-shrink: 0;
min-width: 16px;
text-align: right;
}
.notelist-header {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 10px;
height: 44px;
box-sizing: border-box;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.notelist-search {
flex: 1;
padding: 5px 8px;
height: 28px;
box-sizing: border-box;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-input);
outline: none;
font-size: 12px;
}
.notelist-search:focus { border-color: var(--border-focus); }
.nav-search-btn {
flex-shrink: 0;
border: 1px solid var(--border);
background: var(--bg-input);
}
.nav-search-clear {
flex-shrink: 0;
border: 1px solid var(--border);
background: var(--bg-input);
color: var(--text-muted);
cursor: pointer;
font-size: 0.85em;
}
.notelist-items {
overflow-y: auto;
flex: 1;
}
@media (hover: hover) {
.notelist-item:hover { background: var(--bg-hover); }
}
.notelist-item.active { background: var(--bg-active); }
.notelist-item-title {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text);
min-width: 0;
flex: 1;
}
/* Column 3: Editor */
.col-editor {
flex: 1;
min-width: 0;
background: var(--bg-editor);
display: flex;
flex-direction: column;
overflow: hidden;
}
.editor-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: var(--text-dim);
}
.editor-form {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
/* Read-only editor: dim toolbar + title, block caret + selection so it is
* clear the note cannot be edited. TinyMCE + CM6 also have their own
* contenteditable=false / mode=readonly applied by _applyFormReadonly(). */
.editor-form.editor-readonly .editor-toolbar { opacity: 0.5; pointer-events: none; }
.editor-form.editor-readonly .editor-title { opacity: 0.75; cursor: default; caret-color: transparent; }
.editor-form.editor-readonly .editor-folder-select { opacity: 0.6; cursor: not-allowed; }
.editor-form.editor-readonly .cm-content { caret-color: transparent; }
/* HTML notes (Joplin markup_language 2): rendered, read-only. No editing chrome,
* no markdown/rendered switch (there is only the rendered view). */
.editor-form[data-html-note="1"] #markdown-toggle,
.editor-form[data-html-note="1"] #preview-toggle,
.editor-form[data-html-note="1"] #undo-save-btn,
.editor-form[data-html-note="1"] .editor-toolbar,
.active-html-note #mobile-md-toggle,
.active-html-note #mobile-preview-toggle { display: none !important; }
.editor-form[data-html-note="1"] .editor-title { opacity: 0.85; cursor: default; caret-color: transparent; }
/* Joplin end-to-end encrypted note: locked placeholder only (no form). */
.editor-e2ee {
flex-direction: column;
gap: 10px;
text-align: center;
padding: 40px 20px;
}
.editor-e2ee-hint { font-size: 13px; color: var(--text-muted); }
.notelist-item-e2ee .notelist-item-title,
.mobile-note-row-e2ee .mobile-note-title { opacity: 0.75; font-style: italic; }
.share-readonly-banner {
background: var(--accent);
color: var(--bg);
padding: 4px 12px;
font-size: 12px;
font-weight: 600;
text-align: center;
letter-spacing: 0.5px;
}
.editor-titlebar {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 16px;
height: 44px;
box-sizing: border-box;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.editor-title {
flex: 1;
padding: 0 0;
border: none;
background: transparent;
font-size: 16px;
font-weight: 700;
color: var(--text-heading);
outline: none;
line-height: 28px;
min-height: 28px;
}
.editor-title:empty::before {
content: attr(data-placeholder);
color: var(--text-muted);
pointer-events: none;
}
.editor-folder-select {
padding: 3px 6px;
height: 28px;
box-sizing: border-box;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
color: var(--text);
font-size: 12px;
max-width: 160px;
outline: none;
cursor: pointer;
}
.editor-folder-select:focus { border-color: var(--accent); }
.editor-folder-arrow {
color: var(--text-dim);
font-size: 14px;
margin: 0 2px;
}
/* Toolbar */
.editor-toolbar {
display: none;
align-items: center;
gap: 1px;
padding: 2px 12px 4px;
border-bottom: 1px solid var(--border);
background: color-mix(in srgb, var(--accent) 10%, var(--bg));
flex-shrink: 0;
flex-wrap: wrap;
}
/* Legacy custom toolbar is only used for markdown mode.
Rich mode uses TinyMCE's built-in toolbar on both desktop and mobile. */
body.editor-rich-mode .editor-toolbar {
display: none;
}
body.editor-markdown-mode .editor-toolbar {
display: flex;
}
.tb {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 28px;
height: 26px;
padding: 0 5px;
border-radius: 3px;
font-size: 13px;
color: var(--text-dim);
transition: background 0.1s, color 0.1s;
}
@media (hover: hover) {
.tb:hover { background: var(--bg-hover); color: var(--text); }
}
.tb:focus { outline: none; }
.tb-div {
width: 1px;
height: 16px;
background: var(--border);
margin: 0 4px;
}
/* Export menu */
.export-menu {
position: fixed;
z-index: 500;
min-width: 160px;
background: var(--bg-editor);
border: 1px solid var(--border);
border-radius: 0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
display: none;
flex-direction: column;
padding: 4px;
}
.export-menu:not([hidden]) { display: flex; }
.export-menu button {
display: block;
width: 100%;
text-align: left;
padding: 6px 10px;
font-size: 13px;
color: var(--text);
border-radius: 4px;
background: transparent;
}
@media (hover: hover) {
.export-menu button:hover { background: var(--bg-hover); }
}
.export-menu .export-menu-cancel { color: var(--text-muted); margin-top: 2px; border-top: 1px solid var(--border); border-radius: 0 0 4px 4px; }
/* Editor body (hidden textarea, used as sync target for form submission) */
.editor-body {
display: none;
flex: 1;
min-height: 0;
resize: none;
border: none;
outline: none;
background: var(--bg);
color: var(--text);
font-family: 'Cascadia Mono', monospace;
font-size: var(--font-size-markdown);
line-height: 1.6;
padding: 16px 20px;
overflow-y: auto;
}
/* CodeMirror host */
.cm-host {
flex: 1;
overflow: hidden;
min-height: 0;
font-size: var(--font-size-markdown);
}
/* TinyMCE host — persistent, positioned by JS over #tinymce-slot */
#tinymce-editor { display: none; }
.tinymce-host {
position: fixed;
z-index: 5;
display: none;
flex-direction: column;
background: var(--bg);
}
.tinymce-host.tinymce-host-visible { display: flex; }
.tinymce-slot {
flex: 1;
min-height: 0;
}
.tox-tinymce,
.tox-tinymce--focused {
flex: 1 !important;
min-height: 0 !important;
height: 100% !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
outline: none !important;
}
.tox-tinymce .tox-editor-container,
.tox-tinymce .tox-edit-area,
.tox-tinymce .tox-edit-area__iframe {
flex: 1 !important;
min-height: 0 !important;
height: 100% !important;
}
.tox-statusbar { display: none !important; }
.tox .tox-edit-area,
.tox .tox-edit-area__iframe {
background: var(--bg) !important;
}
/* TinyMCE theme integration — toolbar tinted per-theme via accent color */
.tox .tox-toolbar-overlord,
.tox .tox-toolbar,
.tox .tox-toolbar__primary,
.tox .tox-toolbar__overflow {
background-color: color-mix(in srgb, var(--accent) 10%, var(--bg)) !important;
background-image: none !important;
}
.tox .tox-editor-header {
position: sticky !important;
top: 0 !important;
z-index: 10 !important;
background-color: color-mix(in srgb, var(--accent) 10%, var(--bg)) !important;
}
.tox .tox-tbtn {
color: var(--text-dim) !important;
background: transparent !important;
background-color: transparent !important;
background-image: none !important;
border: none !important;
box-shadow: none !important;
}
.tox .tox-tbtn svg {
fill: var(--text-dim) !important;
}
@media (hover: hover) {
.tox .tox-tbtn:hover {
background: var(--bg-hover) !important;
background-color: var(--bg-hover) !important;
color: var(--text) !important;
}
}
@media (hover: hover) {
.tox .tox-tbtn:hover svg {
fill: var(--text) !important;
}
}
.tox .tox-tbtn--active,
.tox .tox-tbtn--enabled,
.tox .tox-tbtn--enabled:hover {
background: var(--bg-active) !important;
background-color: var(--bg-active) !important;
color: var(--accent) !important;
}
.tox .tox-tbtn--active svg,
.tox .tox-tbtn--enabled svg,
.tox .tox-tbtn--enabled:hover svg {
fill: var(--accent) !important;
}
.tox .tox-toolbar__group {
border-right-color: var(--border) !important;
}
/* Select-style toolbar buttons + fields (e.g. "Paragraph" format menu, list
* split-buttons). The oxide-dark skin gives these a default blue background;
* neutralize to match the app theme. */
.tox .tox-tbtn--select,
.tox .tox-split-button,
.tox .tox-tbtn--bespoke,
.tox .tox-listboxfield .tox-listbox--select,
.tox .tox-selectfield select,
.tox .tox-toolbar__primary .tox-split-button .tox-tbtn {
background: transparent !important;
background-color: transparent !important;
background-image: none !important;
color: var(--text-dim) !important;
border-color: var(--border) !important;
}
.tox .tox-tbtn--select:hover,
.tox .tox-split-button:hover,
.tox .tox-tbtn--bespoke:hover,
.tox .tox-split-button:focus,
.tox .tox-tbtn--select:focus {
background: var(--bg-hover) !important;
background-color: var(--bg-hover) !important;
color: var(--text) !important;
}
.tox .tox-tbtn--select.tox-tbtn--active,
.tox .tox-tbtn--select.tox-tbtn--enabled,
.tox .tox-split-button.tox-tbtn--active,
.tox .tox-split-button.tox-tbtn--enabled {
background: var(--bg-active) !important;
background-color: var(--bg-active) !important;
color: var(--accent) !important;
}
.tox .tox-tbtn__select-label,
.tox .tox-tbtn__select-chevron,
.tox .tox-split-button__chevron,
.tox .tox-tbtn--bespoke .tox-tbtn__select-label {
color: var(--text-dim) !important;
}
.tox .tox-tbtn__select-chevron svg,
.tox .tox-split-button__chevron svg {
fill: var(--text-dim) !important;
}
@media (hover: hover) {
.tox .tox-tbtn--select:hover .tox-tbtn__select-label,
.tox .tox-split-button:hover .tox-tbtn__select-chevron svg,
.tox .tox-tbtn--select:hover .tox-tbtn__select-chevron svg {
color: var(--text) !important;
fill: var(--text) !important;
}
}
/* Dropdown menus, context menus, popups */
.tox .tox-menu,
.tox .tox-collection--list,
.tox .tox-collection--toolbar,
.tox .tox-collection--grid {
background: var(--bg-side) !important;
border-color: var(--border) !important;
}
.tox .tox-collection__item {
color: var(--text-dim) !important;
}
.tox .tox-collection__item--active,
.tox .tox-collection__item:hover {
background: var(--bg-hover) !important;
color: var(--text) !important;
}
.tox .tox-collection__item--enabled {
background: var(--bg-active) !important;
color: var(--accent) !important;
}
.tox .tox-collection__group-label {
color: var(--text-muted) !important;
}
/* TinyMCE codesample plugin uses Prism classes; force app theme colors over default blue */
.tox-edit-area pre[class*="language-"],
.tox-edit-area pre.language-markup,
.tox-edit-area pre.language-javascript,
.tox-edit-area pre.language-css,
.tox-edit-area pre.language-html,
.tox-edit-area pre.language-typescript {
background: var(--bg-hover) !important;
border: 1px solid var(--border) !important;
border-radius: 0 !important;
color: var(--text) !important;
}
.tox-edit-area code[class*="language-"] { background: transparent !important; }
.tox-edit-area pre[class*="language-"] > code {
background: transparent !important;
padding: 0 !important;
border-radius: 0 !important;
}
.tox-edit-area pre[class*="language-"] .hljs-keyword,
.tox-edit-area pre[class*="language-"] .hljs-selector-tag,
.tox-edit-area pre[class*="language-"] .hljs-built_in { color: #c678dd !important; }
.tox-edit-area pre[class*="language-"] .hljs-string,
.tox-edit-area pre[class*="language-"] .hljs-attr,
.tox-edit-area pre[class*="language-"] .hljs-addition { color: #98c379 !important; }
.tox-edit-area pre[class*="language-"] .hljs-number,
.tox-edit-area pre[class*="language-"] .hljs-literal,
.tox-edit-area pre[class*="language-"] .hljs-symbol { color: #d19a66 !important; }
.tox-edit-area pre[class*="language-"] .hljs-title,
.tox-edit-area pre[class*="language-"] .hljs-title.function_ { color: #61afef !important; }
.tox-edit-area pre[class*="language-"] .hljs-type,
.tox-edit-area pre[class*="language-"] .hljs-title.class_ { color: #e5c07b !important; }
.tox-edit-area pre[class*="language-"] .hljs-comment,
.tox-edit-area pre[class*="language-"] .hljs-quote { color: var(--text-dim) !important; font-style: italic; }
.cm-host .cm-editor {
height: 100%;
background: transparent;
color: var(--text);
}
.cm-host .cm-editor.cm-focused {
outline: none;
}
/* Underline links in markdown mode */
.cm-host .cm-link,
.cm-host .cm-url {
text-decoration: underline;
}
.cm-host .cm-scroller {
scrollbar-color: var(--border) transparent;
}
.cm-host .cm-placeholder {
color: var(--text-dim);
font-style: italic;
}
/* ===== Markdown mode extras (public/cm-extras.js) ===== */
/* Image previews under `![](:/id)` lines */
.cm-host .cm-jl-imgrow {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: flex-start;
padding: 4px 0 10px;
font-family: system-ui, sans-serif;
}
.cm-host .cm-jl-img {
position: relative;
display: inline-block;
max-width: 100%;
line-height: 0;
}
.cm-host .cm-jl-img img {
display: block;
max-width: 100%;
height: auto;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--bg-elevated);
cursor: zoom-in;
user-select: none;
-webkit-user-drag: none;
}
.cm-host .cm-jl-img-natural img { max-height: 360px; width: auto; }
.cm-host .cm-jl-img.loading { min-width: 96px; min-height: 56px; border-radius: 6px; background: var(--bg-elevated); }
.cm-host .cm-jl-img.loading img { opacity: 0; }
.cm-host .cm-jl-img.broken {
padding: 8px 12px;
line-height: 1.4;
font-size: 0.85em;
color: var(--text-dim);
border: 1px dashed var(--border);
border-radius: 6px;
}
.cm-host .cm-jl-img-handle {
position: absolute;
right: -7px;
bottom: -7px;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--accent);
border: 2px solid var(--bg-editor, var(--bg));
cursor: nwse-resize;
opacity: 0;
transition: opacity 0.12s;
touch-action: none;
z-index: 2;
}
.cm-host .cm-jl-img:hover .cm-jl-img-handle,
.cm-host .cm-jl-img.resizing .cm-jl-img-handle { opacity: 0.95; }
.cm-host .cm-jl-img.resizing img { outline: 2px solid var(--accent); }
@media (hover: none) { .cm-host .cm-jl-img-handle { opacity: 0.85; width: 22px; height: 22px; right: -9px; bottom: -9px; } }
/* Download buttons (same look as the rendered-mode image button) */
.cm-host .cm-jl-img-dl {
position: absolute;
top: 8px;
right: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
padding: 0;
font-size: 16px;
line-height: 1;
color: var(--text-heading);
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 999px;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.28);
cursor: pointer;
opacity: 0.28;
z-index: 2;
transition: opacity 0.18s ease, color 0.18s ease, border-color 0.18s ease, background-color 0.18s ease;
}
.cm-host .cm-jl-img-dl::after,
.cm-host .cm-jl-chip-dl::after { content: "\2B07\FE0F"; }
.cm-host .cm-jl-img:hover .cm-jl-img-dl,
.cm-host .cm-jl-img-dl:hover,
.cm-host .cm-jl-img-dl:focus { opacity: 1; color: #fff; border-color: var(--accent); background: var(--accent); }
.cm-host .cm-jl-img.broken .cm-jl-img-dl,
.cm-host .cm-jl-img.loading .cm-jl-img-dl { display: none; }
@media (hover: none) { .cm-host .cm-jl-img-dl { opacity: 0.9; width: 32px; height: 32px; } }
/* Attachment / note-link chips (replace `[text](:/id)`) */
.cm-host .cm-jl-chip {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 0 9px 0 7px;
margin: 0 1px;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--bg-hover);
color: var(--text);
font-size: 0.92em;
line-height: 1.6;
cursor: pointer;
vertical-align: baseline;
white-space: nowrap;
max-width: 26em;
}
@media (hover: hover) {
.cm-host .cm-jl-chip:hover { border-color: var(--accent); background: var(--bg-active); }
}
.cm-host .cm-jl-chip-dl {
display: none;
align-items: center;
justify-content: center;
width: 1.5em;
height: 1.5em;
margin: 0 -4px 0 0;
padding: 0;
font-size: 0.85em;
line-height: 1;
color: var(--text-dim);
background: transparent;
border: 0;
border-radius: 999px;
cursor: pointer;
}
.cm-host .cm-jl-chip[data-kind="resource"] .cm-jl-chip-dl { display: inline-flex; }
@media (hover: hover) {
.cm-host .cm-jl-chip-dl:hover { color: #fff; background: var(--accent); }
}
.cm-host .cm-jl-chip-label { overflow: hidden; text-overflow: ellipsis; }
.cm-host .cm-jl-chip-icon::before { content: "\1F517"; font-size: 0.9em; }
.cm-host .cm-jl-chip[data-kind="resource"] .cm-jl-chip-icon::before { content: "\1F4CE"; }
.cm-host .cm-jl-chip[data-kind="note"] .cm-jl-chip-icon::before { content: "\1F4C4"; }
/* Clickable task checkboxes */
.cm-host .cm-jl-check {
display: inline-block;
position: relative;
width: 1.05em;
height: 1.05em;
margin: 0 0.15em;
vertical-align: -0.15em;
border: 1.5px solid var(--text-dim);
border-radius: 4px;
cursor: pointer;
box-sizing: border-box;
}
@media (hover: hover) {
.cm-host .cm-jl-check:hover { border-color: var(--accent); }
}
.cm-host .cm-jl-check.checked { background: var(--accent); border-color: var(--accent); }
.cm-host .cm-jl-check.checked::after {
content: "";
position: absolute;
left: 0.28em;
top: 0.04em;
width: 0.28em;
height: 0.55em;
border: solid var(--text-on-accent, #000);
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
.cm-host .cm-jl-task-done { text-decoration: line-through; color: var(--text-dim); }
/* Fenced code blocks */
.cm-host .cm-jl-codeline { background: var(--bg-elevated); }
.cm-host .cm-jl-codeline-first { border-top-left-radius: 6px; border-top-right-radius: 6px; }
.cm-host .cm-jl-codeline-last { border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; }
.cm-host .cm-jl-copy {
float: right;
margin-left: 8px;
padding: 0 8px;
font: inherit;
font-size: 0.78em;
line-height: 1.6;
color: var(--text-dim);
background: transparent;
border: 1px solid var(--border);
border-radius: 5px;
cursor: pointer;
opacity: 0.55;
}
.cm-host .cm-jl-codeline-first:hover .cm-jl-copy,
.cm-host .cm-jl-copy:focus { opacity: 1; color: var(--text); border-color: var(--accent); }
/* Fold gutter */
.cm-host .cm-foldGutter { width: 18px; }
.cm-host .cm-foldGutter .cm-gutterElement { text-align: center; cursor: pointer; padding: 0; }
.cm-host .cm-jl-fold-marker { opacity: 0; font-size: 0.8em; color: var(--text-dim); transition: opacity 0.12s; }
.cm-host .cm-gutters:hover .cm-jl-fold-marker,
.cm-host .cm-jl-fold-marker.closed { opacity: 0.9; }
@media (hover: hover) {
.cm-host .cm-jl-fold-marker:hover { color: var(--accent); }
}
.cm-host .cm-jl-fold-placeholder {
margin: 0 4px;
padding: 0 6px;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-hover);
color: var(--text-dim);
cursor: pointer;
}
/* Status bar + outline */
.cm-host .cm-panels-bottom {
background: var(--statusbar-bg, var(--bg-side));
border-top: 1px solid var(--border);
color: var(--text-dim);
}
.cm-host .cm-jl-status {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 2px 12px;
font-family: system-ui, sans-serif;
font-size: 12px;
line-height: 22px;
}
.cm-host .cm-jl-stat { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cm-host .cm-jl-outline-btn {
font: inherit;
color: var(--text-dim);
background: transparent;
border: 1px solid var(--border);
border-radius: 5px;
padding: 0 8px;
line-height: 18px;
cursor: pointer;
flex: 0 0 auto;
}
@media (hover: hover) {
.cm-host .cm-jl-outline-btn:hover { color: var(--text); border-color: var(--accent); }
}
.cm-host .cm-jl-outline {
position: absolute;
right: 8px;
bottom: 100%;
min-width: 220px;
max-width: min(420px, 90vw);
max-height: 50vh;
overflow-y: auto;
margin-bottom: 4px;
padding: 4px 0;
background: var(--bg-side);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 8px 24px var(--shadow, rgba(0,0,0,0.3));
z-index: 20;
}
.cm-host .cm-jl-outline[hidden] { display: none; }
.cm-host .cm-jl-outline-item {
display: block;
width: 100%;
text-align: left;
font: inherit;
line-height: 1.5;
padding: 3px 10px;
color: var(--text);
background: transparent;
border: 0;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
@media (hover: hover) {
.cm-host .cm-jl-outline-item:hover { background: var(--bg-hover); }
}
.cm-host .cm-jl-outline-empty { padding: 6px 12px; color: var(--text-dim); }
/* Link hover info */
.cm-tooltip.cm-tooltip-hover {
background: var(--bg-side);
color: var(--text);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 6px 20px var(--shadow, rgba(0,0,0,0.3));
}
.cm-tooltip.cm-tooltip-hover .cm-jl-tip {
padding: 6px 10px;
font-family: system-ui, sans-serif;
font-size: 13px;
max-width: 340px;
}
.cm-jl-tip-title { color: var(--text); font-weight: 600; word-break: break-word; }
.cm-jl-tip-sub { color: var(--text-dim); font-size: 12px; margin-top: 2px; }
.note-autocomplete-popup,
.cm-tooltip-autocomplete {
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
box-shadow: 0 14px 40px var(--shadow);
overflow: hidden;
max-width: min(560px, calc(100vw - 24px));
max-height: 42vh;
overflow-y: auto;
backdrop-filter: blur(8px);
}
.note-autocomplete-item,
.cm-tooltip-autocomplete ul > li {
padding: 10px 12px;
color: var(--text);
font-size: 13px;
line-height: 1.35;
border-top: 1px solid transparent;
}
.note-autocomplete-item:first-child,
.cm-tooltip-autocomplete ul > li:first-child { border-top: 0; }
.note-autocomplete-item.active,
.cm-tooltip-autocomplete ul > li[aria-selected="true"] {
background: var(--bg-active);
color: var(--text-heading);
}
@media (hover: hover) {
.note-autocomplete-item:hover,
.cm-tooltip-autocomplete ul > li:hover {
background: var(--bg-hover);
}
}
.note-autocomplete-item + .note-autocomplete-item,
.cm-tooltip-autocomplete ul > li + li {
border-top-color: var(--border);
}
/* Preview pane */
.editor-preview {
flex: 1;
padding: 16px 20px;
overflow-y: auto;
font-size: var(--font-size-note);
line-height: 1.7;
color: var(--text);
outline: none;
}
.editor-preview p { margin: 0.75em 0; }
.editor-preview p:first-child { margin-top: 0; }
.editor-preview .md-blank-line { margin: 0.75em 0; }
.editor-preview .md-blank-line br { line-height: 0; font-size: 0; display: block; }
/* Match browser-inserted blank paragraphs to the canonical md-blank-line
spacing. Without this, hitting Enter in rendered mode creates <p><br></p>
or <div><br></div> at full line-height, while the same source re-rendered
from markdown produces md-blank-line divs at paragraph-margin scale. */
.editor-preview p:empty,
.editor-preview p:has(> br:only-child),
.editor-preview div:not([class]):empty,
.editor-preview div:not([class]):has(> br:only-child) {
margin: 0.75em 0;
}
.editor-preview[contenteditable="true"] {
cursor: text;
overflow-anchor: none;
}
.editor-preview h1, .editor-preview h2, .editor-preview h3,
.editor-preview h4, .editor-preview h5, .editor-preview h6 {
color: var(--text-heading);
margin: 1em 0 0.5em;
}
.editor-preview > h1:first-child,
.editor-preview > h2:first-child,
.editor-preview > h3:first-child,
.editor-preview > h4:first-child,
.editor-preview > h5:first-child,
.editor-preview > h6:first-child { margin-top: 0; }
.editor-preview h1 { font-size: 1.8em; }
.editor-preview h2 { font-size: 1.5em; }
.editor-preview h3 { font-size: 1.25em; }
.editor-preview strong { color: var(--text-heading); }
.editor-preview a { color: var(--accent); }
.editor-preview code {
background: var(--bg-hover);
padding: 2px 5px;
border-radius: 0;
font-family: 'Cascadia Mono', monospace;
font-size: var(--font-size-code);
}
.editor-preview pre {
background: #1f2329;
border: 1px solid #343a40;
color: #e6edf3;
padding: 28px 16px 12px;
border-radius: 0;
overflow-x: auto;
margin: 1em 0;
font-family: 'Cascadia Mono', monospace;
font-size: var(--font-size-code);
}
.editor-preview pre code { background: none; padding: 0; color: inherit; }
/* highlight.js token colors (One Dark inspired, matches CM6 theme) */
.editor-preview .hljs-keyword,
.editor-preview .hljs-selector-tag,
.editor-preview .hljs-built_in { color: #c678dd; }
.editor-preview .hljs-string,
.editor-preview .hljs-attr,
.editor-preview .hljs-addition { color: #98c379; }
.editor-preview .hljs-number,
.editor-preview .hljs-literal,
.editor-preview .hljs-symbol { color: #d19a66; }
.editor-preview .hljs-title,
.editor-preview .hljs-title.function_ { color: #61afef; }
.editor-preview .hljs-type,
.editor-preview .hljs-title.class_ { color: #e5c07b; }
.editor-preview .hljs-comment,
.editor-preview .hljs-quote { color: #8b949e; font-style: italic; }
.editor-preview .hljs-variable,
.editor-preview .hljs-template-variable { color: #e06c75; }
.editor-preview .hljs-operator { color: #56b6c2; }
.editor-preview .hljs-property { color: #e06c75; }
.editor-preview .hljs-attribute { color: #d19a66; }
.editor-preview .hljs-meta { color: #8b949e; }
.editor-preview .hljs-deletion { color: #e06c75; }
.editor-preview .hljs-section { color: #61afef; font-weight: bold; }
.editor-preview .hljs-name { color: #e06c75; }
.editor-preview .hljs-selector-class,
.editor-preview .hljs-selector-id { color: #e5c07b; }
.editor-preview .hljs-punctuation { color: #e6edf3; }
.editor-preview blockquote {
border-left: 3px solid var(--accent);
margin: 1em 0;
padding: 4px 16px;
color: var(--text-dim);
}
.editor-preview hr { border: none; border-top: 1px solid var(--border); margin: 1.5em 0; }
.editor-preview ul, .editor-preview ol { padding-left: 1.5em; margin: 0.5em 0; }
.editor-preview li { margin: 0.25em 0; }
.editor-preview table { border-collapse: collapse; width: 100%; margin: 0.8em 0; }
.editor-preview th, .editor-preview td { border: 3px solid var(--border); padding: 6px 10px; text-align: left; }
.editor-preview th { background: var(--bg-hover); font-weight: bold; }
.editor-preview .md-checkbox {
margin: 0.25em 0;
padding-left: 0.9em;
display: flex;
align-items: baseline;
gap: 0.35em;
}
.editor-preview .md-checkbox::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
border: 1.5px solid var(--accent);
border-radius: 0;
flex-shrink: 0;
background: transparent;
box-sizing: border-box;
}
.editor-preview .md-checkbox.checked::before {
background: var(--accent);
border-color: var(--accent);
content: '✓';
color: var(--bg);
font-size: 11px;
font-weight: bold;
line-height: 16px;
text-align: center;
}
.preview-img { display: block; max-width: 100%; height: auto; border-radius: 0; margin: 12px 0; cursor: default; }
.editor-preview[contenteditable="true"] .preview-img { cursor: nwse-resize; border: 1px solid transparent; }
@media (hover: hover) {
.editor-preview[contenteditable="true"] .preview-img:hover { border-color: var(--accent); opacity: 0.95; }
}
.editor-preview[contenteditable="true"] .preview-img:active { border-color: var(--accent); }
.preview-img-download-wrap {
position: relative;
display: inline-block;
max-width: 100%;
margin: 12px 0;
}
.preview-img-download-wrap .preview-img { margin: 0; }
.preview-img-download-btn {
position: absolute;
top: 8px;
right: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
padding: 0;
font-size: 18px;
font-weight: 700;
font-family: inherit;
background: color-mix(in srgb, var(--bg-elevated) 82%, transparent);
color: var(--text-heading);
border: 1px solid var(--border);
border-radius: 999px;
cursor: pointer;
line-height: 1;
z-index: 1;
opacity: 0.28;
backdrop-filter: blur(4px);
box-shadow: 0 1px 6px rgba(0,0,0,0.28);
transition: opacity 0.18s ease, color 0.18s ease, border-color 0.18s ease, background-color 0.18s ease, transform 0.18s ease;
}
.preview-img-download-wrap:hover .preview-img-download-btn,
.preview-img-download-wrap:focus-within .preview-img-download-btn,
.preview-img-download-btn:focus,
.preview-img-download-btn:active {
opacity: 1;
}
.preview-img-download-wrap:hover .preview-img-download-btn,
.preview-img-download-wrap:focus-within .preview-img-download-btn {
color: #fff;
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 82%, transparent);
transform: scale(1.04);
}
.preview-img-download-btn:hover,
.preview-img-download-btn:focus,
.preview-img-download-btn:active {
color: #fff;
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 82%, transparent);
transform: scale(1.04);
}
@media (hover: none), (pointer: coarse) {
.preview-img-download-btn {
width: 24px;
height: 24px;
top: 6px;
right: 6px;
font-size: 15px;
opacity: 1;
background: color-mix(in srgb, var(--accent) 80%, transparent);
color: #fff;
border-color: color-mix(in srgb, var(--accent) 70%, var(--border));
}
}
/* --- Resource action sheet (PWA) --- */
.resource-action-backdrop {
position: fixed; inset: 0; z-index: 10010;
background: var(--overlay);
}
.resource-action-sheet {
position: fixed; left: 12px; right: 12px; top: 12px;
z-index: 10011;
display: flex; flex-direction: column; gap: 6px;
padding: 10px;
min-width: 180px;
overflow: auto;
background: var(--bg-side);
border: 1px solid var(--border);
border-radius: 0;
box-shadow: 0 8px 24px rgba(0,0,0,0.45);
}
.resource-action-btn {
appearance: none;
display: block; width: 100%;
padding: 14px 16px;
font-size: 17px; font-weight: 600;
color: var(--text);
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 0;
cursor: pointer;
}
.resource-action-btn:active { background: var(--bg-active); }
.resource-action-btn-cancel { color: var(--text-dim); }
@media (hover: hover) and (pointer: fine) {
.resource-action-backdrop { background: transparent; }
.resource-action-sheet { right: auto; }
}
/* --- Resource viewer (in-app preview: PWA action sheet + desktop image/attachment double-click) --- */
.resource-viewer {
position: fixed; inset: 0; z-index: 10020;
display: flex; flex-direction: column;
background: #000;
}
.resource-viewer-bar {
display: flex; align-items: center; gap: 8px;
padding: 10px 12px;
padding-top: calc(env(safe-area-inset-top, 0px) + 10px);
background: var(--bg-side);
border-bottom: 1px solid var(--border);
}
.resource-viewer-title {
flex: 1; min-width: 0;
color: var(--text);
font-size: 14px;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.resource-viewer-btn {
appearance: none;
padding: 8px 14px;
font-size: 14px; font-weight: 600;
color: var(--text);
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 0;
cursor: pointer;
}
.resource-viewer-btn:active { background: var(--bg-active); }
.resource-viewer-body {
flex: 1; min-height: 0;
display: flex; align-items: center; justify-content: center;
overflow: auto;
background: #000;
padding-bottom: env(safe-area-inset-bottom, 0px);
}
.resource-viewer-img { max-width: 100%; max-height: 100%; object-fit: contain; }
.resource-viewer-frame { width: 100%; height: 100%; border: 0; background: #fff; }
.resource-viewer-msg { padding: 20px; color: var(--text); text-align: center; font-size: 15px; }
/* Autosave */
.autosave-ok { color: #5fd38d; font-size: 11px; opacity: 0.9; }
.autosave-edited { color: var(--danger); font-size: 11px; opacity: 0.95; }
.autosave-error { color: var(--danger); font-size: 11px; }
.autosave-saving { color: var(--text-dim); font-size: 11px; opacity: 0.9; }
.autosave-offline { color: var(--danger); font-size: 11px; animation: pulse-offline 2s ease-in-out infinite; }
@keyframes pulse-offline { 0%,100%{opacity:1} 50%{opacity:0.4} }
.is-offline .app-statusbar { background: color-mix(in srgb, var(--danger) 12%, var(--statusbar-bg)); }
/* --- Disconnected overlay (server unreachable) --- */
.disconnected-overlay {
position: fixed;
inset: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
background: #000;
}
.disconnected-logo {
position: absolute;
width: 320px;
height: 320px;
opacity: 0.15;
filter: blur(4px);
pointer-events: none;
}
.disconnected-card {
position: relative;
text-align: center;
max-width: 340px;
width: calc(100% - 32px);
}
.disconnected-icon svg {
width: 48px;
height: 48px;
color: var(--danger);
margin-bottom: 16px;
}
.disconnected-title {
font-size: 18px;
font-weight: 600;
color: #ccc;
margin-bottom: 6px;
}
.disconnected-sub {
font-size: 13px;
color: #888;
margin-bottom: 16px;
}
.disconnected-countdown {
font-size: 13px;
color: #666;
margin-bottom: 16px;
font-variant-numeric: tabular-nums;
animation: pulse-offline 2s ease-in-out infinite;
}
.disconnected-actions {
display: flex;
flex-direction: column;
gap: 8px;
}
.disconnected-retry {
padding: 8px 16px;
border: 1px solid #555;
border-radius: 0;
background: transparent;
color: #ccc;
font-size: 13px;
font-weight: 500;
font-family: inherit;
cursor: pointer;
transition: background 0.15s;
}
@media (hover: hover) {
.disconnected-retry:hover { background: #222; }
}
.disconnected-retry:disabled { opacity: 0.5; cursor: not-allowed; }
.disconnected-logout {
padding: 8px 16px;
border: 1px solid #333;
border-radius: 0;
background: transparent;
color: #666;
font-size: 13px;
font-family: inherit;
cursor: pointer;
transition: color 0.15s, border-color 0.15s;
}
@media (hover: hover) {
.disconnected-logout:hover { color: var(--danger); border-color: var(--danger); }
}
.is-disconnected .app-layout { display: none; }
.is-disconnected #mobile-app { display: none; }
.autosave-conflict { display: inline-flex; align-items: center; gap: 6px; }
/* Full-screen note loading overlay */
#note-loading-overlay {
display: none;
position: fixed;
inset: 0;
z-index: 9999;
background: rgba(0,0,0,0.45);
align-items: center;
justify-content: center;
flex-direction: column;
gap: 20px;
}
#note-loading-overlay.active { display: flex; }
.mobile-loading-note {
display: flex !important;
align-items: center;
justify-content: center;
flex: 1;
}
.note-loading-ring {
width: 72px;
height: 72px;
border-radius: 50%;
border: 6px solid rgba(255,255,255,0.2);
border-top-color: #fff;
will-change: transform;
animation: note-loading-spin 0.8s linear infinite;
}
.note-loading-label {
color: #fff;
font-size: 15px;
letter-spacing: 0.03em;
opacity: 0.9;
}
@keyframes note-loading-spin {
to { transform: rotate(360deg); }
}
.htmx-indicator { display: none; color: var(--text-dim); font-size: 11px; }
.htmx-request .htmx-indicator { display: inline; }
.htmx-request #autosave-status { display: none; }
.note-meta {
color: var(--text-dim);
font-size: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 260px;
}
#editor-panel > #note-meta {
display: none;
}
/* Status bar */
.app-statusbar {
height: var(--statusbar-height);
display: flex;
align-items: center;
gap: 10px;
padding: 0 12px;
background: var(--statusbar-bg);
border-top: 1px solid var(--border);
font-size: 11px;
color: var(--text-dim);
flex-shrink: 0;
}
.status-user { }
.status-spacer { flex: 1; }
.theme-picker {
padding: 2px 4px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
color: var(--text);
font-size: 11px;
outline: none;
cursor: pointer;
width: auto;
max-width: min(260px, 100%);
flex: 0 1 auto;
}
.theme-picker option {
background: var(--bg-side);
color: var(--text);
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 5px 12px;
border-radius: 4px;
border: 1px solid var(--border);
font-weight: 500;
font-size: 12px;
transition: background 0.1s;
text-decoration: none;
white-space: nowrap;
}
.btn[hidden] { display: none; }
@media (hover: hover) {
.btn:hover { background: var(--bg-hover); }
}
.btn-primary {
background: var(--accent);
color: var(--text-on-accent);
border-color: var(--accent);
}
@media (hover: hover) {
.btn-primary:hover {
background: color-mix(in srgb, var(--accent) 88%, #fff);
border-color: color-mix(in srgb, var(--accent) 88%, #fff);
color: var(--text-on-accent);
}
}
.btn.active {
background: var(--bg-active);
border-color: var(--border-focus);
}
.btn-secondary { background: var(--bg-input); }
.btn-sm { padding: 4px 10px; font-size: 12px; }
.btn-icon {
width: 28px;
height: 28px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
border: none;
font-size: 14px;
color: var(--text-dim);
transition: background 0.1s;
}
@media (hover: hover) {
.btn-icon:hover { background: var(--bg-hover); }
}
#lock-toggle-btn { color: #FFC107; }
@media (hover: hover) {
#lock-toggle-btn:hover { color: #FFC107; }
}
.btn-icon.active { color: var(--accent); background: var(--bg-active); }
.btn-icon-compact { width: 24px; height: 24px; font-size: 13px; }
.btn-danger-soft { color: var(--danger); }
@media (hover: hover) {
.btn-danger-soft:hover { color: var(--danger); background: color-mix(in srgb, var(--danger) 14%, transparent); }
}
@media (hover: hover) {
.btn-danger:hover { color: var(--danger); }
}
.mode-toggle-btn {
width: auto;
min-width: 52px;
height: 28px;
padding: 0 10px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--bg-input);
color: var(--text-muted);
}
.btn-icon.mode-toggle-btn.active {
color: var(--text-on-accent);
background: var(--accent);
border-color: var(--accent);
}
.empty-hint {
padding: 12px;
color: var(--text-dim);
font-size: 12px;
}
/* Login */
.login-page {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
font-family: 'Cascadia Mono', monospace;
min-height: 100dvh;
}
.login-card { text-align: center; max-width: 360px; width: 100%; }
.login-logo {
display: block;
width: 96px;
height: 96px;
margin: 0 auto 14px;
border-radius: 0;
box-shadow: 0 14px 32px var(--shadow);
}
.login-title {
font-size: 36px;
font-weight: 800;
color: var(--accent);
margin-bottom: 8px;
}
.login-brand {
font-size: 28px;
letter-spacing: 0.16em;
}
.login-sub {
color: var(--text-dim);
margin-bottom: 20px;
}
.login-tagline {
font-size: 13px;
line-height: 1.35;
}
.login-form {
display: flex;
flex-direction: column;
gap: 10px;
}
.login-input {
box-sizing: border-box;
min-width: 0;
max-width: 100%;
padding: 10px 12px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
color: var(--text);
font-size: 14px;
outline: none;
}
select.login-input {
background-color: var(--bg-side);
color: var(--text);
}
select.login-input option {
background-color: var(--bg-side);
color: var(--text);
}
.login-input:focus {
border-color: var(--accent);
}
.login-btn {
padding: 10px 12px;
font-size: 14px;
margin-top: 4px;
}
.login-error {
color: var(--danger);
font-size: 13px;
min-height: 1.2em;
}
.settings-page {
min-height: 100vh;
padding: calc(28px + env(safe-area-inset-top, 0px)) 20px calc(28px + env(safe-area-inset-bottom, 0px));
min-height: 100dvh;
background: var(--bg);
}
.settings-card {
max-width: 760px;
margin: 0 auto;
padding: 20px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-side);
box-shadow: 0 18px 40px var(--shadow);
}
.about-info {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 16px;
}
.about-row {
display: flex;
align-items: baseline;
gap: 12px;
}
.about-label {
font-size: 13px;
color: var(--text-dim);
min-width: 120px;
flex-shrink: 0;
}
.about-value {
font-size: 14px;
color: var(--text);
}
.about-link {
color: var(--accent);
text-decoration: none;
}
@media (hover: hover) {
.about-link:hover {
text-decoration: underline;
}
}
.settings-header {
display: flex;
justify-content: space-between;
gap: 16px;
align-items: flex-start;
margin-bottom: 18px;
}
.settings-title {
margin: 0;
font-size: 28px;
color: var(--text-heading);
}
.settings-sub,
.settings-section-sub {
margin: 6px 0 0;
color: var(--text-dim);
}
.settings-section {
padding-top: 18px;
margin-top: 18px;
border-top: 1px solid var(--border);
}
.status-settings-link {
text-decoration: none;
flex-shrink: 0;
width: 42px;
height: 42px;
font-size: 21px;
position: relative;
top: 1px;
}
.settings-section-title {
margin: 0 0 8px;
font-size: 18px;
color: var(--text-heading);
}
.settings-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
margin-top: 16px;
}
.settings-form {
display: grid;
gap: 16px;
}
.settings-field {
display: grid;
gap: 8px;
color: var(--text);
/* Grid cells stretch to the tallest cell in their row; without this the
rows inside a field stretch too and a <select> balloons to fill it. */
align-content: start;
}
.settings-checkbox {
align-content: start;
}
/* A field that needs the whole row (e.g. a group of checkboxes). */
.settings-field-wide {
grid-column: 1 / -1;
}
.settings-checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 8px 28px;
}
.settings-actions {
display: flex;
justify-content: flex-end;
}
.settings-security-card {
margin-top: 14px;
padding: 16px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-elevated);
}
.settings-mfa-status,
.settings-secret {
margin: 0 0 12px;
}
.settings-mfa-status .badge { vertical-align: middle; margin-right: 8px; }
.settings-qr {
display: block;
width: 200px;
height: 200px;
max-width: 100%;
margin: 16px 0;
border-radius: 0;
background: #fff;
padding: 12px;
}
.settings-mfa-row {
display: flex;
gap: 8px;
align-items: center;
margin-top: 8px;
}
.settings-mfa-row .login-input {
flex: 1;
max-width: 160px;
}
.settings-mfa-setup .settings-mfa-row { margin-bottom: 12px; }
.settings-mfa-cancel { margin-top: 12px; }
.settings-mfa-global {
margin-top: 16px;
background: color-mix(in srgb, var(--accent) 10%, transparent);
border: 1px solid var(--accent);
}
.badge-warning { background: color-mix(in srgb, #f59e0b 20%, transparent); color: #f59e0b; }
/* AI profile cards */
.ai-profiles-bar {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 14px;
max-width: 100%;
}
.ai-profiles-bar-label {
display: flex;
align-items: center;
flex: 1 1 260px;
gap: 8px;
min-width: 0;
font-size: 13px;
color: var(--text-muted);
}
.ai-active-select {
width: 200px;
max-width: 200px;
}
.ai-profiles {
display: grid;
gap: 10px;
margin-top: 12px;
min-width: 0;
}
.ai-profile-card {
min-width: 0;
max-width: 100%;
box-sizing: border-box;
padding: 12px 14px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-elevated);
}
.ai-profile-card-active {
border-color: var(--accent);
}
.ai-profile-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 10px;
flex-wrap: wrap;
}
.ai-profile-name-input {
flex: 1 1 180px;
min-width: 120px;
}
.ai-profile-provider-select {
flex: 1 1 150px;
width: 150px;
max-width: 150px;
min-width: 0;
}
.ai-profile-body {
display: grid;
gap: 8px;
min-width: 0;
}
.ai-profile-field {
display: grid;
gap: 4px;
min-width: 0;
font-size: 13px;
color: var(--text-muted);
}
.ai-profile-field .login-input {
width: 100%;
}
.ai-profile-field .settings-field-hint,
.ai-profile-field code {
max-width: 100%;
overflow-wrap: anywhere;
word-break: break-word;
}
.ai-profile-field > span:first-child {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
}
.ai-profile-actions {
display: flex;
align-items: center;
gap: 10px;
margin-top: 4px;
}
.ai-test-result {
font-size: 13px;
color: var(--text-muted);
}
.ai-test-ok { color: var(--accent); }
.ai-test-fail { color: #ef4444; }
.logout-progress {
display: grid;
gap: 6px;
margin-top: 18px;
text-align: left;
}
.logout-step {
padding: 8px 0;
border: 0;
border-bottom: 1px solid var(--border);
border-radius: 0;
background: transparent;
color: var(--text-dim);
text-align: left;
cursor: pointer;
}
.logout-step.done {
color: var(--text);
}
.logout-step-check {
float: right;
color: #4caf50;
font-weight: 700;
}
.logout-detail {
display: none;
padding: 0 0 8px;
color: var(--text-dim);
font-size: 13px;
line-height: 1.5;
}
.logout-detail.open {
display: block;
}
.login-password-wrap {
position: relative;
display: flex;
}
.login-password-wrap .login-input {
flex: 1;
padding-right: 36px;
}
.login-eye {
position: absolute;
right: 4px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
font-size: 18px;
padding: 4px;
line-height: 1;
opacity: 0.6;
}
@media (hover: hover) {
.login-eye:hover {
opacity: 1;
}
}
.login-totp {
opacity: 0.7;
font-size: 14px;
}
.login-totp:focus {
opacity: 1;
}
/* Scrollbar — standard props (Firefox, modern Chromium/Safari) + WebKit
pseudo-elements (older Chromium/Safari) so every scrollable panel in the
app (note list, sidebars, modals, etc.) gets the same thin, theme-colored
scrollbar as the markdown editor (.cm-scroller). */
body { scrollbar-width: thin; scrollbar-color: var(--scrollbar) transparent; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 0; }
/* Responsive */
/* The mobile shell. "Phone" = narrow window (<=768px) OR a touch device whose physical screen has a
short side <=500px. The second part is what makes a phone in LANDSCAPE (812-956px wide) keep the
mobile layout. It must be the screen, never the window height: a soft keyboard shrinks the window
(on iOS home-screen apps innerHeight shrinks with it), so a height test would flip an iPad to the
phone layout and reload the page while typing. iOS reports device-width as the portrait width in
both orientations and Android rotates it, hence both device-width and device-height.
public/app.js _computeMobileShell() must stay in step; tests/landscapeShell.test.js checks both. */
@media (max-width: 768px), (pointer: coarse) and (max-device-width: 500px), (pointer: coarse) and (max-device-height: 500px) {
body { font-size: 12px; }
body { --statusbar-height: 36px; }
/* Prevent iOS auto-zoom: all inputs must be >= 16px */
input, select, textarea { font-size: 16px !important; }
html, body { overflow-x: hidden; }
.login-page {
padding: calc(20px + env(safe-area-inset-top, 0px)) 16px 20px;
align-items: flex-start;
}
.login-card {
max-width: 320px;
margin: 0 auto;
}
.login-logo { width: 108px; height: 108px; margin-bottom: 16px; }
.login-title { font-size: 36px; }
.login-brand { font-size: 24px; }
.login-sub { margin-bottom: 20px; font-size: 18px; line-height: 1.45; }
.login-tagline { font-size: 12px; line-height: 1.3; }
.login-input,
.login-btn { font-size: 18px; }
.login-input { padding: 12px 14px; }
.login-btn { width: 100%; min-height: 52px; padding: 14px 18px; font-size: 20px; font-weight: 700; }
.app { display: block; position: relative; height: calc(100vh - var(--statusbar-height) - env(safe-area-inset-bottom, 0px) - 22px); }
body.mobile-nav-open { overflow: hidden; }
.nav-toggle-btn { display: none; }
.nav-reopen-btn {
display: inline-flex;
position: fixed;
top: env(safe-area-inset-top, 6px);
left: 8px;
z-index: 15;
}
body.nav-collapsed .nav-reopen-btn,
body:not(.nav-collapsed) .nav-reopen-btn { display: inline-flex; }
.mobile-nav-backdrop {
display: block;
position: fixed;
inset: 0;
background: var(--overlay);
opacity: 0;
pointer-events: none;
transition: opacity 0.18s;
z-index: 18;
}
.mobile-nav-backdrop.open {
opacity: 1;
pointer-events: auto;
}
.col-nav {
display: flex;
position: fixed;
left: 0;
top: 0;
bottom: calc(var(--statusbar-height) + env(safe-area-inset-bottom, 0px) + 22px);
width: min(88vw, 360px);
max-width: 100%;
flex-direction: column;
background: var(--bg-side);
transform: translateX(-100%);
transition: transform 0.18s ease;
z-index: 20;
box-shadow: 10px 0 30px var(--shadow);
}
.col-nav.open { transform: translateX(0); }
body.nav-collapsed .col-nav { display: flex; }
.col-editor { height: 100%; min-height: 0; }
.nav-panel-header { padding: 10px; gap: 5px; }
.nav-items { padding: 8px; }
.nav-folder-row { padding: 8px; }
.nav-folder > .nav-folder-row { padding-left: calc(8px + var(--nav-depth, 0) * 14px); }
.nav-folder-notes .notelist-item { padding: 8px 10px 8px calc(32px + var(--nav-depth, 0) * 14px); }
.editor-titlebar {
padding: 6px 8px 6px 62px;
gap: 4px;
flex-wrap: nowrap;
align-items: center;
}
.editor-title {
flex: 1 1 auto;
min-width: 0;
font-size: 13px;
line-height: 1.2;
padding: 0;
min-height: 1.2em;
order: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.editor-folder-select {
max-width: 110px;
font-size: 11px;
padding: 2px 5px;
order: 1;
}
.editor-folder-arrow { margin: 0; font-size: 12px; order: 1; }
#autosave-status,
#autosave-indicator { margin-left: auto; font-size: 10px; order: 1; }
.btn,
.btn-sm { padding: 4px 8px; font-size: 11px; }
.login-btn { font-size: 20px; }
.btn-icon { width: 26px; height: 26px; font-size: 13px; order: 1; }
.editor-title-mobile-readonly {
pointer-events: none;
}
.editor-toolbar {
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
padding: 10px 12px;
gap: 6px;
-webkit-overflow-scrolling: touch;
}
.editor-toolbar::-webkit-scrollbar { height: 3px; }
.editor-toolbar .tb { min-width: 46px; height: 46px; padding: 0 12px; font-size: 18px; border-radius: 10px; flex: 0 0 auto; }
.editor-toolbar .tb-div { margin: 0 5px; height: 24px; flex: 0 0 auto; }
.editor-toolbar .tb[data-format="h1"],
.editor-toolbar .tb[data-format="h2"] { display: none; }
.cm-host .cm-content {
padding: 10px 12px;
}
.editor-preview {
padding: 10px 12px;
font-size: var(--font-size-note-mobile, var(--font-size-note));
line-height: 1.7;
}
.editor-preview h1 { font-size: 1.45em; }
.editor-preview h2 { font-size: 1.28em; }
.editor-preview h3 { font-size: 1.15em; }
.app-statusbar {
height: var(--statusbar-height);
gap: 6px;
padding: 0 8px calc(env(safe-area-inset-bottom, 0px) + 18px);
font-size: 10px;
}
.status-user {
max-width: 40vw;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.theme-picker { padding: 1px 3px; font-size: 10px; }
}
/* --- Mobile app (only shown on mobile) --- */
.mobile-app {
display: none;
}
.mobile-fab {
display: none;
}
@media (max-width: 768px), (pointer: coarse) and (max-device-width: 500px), (pointer: coarse) and (max-device-height: 500px) {
/* Hide desktop layout on mobile */
.app, .nav-reopen-btn, .mobile-nav-backdrop { display: none !important; }
.app-statusbar { display: none; }
#mobile-editor-body #note-meta { display: none !important; }
#mobile-editor-body > #note-meta {
display: none !important;
height: 0 !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
/* Show mobile app */
.mobile-app {
display: flex;
position: fixed;
inset: 0 env(safe-area-inset-right, 0px) 0 env(safe-area-inset-left, 0px);
overflow: hidden;
background: var(--bg);
}
/* Each screen fills the container */
.mobile-screen {
position: absolute;
inset: 0;
display: none;
flex-direction: column;
background: var(--bg);
pointer-events: none;
}
.mobile-screen-active {
display: flex;
pointer-events: auto;
}
/* Header bar */
.mobile-header {
display: flex;
align-items: center;
height: calc(44px + env(safe-area-inset-top, 0px));
padding-top: env(safe-area-inset-top, 0px);
padding-left: 4px;
padding-right: 4px;
background: var(--bg-side);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
gap: 4px;
}
.mobile-header-title {
flex: 1;
min-width: 0;
font-size: 17px;
font-weight: 600;
color: var(--text);
padding: 0 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mobile-editor-title-editable[contenteditable="true"] {
cursor: text;
outline: none;
border-bottom: 1px solid transparent;
transition: border-color 0.15s;
}
.mobile-editor-title-editable[contenteditable="true"]:focus {
border-bottom-color: var(--accent);
white-space: normal;
overflow: visible;
text-overflow: clip;
}
.mobile-editor-title-editable:empty:before {
content: attr(data-placeholder);
color: var(--text-muted, #888);
pointer-events: none;
}
.mobile-header-btn {
background: none;
border: none;
color: var(--accent);
font-size: 22px;
line-height: 1;
padding: 6px 10px;
cursor: pointer;
flex-shrink: 0;
font-family: inherit;
}
.mobile-editor-search-header {
padding-left: 8px;
padding-right: 8px;
}
.mobile-editor-search-input {
flex: 1;
min-width: 0;
height: 34px;
padding: 0 10px;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--bg-input);
color: var(--text);
font: inherit;
}
.mobile-editor-search-input:focus {
outline: none;
border-color: var(--border-focus);
}
.mobile-search-nav-counter {
flex-shrink: 0;
min-width: 40px;
text-align: center;
font-size: 12px;
font-variant-numeric: tabular-nums;
color: var(--text);
}
.mobile-search-nav-btn {
width: 34px;
height: 34px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--bg-input);
color: var(--text);
font-size: 16px;
}
.mobile-mode-toggle {
width: 34px;
height: 34px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--bg-input);
color: var(--text-muted);
font-size: 11px;
font-weight: 600;
flex-shrink: 0;
}
.mobile-header-btn.mobile-mode-toggle.active {
background: var(--accent);
border-color: var(--accent);
color: var(--text-on-accent);
}
.mobile-back-btn {
font-size: 28px;
padding: 2px 8px;
position: relative;
z-index: 1;
}
.mobile-editor-status {
flex-shrink: 0;
font-size: 12px;
color: var(--text-muted);
min-width: 3.5em;
text-align: right;
}
.mobile-editor-status .autosave-ok,
.mobile-editor-status .autosave-edited,
.mobile-editor-status .autosave-error,
.mobile-editor-status .autosave-saving {
font-size: 12px;
opacity: 1;
}
/* Screen body */
.mobile-screen-body {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
}
/* The folder and note lists end clear of the floating "+" (56px tall, 20px above the
bottom edge, so 76px) plus breathing room and the home indicator. Without this the last
row's count / "+" / chevron (or "Load more") sit under the button and cannot be scrolled
out from beneath it. Scoped to the two list bodies: the editor body shares
.mobile-screen-body and must not get padding. */
#mobile-folders-body,
#mobile-notes-body {
padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
}
/* Editor body must not scroll at the outer level — TinyMCE scrolls internally.
overflow:hidden + overscroll-behavior:none kills iOS rubber-band on the shell. */
.mobile-editor-body {
display: flex;
flex-direction: column;
overflow: hidden;
overscroll-behavior: none;
min-width: 0;
position: relative;
}
.mobile-editor-body .col-editor,
.mobile-editor-body > form {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
min-width: 0;
position: absolute;
inset: 0;
width: 100%;
}
.mobile-editor-body > form > * {
min-height: 0;
}
/* Folder rows */
.mobile-folder-row {
display: flex;
align-items: center;
flex-wrap: nowrap;
width: 100%;
background: none;
border: none;
border-bottom: 1px solid var(--border);
padding: 14px 16px;
gap: 10px;
cursor: pointer;
color: var(--text);
font-size: 15px;
font-family: inherit;
text-align: left;
}
.mobile-folder-row:active { background: var(--bg-hover); }
/* display:flex above beats the UA [hidden] rule, so restate it. */
.mobile-folder-row[hidden] { display: none; }
/* Nested notebooks: indent per level (capped at 4 by the server). */
.mobile-folder-row { padding-left: calc(16px + var(--m-depth, 0) * 18px); }
/* Chevron is its own 44px-tall tap target; the row itself still opens the notes. */
.mobile-folder-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 28px;
align-self: stretch;
margin: -14px 0 -14px -8px;
color: var(--text-muted);
font-size: 16px;
transition: transform 0.12s;
}
.mobile-folder-toggle-placeholder { visibility: hidden; }
.mobile-folder-row.expanded > .mobile-folder-toggle { transform: rotate(90deg); }
.mobile-folder-icon { font-size: 16px; flex-shrink: 0; color: var(--accent); }
.mobile-folder-title { flex: 1 1 auto; min-width: 0; }
.mobile-folder-count { color: var(--text-muted); font-size: 13px; flex-shrink: 0; }
.mobile-vault-folder-lock {
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
line-height: 1;
font-size: 16px;
}
.mobile-folder-add {
color: var(--accent);
font-size: 24px;
line-height: 1;
padding: 0 6px;
flex-shrink: 0;
}
.mobile-folder-arrow { color: var(--text-muted); font-size: 20px; flex-shrink: 0; }
/* Note rows */
.mobile-note-row {
display: flex;
align-items: center;
width: 100%;
background: none;
border: none;
border-bottom: 1px solid var(--border);
padding: 14px 16px;
gap: 10px;
cursor: pointer;
color: var(--text);
font-size: 15px;
font-family: inherit;
text-align: left;
}
.mobile-note-row:active { background: var(--bg-hover); }
.mobile-note-title { flex: 1; }
.mobile-note-arrow { color: var(--text-muted); font-size: 20px; }
/* Editor inside mobile */
.mobile-editor-body .editor-titlebar {
padding: 8px 12px;
flex-wrap: nowrap;
}
.mobile-editor-body .editor-folder-select,
.mobile-editor-body .editor-folder-arrow,
.mobile-editor-body #mobile-delete-btn {
display: none;
}
.mobile-hidden-folder-select {
display: none !important;
}
.mobile-editor-body .editor-title {
font-size: 15px;
}
.mobile-editor-body .cm-host .cm-content,
.mobile-editor-body .editor-preview {
font-size: var(--font-size-note-mobile, var(--font-size-note));
}
.mobile-editor-body .cm-host,
.mobile-editor-body .editor-preview {
flex: 1;
min-height: 0;
height: 0;
}
/* FAB */
.mobile-fab {
position: fixed;
bottom: calc(20px + env(safe-area-inset-bottom, 0px));
right: calc(20px + env(safe-area-inset-right, 0px));
width: 56px;
height: 56px;
border-radius: 50%;
background: var(--accent);
color: #000;
font-size: 28px;
line-height: 1;
border: none;
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
z-index: 100;
box-shadow: 0 4px 16px var(--shadow);
}
.mobile-fab-menu-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.2);
z-index: 109;
}
.mobile-fab-menu {
position: fixed;
right: calc(20px + env(safe-area-inset-right, 0px));
bottom: calc(88px + env(safe-area-inset-bottom, 0px));
background: var(--bg-side);
border: 1px solid var(--border);
border-radius: 0;
box-shadow: 0 8px 24px var(--shadow);
z-index: 110;
min-width: 180px;
overflow: hidden;
}
.mobile-fab-menu-btn {
display: block;
width: 100%;
background: none;
border: none;
text-align: left;
padding: 18px 20px;
font: inherit;
font-size: 18px;
color: var(--text);
min-height: 56px;
}
.mobile-fab-menu-btn:active { background: var(--bg-hover); }
.mobile-fab-menu-cancel {
border-top: 1px solid var(--border);
color: var(--text-muted);
}
/* Context menu bottom sheet */
.mobile-ctx-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.45);
z-index: 200;
}
.mobile-ctx-sheet {
position: fixed;
left: 0; right: 0; bottom: 0;
background: var(--bg-side);
border-radius: 0;
padding: 8px env(safe-area-inset-right, 0px) calc(16px + env(safe-area-inset-bottom, 0px)) env(safe-area-inset-left, 0px);
z-index: 201;
box-shadow: 0 -4px 24px var(--shadow);
animation: mobileCtxSlideUp 0.2s cubic-bezier(0.4,0,0.2,1);
}
@keyframes mobileCtxSlideUp {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.mobile-ctx-title {
font-size: 15px;
color: var(--text-muted);
text-align: center;
padding: 10px 16px 14px;
border-bottom: 1px solid var(--border);
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mobile-ctx-meta {
font-size: 12px;
color: var(--text-dim);
text-align: center;
padding: 6px 16px 10px;
border-bottom: 1px solid var(--border);
margin-bottom: 4px;
}
.mobile-ctx-btn {
display: block;
width: 100%;
background: none;
border: none;
color: var(--text);
font-size: 18px;
font-family: inherit;
text-align: left;
padding: 16px 20px;
cursor: pointer;
min-height: 56px;
}
.mobile-ctx-btn:active { background: var(--bg-hover); }
.mobile-ctx-btn:disabled {
opacity: 0.55;
}
.mobile-ctx-btn-cancel {
color: var(--text-muted);
border-top: 1px solid var(--border);
margin-top: 4px;
}
.mobile-folder-picker-sheet {
max-height: min(70vh, 520px);
display: flex;
flex-direction: column;
}
.mobile-folder-picker-list {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 4px;
}
.mobile-folder-picker-btn.is-current {
color: var(--text-muted);
}
}
/* Forced UI mode overrides (user setting) */
body.force-mobile .app,
body.force-mobile .nav-reopen-btn,
body.force-mobile .mobile-nav-backdrop,
body.force-mobile .app-statusbar { display: none !important; }
body.force-mobile #mobile-editor-body #note-meta { display: none !important; }
body.force-mobile #mobile-editor-body > #note-meta {
display: none !important;
height: 0 !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
body.force-mobile .mobile-editor-body {
position: relative;
}
body.force-mobile .mobile-editor-body > form {
position: absolute;
inset: 0;
width: 100%;
}
body.force-mobile .mobile-app {
display: flex !important;
position: fixed;
/* left/right keep clear of a landscape notch or Dynamic Island (0 in portrait and in browsers) */
inset: 0 env(safe-area-inset-right, 0px) 0 env(safe-area-inset-left, 0px);
overflow: hidden;
background: var(--bg);
}
body.force-mobile .mobile-fab { display: flex; }
/* While a soft keyboard is up, public/viewport.js sizes the shell to the visible area and keeps it
at the top of that area (and pins the page scroll at 0). iOS then has nothing to scroll into
view, so the header and the markdown toolbar stay on screen. Outside that state .mobile-app is
inset:0 exactly as before. */
html[data-keyboard] .mobile-app,
html[data-keyboard] body.force-mobile .mobile-app {
top: var(--app-top, 0px);
bottom: auto;
height: var(--app-height);
}
/* Hide the custom toolbar in mobile rich (TinyMCE) mode — applies at any viewport width.
TinyMCE's own built-in toolbar is rendered inside the editor host instead.
In markdown/preview mode body.mobile-markdown-mode is set, restoring it. */
#mobile-editor-body .editor-toolbar {
display: none;
}
body.mobile-markdown-mode #mobile-editor-body .editor-toolbar {
display: flex;
}
body.force-desktop .mobile-app { display: none !important; }
body.force-desktop .mobile-fab { display: none !important; }
body.force-desktop .app { display: flex !important; }
body.force-desktop .app-statusbar { display: flex !important; }
/* Disable mobile screen slide transitions during resize to prevent glitching */
body.resizing .mobile-screen,
body.resizing .mobile-screen-active,
body.resizing .mobile-screen-left,
body.resizing .mobile-screen-right { transition: none !important; }
/* Mobile locked editor */
@media (max-width: 768px), (pointer: coarse) and (max-device-width: 500px), (pointer: coarse) and (max-device-height: 500px) {
.editor-locked {
padding: 60px 20px;
}
.editor-locked-password {
max-width: 100%;
font-size: 16px;
}
}
.settings-tabs {
display: flex;
gap: 2px;
border-bottom: 1px solid var(--border);
margin-bottom: 0;
padding: 0 0 0 0;
}
.settings-tab {
background: none;
border: none;
border-bottom: 2px solid transparent;
color: var(--text-muted);
cursor: pointer;
font-size: 13px;
padding: 8px 16px;
font-family: inherit;
transition: color 0.15s, border-color 0.15s;
margin-bottom: -1px;
}
@media (hover: hover) {
.settings-tab:hover { color: var(--text); }
}
.settings-tab.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.settings-tab-panel { display: none; }
.settings-tab-panel.active { display: block; }
@media (max-width: 768px), (pointer: coarse) and (max-device-width: 500px), (pointer: coarse) and (max-device-height: 500px) {
.settings-page {
padding: calc(16px + env(safe-area-inset-top, 0px)) 12px calc(20px + env(safe-area-inset-bottom, 0px));
}
.settings-card {
width: 100%;
padding: 16px;
border-radius: 0;
overflow: hidden;
}
.settings-header {
flex-direction: column;
align-items: stretch;
gap: 12px;
}
.settings-header .btn {
align-self: flex-start;
}
.settings-tabs {
display: grid;
grid-template-columns: 1fr;
gap: 6px;
border-bottom: 0;
margin: 0 0 12px;
}
.settings-tab {
width: 100%;
padding: 12px 14px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-elevated);
text-align: left;
font-size: 16px;
margin-bottom: 0;
}
.settings-tab.active {
border-color: var(--accent);
background: var(--bg-active);
}
.settings-grid {
grid-template-columns: 1fr;
}
.settings-actions {
justify-content: stretch;
}
.settings-actions .btn,
.settings-actions .btn-primary {
width: 100%;
}
.ai-profiles-bar {
display: grid;
grid-template-columns: 1fr 1fr;
align-items: stretch;
}
.ai-profiles-bar-label {
grid-column: 1 / -1;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
}
.ai-active-select {
width: 100%;
max-width: 100%;
}
.ai-profiles-bar .btn {
width: 100%;
}
.ai-profile-header {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: stretch;
}
.ai-profile-name-input,
.ai-profile-provider-select,
.ai-profile-header .btn {
width: 100%;
max-width: 100%;
}
.ai-profile-header .badge {
justify-self: start;
}
}
/* --- Flash messages --- */
.settings-flash {
margin: 0 0 12px 0;
padding: 8px 14px;
border-radius: 0;
font-size: 13px;
font-weight: 500;
}
.settings-flash-ok { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); }
.settings-flash-err { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent); }
/* --- Admin table --- */
.admin-table-wrap { overflow-x: auto; }
.admin-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
margin-top: 8px;
}
.admin-table th, .admin-table td {
text-align: left;
padding: 7px 10px;
border-bottom: 1px solid var(--border);
}
.admin-table th { color: var(--text-muted); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; }
.admin-table tr:last-child td { border-bottom: none; }
@media (hover: hover) {
.admin-table tr:hover td { background: color-mix(in srgb, var(--accent) 6%, transparent); }
}
.admin-actions-cell { white-space: nowrap; }
.admin-inline-form { display: inline; margin: 0; }
.admin-backup-actions { display: inline-flex; align-items: center; gap: 6px; }
/* --- Badges --- */
.badge { display: inline-block; padding: 2px 7px; border-radius: 0; font-size: 11px; font-weight: 600; }
.badge-ok { background: color-mix(in srgb, var(--accent) 20%, transparent); color: var(--accent); }
.badge-off { background: color-mix(in srgb, var(--text-muted) 20%, transparent); color: var(--text-muted); }
.badge-mfa { background: color-mix(in srgb, #8b5cf6 20%, transparent); color: #a78bfa; margin-left: 4px; }
/* --- Admin user modal --- */
.admin-modal {
border: none;
border-radius: 0;
padding: 0;
background: var(--bg-elevated);
color: var(--text);
max-width: 420px;
width: calc(100% - 32px);
max-height: calc(100vh - 32px);
max-height: calc(100dvh - 32px);
overflow: hidden;
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
}
.admin-modal::backdrop {
background: rgba(0,0,0,0.6);
backdrop-filter: blur(4px);
}
.admin-modal-content {
display: flex;
flex-direction: column;
max-height: calc(100vh - 32px);
max-height: calc(100dvh - 32px);
overflow-y: auto;
}
.admin-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid var(--border);
}
.admin-modal-header h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
}
.admin-modal-close {
background: none;
border: none;
font-size: 28px;
line-height: 1;
color: var(--text-muted);
cursor: pointer;
padding: 0 4px;
}
@media (hover: hover) {
.admin-modal-close:hover { color: var(--text); }
}
.admin-modal-user {
display: flex;
flex-direction: column;
gap: 4px;
padding: 16px 20px;
background: var(--bg-side);
border-bottom: 1px solid var(--border);
}
.admin-modal-user strong { font-size: 16px; }
.admin-modal-user span { font-size: 14px; color: var(--text-muted); }
.admin-modal-user .badge { align-self: flex-start; margin-top: 4px; }
.admin-modal-actions {
padding: 16px 20px;
display: flex;
flex-direction: column;
gap: 16px;
}
.admin-modal-form {
display: flex;
flex-direction: column;
gap: 8px;
}
.admin-modal-label {
font-weight: 600;
font-size: 14px;
}
.admin-modal-hint {
font-size: 13px;
color: var(--text-muted);
margin: 0 0 4px 0;
}
.admin-modal-row {
display: flex;
gap: 8px;
}
.admin-modal-row .login-input { flex: 1; }
.admin-modal-divider {
height: 1px;
background: var(--border);
margin: 4px 0;
}
.admin-modal-footer {
padding: 12px 20px 16px;
border-top: 1px solid var(--border);
}
.btn-block { width: 100%; }
/* Admin TOTP reveal */
.admin-totp-details { margin-top: 8px; }
.admin-totp-details > summary { cursor: pointer; }
.admin-totp-reveal {
margin-top: 12px;
padding: 12px;
background: var(--bg-side);
border-radius: 0;
text-align: center;
}
.admin-totp-qr {
width: 140px;
height: 140px;
background: #fff;
border-radius: 0;
padding: 8px;
margin-bottom: 8px;
}
.admin-totp-seed {
display: block;
font-size: 12px;
word-break: break-all;
color: var(--text-muted);
}
/* --- Code block copy button --- */
.editor-preview pre { position: relative; }
.pre-copy-btn {
position: sticky;
top: 6px;
float: right;
margin: -22px 0 8px 12px;
z-index: 1;
padding: 2px 8px;
font-size: 11px;
font-family: inherit;
background: var(--bg-elevated);
color: var(--text-muted);
border: 1px solid var(--border);
border-radius: 4px;
cursor: pointer;
opacity: 0;
transition: opacity 0.15s, color 0.15s;
line-height: 1.6;
}
@media (hover: hover) {
.editor-preview pre:hover .pre-copy-btn { opacity: 1; }
}
@media (hover: hover) {
.pre-copy-btn:hover { color: var(--accent); border-color: var(--accent); }
}
mark.search-highlight {
background: #ffe066;
color: #111;
border-radius: 0;
padding: 0 1px;
}
.theme-light mark.search-highlight { background: #ffe066; color: #111; }
.search-nav-bar {
display: flex;
align-items: center;
gap: 4px;
padding: 3px 8px;
background: #ffe066;
border-bottom: 1px solid #e6c800;
color: #111;
flex-shrink: 0;
}
.search-nav-bar[hidden] { display: none; }
.search-nav-counter { min-width: 48px; font-variant-numeric: tabular-nums; }
.search-nav-btn {
background: none;
border: 1px solid #b8960a;
border-radius: 0;
color: #111;
cursor: pointer;
font-size: 11px;
line-height: 1;
padding: 2px 5px;
}
@media (hover: hover) {
.search-nav-btn:hover { border-color: #333; background: rgba(0,0,0,0.08); }
}
.search-nav-close { margin-left: auto; }
/* Remote-update bar reuses .search-nav-bar layout; this rule lets the message
take the remaining space so the action buttons pack to the right. */
.remote-update-bar .remote-update-text { flex: 1; }
mark.search-highlight-active {
background: #ff9800;
color: #111;
border-radius: 0;
padding: 0 1px;
}
/* --- Encryption UI --- */
.note-lock-icon {
font-size: 13px;
margin-right: 4px;
opacity: 0.7;
flex-shrink: 0;
display: inline-flex;
align-items: center;
color: #FFC107;
}
.note-lock-icon.note-lock-unlocked {
color: var(--accent);
opacity: 0.9;
}
.notelist-item {
display: flex;
align-items: center;
width: 100%;
padding: 8px 12px;
text-align: left;
border-bottom: 1px solid var(--border);
transition: background 0.1s;
}
.editor-locked {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
gap: 12px;
padding: 40px 20px;
min-height: 200px;
}
.editor-locked-icon {
font-size: 48px;
opacity: 0.5;
color: #FFC107;
}
.editor-locked-icon .vault-svg-icon {
width: 48px;
height: 48px;
}
.editor-locked-text {
font-size: 16px;
color: var(--text-dim);
}
.editor-locked-password {
width: 100%;
max-width: 280px;
padding: 10px 14px;
border: 1px solid var(--border);
border-radius: 0;
background: var(--bg-input, var(--bg-hover));
color: var(--text);
font-size: 15px;
text-align: center;
}
.editor-locked-password:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 20%, transparent);
}
.editor-locked-btn {
min-width: 120px;
}
.editor-locked-actions {
display: flex;
gap: 8px;
justify-content: center;
flex-wrap: wrap;
}
.editor-locked-error {
color: var(--danger, #e06c75);
font-size: 13px;
min-height: 18px;
}
.autosave-encrypted {
color: var(--accent);
font-size: 11px;
opacity: 0.8;
}
.lock-modal-warning {
font-size: 13px;
color: var(--danger, #e06c75);
margin: 0 0 8px;
line-height: 1.4;
}
.lock-modal-checkbox {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: var(--text-dim);
margin: 4px 0;
cursor: pointer;
}
.lock-modal-error {
color: var(--danger, #e06c75);
font-size: 13px;
min-height: 18px;
}
#tb-remove-lock, #tb-change-password {
font-size: 11px;
white-space: nowrap;
}
/* Vault folder styles */
.nav-folder-vault > .nav-folder-row {
/* subtle accent to distinguish vault folders */
}
.vault-folder-lock {
font-size: 14px;
opacity: 0.85;
background: none;
border: none;
cursor: pointer;
padding: 0 2px;
color: #FFC107;
line-height: 1;
flex-shrink: 0;
}
@media (hover: hover) {
.vault-folder-lock:hover {
opacity: 1;
color: #FFC107;
}
}
/* SVG lock icons */
.vault-svg-icon {
width: 1em;
height: 1em;
display: inline-block;
vertical-align: -0.125em;
}
/* Mobile lock icon in note row */
.mobile-note-row .note-lock-icon {
font-size: 13px;
margin-right: 6px;
}
/* Link-copied toast */
#link-copied-toast {
position: fixed;
z-index: 99999;
background: var(--accent);
color: #fff;
font-size: 13px;
padding: 4px 10px;
border-radius: 0;
pointer-events: none;
opacity: 0;
transform: translate(-50%, -120%);
transition: opacity 0.15s;
}
#link-copied-toast.visible {
opacity: 1;
}
/* ===== Touch devices =====
Controls are not text: a long press on a row, a tab or a button opens no loupe or link callout,
and a quick second tap does not zoom the page (pinch zoom stays; WCAG 1.4.4). Note text, fields
and the editors keep selection. */
@media (hover: none) and (pointer: coarse) {
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
a,
button,
input,
select,
textarea,
summary,
label,
[role="button"],
[role="tab"],
.mobile-folder-row,
.mobile-note-row,
.nav-folder-row,
.notelist-item {
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
.mobile-header,
.mobile-folder-row,
.mobile-note-row,
.mobile-fab,
.mobile-fab-menu,
.mobile-ctx-sheet,
.editor-toolbar,
.nav-folder-row,
.notelist-item,
.settings-tab,
button,
[role="button"],
[role="tab"],
summary {
-webkit-user-select: none;
user-select: none;
-webkit-touch-callout: none;
}
input,
textarea,
[contenteditable],
.cm-content {
-webkit-user-select: text;
user-select: text;
}
}
/* Reduced motion: no slides, fades or pulses. The loading ring is progress, not decoration, so it
keeps turning. */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
transition-duration: 0.01ms !important;
transition-delay: 0s !important;
scroll-behavior: auto !important;
}
*:not(.note-loading-ring) {
animation: none !important;
}
}
/* Short windows: a phone in landscape (about 390px tall), or any phone with the keyboard up. The
shell's fixed chrome (title bar 44px + toolbar 67px) is most of that, so tighten it. These
elements exist only in the mobile shell, so a tablet's desktop layout is unaffected. */
@media (max-height: 500px) {
.mobile-header {
height: calc(36px + env(safe-area-inset-top, 0px));
}
.mobile-app .editor-toolbar {
padding: 4px 10px;
}
.mobile-app .editor-toolbar .tb {
min-width: 40px;
height: 34px;
font-size: 16px;
}
}
/* Landscape with the keyboard up leaves room for little more than the toolbar and a few lines of
text: the editor's title bar (back, search, menu) steps aside until the keyboard is dismissed. */
@media (max-height: 500px) and (orientation: landscape) {
html[data-keyboard] #mobile-editor-header {
display: none;
}
}