  :root {
    /* Tells browser chrome (status-bar text, form controls, soft keyboard,
       overscroll canvas) which appearance the page renders. Keyed off
       data-resolved, so a manual theme toggle retunes it too. */
    color-scheme: light;
    --bg:#ffffff; --surface:#fbfbfa; --surface-2:#f1f1ef; --sidebar:#f7f7f5;
    --fg:#2c2c30; --fg-soft:#5b5b62; --muted:#75757f; --line:#ebebe8; --line-strong:#dededb;
    --accent:#4a55d6; --accent-fg:#ffffff; --accent-soft:#eef0ff; --danger:#d6473b; --danger-soft:#fdeceb;
    --success:#1f8f3e;
    --hover:rgba(45,45,55,.045); --hover-2:rgba(45,45,55,.08);
    --shadow-sm:0 1px 2px rgba(20,20,40,.06),0 1px 1px rgba(20,20,40,.04);
    --shadow-md:0 4px 12px rgba(20,20,40,.08),0 2px 4px rgba(20,20,40,.05);
    --shadow-lg:0 16px 48px rgba(20,20,40,.16),0 4px 12px rgba(20,20,40,.08);
    --radius:8px; --radius-sm:6px; --radius-lg:14px; --radius-xl:16px;
    --fs-body:14px; --fs-ui:13.5px; --fs-sm:12.5px; --fs-xs:11.5px; --fs-micro:11px;
    --ui:"Hanken Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
    --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,monospace;
    --note-lh:1.6;
    --code-bg:#f8f8f6;
    --hl-cmt:#9a9aa2; --hl-key:#a626a4; --hl-str:#28823f; --hl-num:#b76a00;
    --hl-fn:#3f51d6; --hl-type:#0a7ea4; --hl-var:#c2410c;
  }
  /* Dark palette — exactly once. JS resolves the user's choice (including
   * "system" → the OS preference) to <html data-resolved="light|dark"> before
   * first paint (FOUC script in the shell) and on every change (theme.ts), so
   * CSS never needs a prefers-color-scheme duplicate of this block. */
  :root[data-resolved="dark"] {
    color-scheme: dark;
    --bg:#1a1a1c; --surface:#202022; --surface-2:#2a2a2d; --sidebar:#171719;
    --fg:#e6e6e9; --fg-soft:#b4b4bb; --muted:#8b8b95; --line:#2c2c30; --line-strong:#3a3a40;
    --accent:#7b86ff; --accent-fg:#14141a; --accent-soft:#23243a; --danger:#f87168; --danger-soft:#341e1c;
    --success:#3fb950;
    --hover:rgba(255,255,255,.05); --hover-2:rgba(255,255,255,.09);
    --shadow-sm:0 1px 2px rgba(0,0,0,.4); --shadow-md:0 4px 14px rgba(0,0,0,.45); --shadow-lg:0 20px 56px rgba(0,0,0,.6);
    --code-bg:#1d1d20;
    --hl-cmt:#7d7d86; --hl-key:#d291e4; --hl-str:#7ed492; --hl-num:#e0a566;
    --hl-fn:#86a8ff; --hl-type:#5fc6e0; --hl-var:#f0936b;
  }
  * { box-sizing: border-box; }
  html, body { margin: 0; height: 100%; }
  /* Explicit backgrounds on BOTH html and body: iOS 26 Safari tints its liquid
     glass chrome by sampling page CSS (theme-color is ignored there), and a
     transparent root is a known path to white toolbars on dark pages. */
  html { background: var(--bg); scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
  /* Honor reduced motion everywhere; near-zero (not none) so animationend /
     final keyframe states still apply. The empty-state illustration adds its
     own targeted overrides below. */
  @media (prefers-reduced-motion: reduce) {
    *, ::before, ::after {
      animation-duration:.01ms !important; animation-iteration-count:1 !important;
      transition-duration:.01ms !important;
    }
  }
  body { font-family: var(--ui); font-size: var(--fs-body); line-height: 1.55; color: var(--fg); background: var(--bg);
    overflow: hidden; text-rendering: auto; }
  button { font: inherit; color: inherit; cursor: pointer; background: none; border: 0; padding: 0; }
  input, textarea { font: inherit; color: inherit; }
  /* Keyboard focus must be visible everywhere (mouse/touch :focus stays clean
     via :focus-visible). :where() keeps specificity at zero so any component
     can override; contentEditable surfaces keep their caret as the indicator. */
  :where(button, [role="button"], select, [tabindex]):focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px;
  }
  .muted { color: var(--muted); }
  svg { display: block; }
  .ico { width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:1.75; stroke-linecap:round; stroke-linejoin:round; flex:none; }
  .ico.sm { width:14px; height:14px; }
  ::-webkit-scrollbar { width:10px; height:10px; }
  ::-webkit-scrollbar-thumb { background:var(--line-strong); border-radius:8px; border:3px solid transparent; background-clip:padding-box; }
  ::-webkit-scrollbar-thumb:hover { background:var(--muted); background-clip:padding-box; border:3px solid transparent; }
  /* Scroll containers swallow their own overscroll: no rubber-banding the whole
     page / accidental pull-to-refresh when an inner list hits its end. */
  .content, .sb-scroll, .peek-body, .modal-body, .pop, .qn-body { overscroll-behavior:contain; }
  .tablescroll, .tl-scroll, .board { overscroll-behavior-x:contain; }

  /* dvh tracks the *visible* viewport on mobile (iOS Safari's collapsing
     address bar); the vh line before it is the fallback older engines keep. */
  #app { display: flex; height: 100vh; height: 100dvh; }

  /* sidebar */
  .sidebar { width:268px; flex:none; background:var(--sidebar); border-right:1px solid var(--line);
    display:flex; flex-direction:column; position:relative; transition:margin-left .22s cubic-bezier(.4,0,.2,1); }
  /* right:-4px (not -3): the 7px handle then straddles the 1px border line
     symmetrically (3.5px each side of the border's center), so the centered
     ::before grip line lands exactly on the border instead of 1px left of it. */
  .sb-resizer { position:absolute; top:0; right:-4px; width:7px; height:100%; cursor:col-resize; z-index:5; }
  /* Unified resize-handle visual (sidebar + datasheet/doc-table column resizers):
     the handle stays an invisible hit area; a centered 3px round-capped line
     fades/expands in on hover and solidifies with a soft halo while dragging.
     --rz-guide-h (written by startColumnResize) stretches the dragging line to
     the full table height so the new column edge is visible across all rows. */
  .sb-resizer::before, .col-resizer::before, .doc-col-resizer::before {
    content:""; position:absolute; left:50%; top:0; height:100%; width:3px;
    transform:translateX(-50%) scaleX(.4); border-radius:999px;
    background:var(--accent); opacity:0; pointer-events:none;
    transition:opacity .15s cubic-bezier(.4,0,.2,1), transform .15s cubic-bezier(.4,0,.2,1), box-shadow .15s; }
  .sb-resizer:hover::before, .col-resizer:hover::before, .doc-col-resizer:hover::before {
    opacity:.6; transform:translateX(-50%) scaleX(1); }
  .sb-resizer.dragging::before, .col-resizer.dragging::before, .doc-col-resizer.dragging::before {
    opacity:1; transform:translateX(-50%) scaleX(1);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
    height:var(--rz-guide-h, 100%); }
  .sb-head { display:flex; align-items:center; gap:8px; padding:14px 14px 10px; }
  .brand { display:flex; align-items:center; gap:8px; flex:1; font-weight:700; font-size:15px; letter-spacing:-.01em; }
  .brand .mark { width:24px; height:24px; border-radius:7px;
    background:linear-gradient(135deg,var(--accent),color-mix(in srgb,var(--accent) 60%,#fff));
    display:grid; place-items:center; color:#fff; box-shadow:var(--shadow-sm); }
  .brand .mark svg { width:15px; height:15px; stroke:#fff; }
  .sb-search { margin:0 12px 8px; display:flex; align-items:center; gap:7px; cursor:text;
    background:var(--bg); border:1px solid var(--line); border-radius:var(--radius-sm); padding:6px 9px; color:var(--muted);
    box-shadow:var(--shadow-sm); transition:border-color .15s; }
  .sb-search:focus-within { border-color:var(--accent); }
  .sb-search input { border:0; background:none; outline:none; color:var(--fg); width:100%; }
  .sb-search kbd { font-family:var(--mono); font-size:10px; color:var(--muted); border:1px solid var(--line-strong); border-radius:4px; padding:1px 4px; }
  .sb-scroll { flex:1; overflow-y:auto; padding:4px 8px 24px; }
  .sb-section { margin-top:12px; }
  .sb-section-head { display:flex; align-items:center; justify-content:space-between;
    font-size:var(--fs-micro); font-weight:600; text-transform:uppercase; letter-spacing:.06em; color:var(--muted); padding:4px 8px; }
  .sb-section-head .add { opacity:0; padding:3px; border-radius:5px; color:var(--muted); transition:opacity .12s; }
  .sb-section:hover .add { opacity:1; }
  .sb-section-head .add:hover { background:var(--hover-2); color:var(--fg); }
  .navitem { display:flex; align-items:center; gap:3px; width:100%; text-align:left; padding:5px 6px; margin-bottom:2px; border-radius:var(--radius-sm);
    color:var(--fg-soft); font-size:var(--fs-ui); position:relative; white-space:nowrap; transition:background .1s; }
  .navitem:hover { background:var(--hover-2); }
  .navitem.active { background:var(--bg); color:var(--fg); font-weight:600; box-shadow:var(--shadow-sm); }
  .navitem .tw { width:18px; height:18px; display:grid; place-items:center; color:var(--muted); border-radius:4px; flex:none; }
  .navitem .tw:hover { background:var(--hover-2); }
  .navitem .tw svg { width:13px; height:13px; transition:transform .12s; }
  .navitem .tw.open svg { transform:rotate(90deg); }
  .navitem .emoji { width:20px; text-align:center; flex:none; font-size:var(--fs-body); }
  .navitem .label { flex:1; overflow:hidden; text-overflow:ellipsis; }
  .navitem .acts { display:flex; gap:1px; opacity:0; }
  .navitem:hover .acts { opacity:1; }
  .navitem .acts button { width:22px; height:22px; display:grid; place-items:center; color:var(--muted); border-radius:5px; }
  .navitem .acts button:hover { background:var(--hover-2); color:var(--fg); }
  .navchildren { margin-left:16px; border-left:1px solid var(--line-strong); padding-left:2px; }
  .navitem.drop-into { box-shadow:inset 0 0 0 2px var(--accent); }
  .navitem.drop-before { box-shadow:inset 0 2px 0 0 var(--accent); }
  .navitem.drop-after { box-shadow:inset 0 -2px 0 0 var(--accent); }
  .dragging { opacity:.35; }
  /* Slim status row: sites/settings icon buttons left, version right. */
  .sb-footer { flex:none; display:flex; align-items:center; gap:2px; padding:5px 10px; border-top:1px solid var(--line); }
  .sb-footer .sb-act { display:grid; place-items:center; width:28px; height:28px; flex:none;
    border-radius:var(--radius-sm); color:var(--muted); position:relative; }
  .sb-footer .sb-act:hover { background:var(--hover-2); color:var(--fg); }
  .sb-footer .sb-act.active { background:var(--bg); color:var(--fg); box-shadow:var(--shadow-sm); }
  .sb-footer .sb-act .nav-dot { position:absolute; top:4px; right:4px; box-shadow:0 0 0 2px var(--sidebar); }
  .sbf-ver { margin-left:auto; font-family:var(--mono); font-size:var(--fs-micro); color:var(--muted);
    letter-spacing:-.01em; user-select:text; }
  /* Sites/settings as sb-head icon buttons — the mobile home's replacement for
     the .sb-footer row (swapped in the mobile media block below). */
  .sb-act { display:none; }
  .nav-dot { flex:none; width:7px; height:7px; border-radius:50%; background:var(--danger);
    box-shadow:0 0 0 2px var(--surface); margin-right:2px; }

  /* settings page */
  .set-page { max-width:680px; margin:0 auto; padding:40px 28px 64px; }
  .set-title { font-size:26px; font-weight:700; letter-spacing:-.02em; color:var(--fg); }
  .set-sub { color:var(--muted); margin-top:4px; }
  .set-section { margin-top:34px; }
  .set-section-head { font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.07em; color:var(--muted); margin-bottom:4px; }
  .set-section-desc { color:var(--fg-soft); margin-bottom:16px; }
  .set-footer { margin-top:40px; padding-top:20px; border-top:1px solid var(--line); display:flex;
    flex-wrap:wrap; justify-content:center; align-items:center; gap:7px; color:var(--muted); font-size:12px; }
  .set-footer-sep { opacity:.45; }
  .ver-num { font-family:var(--mono); font-size:var(--fs-micro); color:var(--fg-soft); letter-spacing:-.01em; }
  .ver-up { display:inline-flex; align-items:center; gap:6px; }
  .ver-up.err .ver-msg { color:var(--danger); }
  .ver-act { background:none; border:0; padding:0; margin:0; font:inherit; font-size:12px; line-height:1;
    color:var(--muted); cursor:pointer; transition:color .12s; }
  .ver-act:hover { color:var(--accent); }
  .ver-act.accent { color:var(--accent); font-weight:600; }
  .ver-act[aria-disabled="true"] { opacity:.6; cursor:default; pointer-events:none; }
  .ver-dot { width:6px; height:6px; border-radius:50%; background:var(--accent); flex:none; }
  .ver-dot.pulse { animation:verpulse 1.8s ease-in-out infinite; }
  @keyframes verpulse { 0%,100% { opacity:1; } 50% { opacity:.4; } }
  .theme-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
  .theme-card { position:relative; display:flex; flex-direction:column; align-items:flex-start; gap:10px;
    text-align:left; padding:16px; border:1px solid var(--line-strong); border-radius:var(--radius);
    background:var(--surface); color:var(--fg-soft); box-shadow:var(--shadow-sm);
    transition:border-color .14s, background .14s, transform .14s, box-shadow .14s; }
  .theme-card:hover { border-color:var(--muted); transform:translateY(-1px); }
  .theme-card .tc-ico { width:34px; height:34px; display:grid; place-items:center; border-radius:9px;
    background:var(--surface-2); color:var(--fg); }
  .theme-card .tc-ico svg { width:18px; height:18px; }
  .theme-card .tc-name { font-weight:600; font-size:var(--fs-body); color:var(--fg); }
  .theme-card .tc-desc { font-size:12px; color:var(--muted); line-height:1.45; }
  .theme-card .tc-check { position:absolute; top:10px; right:10px; width:18px; height:18px; border-radius:50%;
    background:var(--accent); color:var(--accent-fg); display:grid; place-items:center; opacity:0; transform:scale(.6); transition:opacity .14s, transform .14s; }
  .theme-card .tc-check svg { width:12px; height:12px; stroke-width:2.6; }
  .theme-card.sel { border-color:var(--accent); background:var(--accent-soft); box-shadow:0 0 0 1px var(--accent) inset, var(--shadow-sm); }
  .theme-card.sel .tc-ico { background:var(--accent); color:var(--accent-fg); }
  .theme-card.sel .tc-check { opacity:1; transform:scale(1); }
  @media (max-width:560px) { .theme-grid { grid-template-columns:1fr; } }

  /* sync devices */
  .peer-actions { display:flex; gap:10px; margin-bottom:16px; flex-wrap:wrap; }
  .peer-actions .btn { display:inline-flex; align-items:center; gap:6px; }
  .peer-list { display:flex; flex-direction:column; gap:8px; }
  .peer-row { display:flex; align-items:center; gap:12px; padding:12px 14px; border:1px solid var(--line);
    border-radius:var(--radius); background:var(--surface); }
  .peer-dot { width:9px; height:9px; border-radius:50%; flex:none; background:var(--muted); }
  .peer-dot.on { background:var(--success); } .peer-dot.err { background:var(--danger); } .peer-dot.off { background:var(--muted); }
  .peer-main { flex:1; min-width:0; }
  .peer-url { font-weight:600; font-size:var(--fs-body); color:var(--fg); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .peer-sub { font-size:12px; color:var(--muted); margin-top:2px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .peer-menu { flex:none; padding:6px; }
  .pair-code { font-family:var(--mono); font-size:26px; font-weight:700; letter-spacing:.12em;
    text-align:center; padding:16px; border:1px dashed var(--line); border-radius:var(--radius); background:var(--surface); color:var(--fg); }

  /* main */
  /* Opaque background matters: on mobile this is a full-screen fixed pane that
     iOS 26 Safari samples for its toolbar tint — transparent would read white. */
  .main { flex:1; display:flex; flex-direction:column; overflow:hidden; min-width:0; background:var(--bg); }
  .topbar { display:flex; align-items:center; gap:6px; padding:10px 18px; border-bottom:1px solid var(--line); min-height:49px; }
  .topbar.bare { border-bottom:0; }
  .topbar .hamburger { display:none; }
  .topbar .hamburger.show-collapsed { display:grid; }
  .sidebar.collapsed { overflow:hidden; }
  .sidebar.collapsed .sb-resizer { pointer-events:none; }
  .crumb { display:flex; align-items:center; gap:7px; flex:1; min-width:0; font-size:var(--fs-ui); color:var(--fg); font-weight:500; }
  .crumb .emoji { font-size:15px; } .crumb .sub { color:var(--muted); font-weight:400; }
  .iconbtn { width:30px; height:30px; display:grid; place-items:center; border-radius:var(--radius-sm); color:var(--fg-soft); transition:background .12s; }
  .iconbtn:hover { background:var(--hover-2); color:var(--fg); }
  .content { flex:1; overflow:auto; }
  .btn { display:inline-flex; align-items:center; gap:6px; padding:6px 12px; border-radius:var(--radius-sm); font-size:13px; font-weight:500; transition:all .12s; white-space:nowrap; }
  .btn-ghost { color:var(--fg-soft); } .btn-ghost:hover { background:var(--hover-2); color:var(--fg); }
  .btn-secondary { background:var(--bg); border:1px solid var(--line-strong); color:var(--fg); box-shadow:var(--shadow-sm); }
  .btn-secondary:hover { background:var(--surface-2); }
  .btn-primary { background:var(--accent); color:var(--accent-fg); box-shadow:var(--shadow-sm); }
  .btn-primary:hover { filter:brightness(1.07); }
  .btn-danger { background:var(--danger); color:#fff; } .btn-danger:hover { filter:brightness(1.05); }

  /* macOS desktop (hiddenInset frameless): drop the sidebar logo and reserve a
     draggable strip so the inset traffic lights never overlap our controls.
     Windows/Linux keep the native frame, so the logo stays. */
  body.desktop-mac .brand { display:none; }
  /* logo gone → keep the collapse button on the right (where .brand's flex used to push it) */
  body.desktop-mac .sb-head .iconbtn { margin-left:auto; }
  body.desktop-mac .sb-head { -webkit-app-region:drag; }
  body.desktop-mac .sb-head .iconbtn { -webkit-app-region:no-drag; }
  body.desktop-mac .topbar { -webkit-app-region:drag; }
  body.desktop-mac .topbar .iconbtn, body.desktop-mac .topbar .btn { -webkit-app-region:no-drag; }
  /* peek drawer header overlaps the topbar drag region → clear its buttons so they stay clickable */
  body.desktop-mac .peek-head { -webkit-app-region:drag; }
  body.desktop-mac .peek-head .iconbtn, body.desktop-mac .peek-head .btn, body.desktop-mac .peek-head .hist-toggle { -webkit-app-region:no-drag; }
  /* sidebar collapsed → traffic lights sit over the main header; clear the hamburger */
  body.desktop-mac .sidebar.collapsed ~ .main .topbar { padding-left:80px; }

  /* document editor */
  .doc { max-width:740px; margin:0 auto; padding:60px 60px 36vh; }
  .doc-title { font-size:38px; font-weight:700; letter-spacing:-.02em; outline:none; line-height:1.15; margin-bottom:4px; }
  .doc-title:empty::before { content:"无标题"; color:var(--muted); }
  .doc-meta { display:flex; gap:14px; color:var(--muted); font-size:var(--fs-sm); margin-bottom:22px; }
  .doc-meta span { display:inline-flex; align-items:center; gap:5px; }
  /* Save-conflict banner: the doc changed elsewhere; auto-save is paused until
     the user picks a side, so it must read as blocking, not as a toast. */
  .doc-conflict { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:10px 14px; margin-bottom:16px; border:1px solid var(--danger); border-radius:var(--radius-sm); background:var(--danger-soft); font-size:13px; }
  .doc-conflict-msg { color:var(--danger); font-weight:600; flex:1; min-width:180px; }
  .doc.source-mode { min-height:100%; }
  .doc-source { display:block; width:100%; min-height:calc(100vh - 210px); min-height:calc(100dvh - 210px); resize:none; border:0;
    background:transparent; color:var(--fg); outline:none; overflow:hidden; padding:3px 2px 36vh;
    font-family:var(--ui); font-size:15px; line-height:1.7; tab-size:2; }
  /* floating table of contents: a column of indented tick marks in the right
     gutter that expands to a labelled list on hover (Notion / Vercel-docs style).
     Fixed to the viewport so it never disturbs the centred .doc column. */
  .doc-toc { position:fixed; top:72px; right:18px; z-index:40; display:flex; flex-direction:column; gap:2px;
    width:24px; max-height:calc(100vh - 120px); max-height:calc(100dvh - 120px); padding:6px; box-sizing:content-box; overflow:hidden;
    border:1px solid transparent; border-radius:var(--radius); background:transparent;
    transition:width .22s ease, background .22s ease, border-color .22s ease, box-shadow .22s ease; }
  .doc-toc:hover { width:228px; overflow-y:auto; background:var(--surface); border-color:var(--line);
    box-shadow:var(--shadow-md); }
  .toc-row { display:flex; align-items:center; gap:8px; width:100%; height:24px; padding:0 2px; border-radius:var(--radius-sm);
    color:var(--muted); text-align:left; cursor:pointer; transition:color .12s, background .12s; }
  .doc-toc:hover .toc-row { padding:3px 8px; height:auto; min-height:26px; }
  .doc-toc:hover .toc-row:hover { background:var(--hover); color:var(--fg); }
  .toc-row.active { color:var(--accent); }
  /* collapsed: right-aligned ticks, length by heading level; active is accented */
  .toc-tick { flex:none; margin-left:auto; height:2px; border-radius:2px; background:var(--line-strong);
    transition:background .12s, width .22s ease, margin .22s ease; }
  .toc-row.lvl-1 .toc-tick { width:16px; }
  .toc-row.lvl-2 .toc-tick { width:11px; }
  .toc-row.lvl-3 .toc-tick { width:7px; }
  .toc-row.active .toc-tick { background:var(--accent); }
  .doc-toc:hover .toc-tick { width:0; margin:0; }
  /* expanded: labels, indented by level; hidden until hover */
  .toc-label { flex:1; min-width:0; font-size:13px; line-height:1.4; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    opacity:0; transition:opacity .18s ease; }
  .doc-toc:hover .toc-label { opacity:1; }
  .toc-row.lvl-2 .toc-label { padding-left:12px; font-size:var(--fs-sm); }
  .toc-row.lvl-3 .toc-label { padding-left:24px; font-size:var(--fs-sm); color:var(--fg-soft); }
  .toc-row.active .toc-label { color:var(--accent); font-weight:550; }
  /* not enough room for the gutter → hide entirely (also covers mobile) */
  @media (max-width:1100px) { .doc-toc { display:none; } }

  .block-wrap { position:relative; }
  .block-wrap.nested { padding-left:24px; }
  /* Subtle indent guide only for true sub-lists; suppressed for code/other
     nested content so code-in-list items don't stack a thicket of lines. */
  .block-wrap.nested:has(> .block.b-bullet, > .block.b-numbered, > .block.b-todo)::before {
    content:""; position:absolute; left:8px; top:2px; bottom:2px; width:1px; background:var(--line); }
  .block { position:relative; display:flex; align-items:flex-start; padding:1px 0; border-radius:4px; scroll-margin-top:60px; }
  .block .gutter { position:absolute; left:-52px; top:2px; display:flex; gap:1px; opacity:0; transition:opacity .12s; }
  .block:hover .gutter, .block.drop-before .gutter, .block.drop-after .gutter, .block.dragging .gutter { opacity:1; }
  .gutter button { width:22px; height:24px; display:grid; place-items:center; color:var(--muted); border-radius:5px; }
  .gutter button:hover { background:var(--hover-2); color:var(--fg); }
  .gutter .grip { cursor:grab; } .gutter .grip:active { cursor:grabbing; }
  .block.dragging { opacity:.42; background:var(--hover); }
  .block.drop-before::before, .block.drop-after::after { content:""; position:absolute; left:0; right:0; height:2px; background:var(--accent);
    border-radius:2px; pointer-events:none; box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 18%,transparent); }
  .block.drop-before::before { top:-1px; }
  .block.drop-after::after { bottom:-1px; }
  /* multi-block selection: whole-block tint + suppress stray native text highlight while dragging */
  .block.selected { background:var(--accent-soft); }
  .block.selected .editable::selection, .block.selected .editable *::selection { background:transparent; }
  .doc.selecting, .doc.selecting * { user-select:none; -webkit-user-select:none; cursor:default; }
  .block.list-code-host { height:0; min-height:0; padding:0; overflow:visible; }
  .block-wrap:hover > .block.list-code-host .gutter { opacity:1; }
  .block.list-code-host .marker { position:absolute; left:0; top:0; padding-top:4px; z-index:1; }
  /* The list item's host gutter controls the whole unit, so suppress the nested
     code block's own gutter (it would overlap the list marker on the same row). */
  .block.list-code-host + .block-wrap.nested .gutter { display:none; }
  .editable { outline:none; flex:1; min-width:0; padding:3px 2px; line-height:var(--note-lh); }
  .editable:empty::before { content:attr(data-ph); color:var(--muted); pointer-events:none; }
  /* The generic "/" prompt only shows on the focused line; idle blank lines (paragraphs and list items, any depth) stay blank. */
  .editable[data-ph-hint="slash"]:empty:not(:focus)::before { content:""; }
  .b-h1 .editable { font-size:28px; font-weight:700; letter-spacing:-.02em; padding-top:12px; }
  .b-h2 .editable { font-size:22px; font-weight:650; letter-spacing:-.01em; padding-top:8px; }
  .b-h3 .editable { font-size:18px; font-weight:600; padding-top:4px; }
  .b-h1 .gutter { top:22px; } .b-h2 .gutter { top:14px; } .b-h3 .gutter { top:7px; }
  .b-quote .editable { border-left:3px solid var(--line-strong); padding:1px 0 1px 16px; color:var(--fg-soft); font-style:italic; }

  /* code block: transparent textarea over a highlight.js mirror */
  .b-code .codeblock { flex:1; min-width:0; }
  .codeblock { position:relative; --code-fs:12.5px; --code-lh:1.55; --code-pad:8px; margin:2px 0;
    background:var(--code-bg); border:1px solid var(--line); border-radius:8px; overflow:hidden; box-shadow:var(--shadow-sm); }
  /* lang + copy float bottom-right, revealed on hover */
  .code-tools { position:absolute; right:6px; bottom:6px; z-index:2; display:flex; align-items:center; gap:1px;
    padding:2px; border-radius:7px; border:1px solid var(--line); box-shadow:var(--shadow-sm);
    background:color-mix(in srgb,var(--code-bg) 82%,transparent); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
    opacity:0; transform:translateY(3px); pointer-events:none; transition:opacity .12s,transform .12s; }
  .codeblock:hover .code-tools, .code-tools:focus-within { opacity:1; transform:none; pointer-events:auto; }
  .code-lang { position:relative; display:inline-flex; align-items:center; }
  .code-lang select { appearance:none; -webkit-appearance:none; border:0; outline:none; background:none; cursor:pointer;
    font-family:var(--mono); font-size:10.5px; font-weight:500; color:var(--fg-soft); padding:3px 17px 3px 7px; border-radius:5px; }
  .code-lang select:hover { background:var(--hover-2); }
  .code-lang svg { position:absolute; right:3px; width:12px; height:12px; pointer-events:none; color:var(--muted); }
  .code-copy { display:inline-flex; align-items:center; gap:4px; font-size:10.5px; font-weight:500; color:var(--muted);
    padding:3px 7px; border-radius:5px; transition:background .12s,color .12s; }
  .code-copy:hover { background:var(--hover-2); color:var(--fg-soft); }
  .code-copy.ok { color:var(--accent); }
  .code-body { display:flex; align-items:stretch; font-family:var(--mono); font-size:var(--code-fs); line-height:var(--code-lh); }
  .code-gutter { flex:none; text-align:right; white-space:pre; user-select:none; color:var(--muted); opacity:.55;
    padding:var(--code-pad) 8px var(--code-pad) 12px; border-right:1px solid var(--line); font-variant-numeric:tabular-nums; }
  .code-scroll { position:relative; flex:1; min-width:0; }
  .code-hl, .code-input { margin:0; font-family:var(--mono); font-size:var(--code-fs); line-height:var(--code-lh);
    padding:var(--code-pad) 16px; tab-size:2; -moz-tab-size:2; white-space:pre; letter-spacing:0; }
  .code-hl { position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; background:none; color:var(--fg); }
  .code-hl code { display:block; font:inherit; background:none; padding:0; }
  .code-input { display:block; position:relative; z-index:1; width:100%; border:0; outline:none; resize:none;
    overflow-x:auto; overflow-y:hidden; background:transparent; color:transparent; caret-color:var(--fg);
    min-height:calc(var(--code-fs) * var(--code-lh) + var(--code-pad) * 2); }
  .code-input::placeholder { color:var(--muted); }

  /* highlight.js token theme (cohesive with the app palette) */
  .hljs-comment, .hljs-quote { color:var(--hl-cmt); font-style:italic; }
  .hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-section, .hljs-doctag { color:var(--hl-key); }
  .hljs-string, .hljs-regexp, .hljs-addition, .hljs-meta .hljs-string { color:var(--hl-str); }
  .hljs-number, .hljs-bullet { color:var(--hl-num); }
  .hljs-title, .hljs-title.function_, .hljs-name, .hljs-selector-id, .hljs-selector-class { color:var(--hl-fn); }
  .hljs-type, .hljs-class .hljs-title, .hljs-built_in, .hljs-attr, .hljs-attribute, .hljs-property { color:var(--hl-type); }
  .hljs-variable, .hljs-template-variable, .hljs-symbol, .hljs-tag, .hljs-meta, .hljs-link { color:var(--hl-var); }
  .hljs-deletion { color:var(--danger); }
  .hljs-params, .hljs-subst { color:var(--fg); }
  .hljs-emphasis { font-style:italic; }
  .hljs-strong { font-weight:700; }
  .marker { width:24px; flex:none; text-align:center; color:var(--fg-soft); user-select:none; padding-top:4px; }
  .b-todo .marker { box-sizing:content-box; padding-top:3px; height:calc(1em * var(--note-lh));
    display:flex; align-items:center; justify-content:center; }
  .b-todo .marker input { width:15px; height:15px; accent-color:var(--accent); cursor:pointer; }
  .b-divider { padding:10px 0; }
  .b-divider hr { border:0; border-top:1px solid var(--line-strong); margin:0; width:100%; }
  .b-done .editable { color:var(--muted); text-decoration:line-through; }
  .editable b, .editable strong { font-weight:700; }
  .editable code { font-family:var(--mono); background:var(--surface-2); padding:1px 5px; border-radius:4px; font-size:.9em; }
  .editable a { color:var(--accent); }

  /* document table (GFM pipe table block) */
  .b-table .doc-table-wrap { flex:1; min-width:0; margin:4px 0; }
  .doc-table-scroll { overflow-x:auto; padding:2px 0; }
  .doc-table-inner { width:max-content; }
  .doc-table-row { display:flex; align-items:stretch; }
  table.doc-table { border-collapse:separate; border-spacing:0; table-layout:fixed; width:max-content;
    border:1px solid var(--line); border-radius:var(--radius-sm); overflow:hidden; box-shadow:var(--shadow-sm); }
  table.doc-table td { position:relative; vertical-align:top; padding:0;
    border-right:1px solid var(--line); border-bottom:1px solid var(--line); }
  table.doc-table tr td:last-child { border-right:0; }
  table.doc-table tr:last-child td { border-bottom:0; }
  table.doc-table .doc-th { background:var(--surface); }
  .doc-td { outline:none; padding:7px 22px 7px 10px; min-height:20px; line-height:1.55; word-break:break-word; white-space:pre-wrap; }
  .doc-th .doc-td { font-weight:650; color:var(--fg); }
  .doc-td:empty::before { content:attr(data-ph); color:var(--muted); pointer-events:none; }
  .doc-td b, .doc-td strong { font-weight:700; }
  .doc-td code { font-family:var(--mono); background:var(--surface-2); padding:1px 5px; border-radius:4px; font-size:.9em; }
  .doc-td a { color:var(--accent); }
  /* header cell: column menu + resize handle */
  .doc-col-menu { position:absolute; top:4px; right:4px; width:18px; height:18px; display:grid; place-items:center;
    color:var(--muted); border-radius:4px; opacity:0; transition:opacity .12s,background .12s; }
  .doc-th:hover .doc-col-menu { opacity:1; }
  .doc-col-menu:hover { background:var(--hover-2); color:var(--fg); }
  .doc-col-resizer { position:absolute; top:0; right:-4px; width:7px; height:100%; cursor:col-resize; z-index:3; touch-action:none; }
  /* per-row delete: small handle floating at the first cell on row hover */
  .doc-row-del { position:absolute; top:3px; left:2px; width:18px; height:18px; display:grid; place-items:center;
    color:var(--muted); background:var(--bg); border:1px solid var(--line); border-radius:5px; box-shadow:var(--shadow-sm);
    opacity:0; transition:opacity .12s; }
  table.doc-table tr:hover .doc-row-del { opacity:1; }
  .doc-row-del:hover { background:var(--danger-soft); color:var(--danger); border-color:var(--danger-soft); }
  /* add-column (right edge) and add-row (bottom edge) buttons */
  .doc-table-addcol { width:22px; margin-left:4px; flex:none; display:grid; place-items:center; color:var(--muted);
    border:1px dashed var(--line-strong); border-radius:var(--radius-sm); background:var(--surface); transition:background .12s,color .12s,border-color .12s; }
  .doc-table-addrow { width:100%; height:22px; margin-top:4px; display:grid; place-items:center; color:var(--muted);
    border:1px dashed var(--line-strong); border-radius:var(--radius-sm); background:var(--surface); transition:background .12s,color .12s,border-color .12s; }
  .doc-table-addcol:hover, .doc-table-addrow:hover { background:var(--accent-soft); color:var(--accent); border-color:var(--accent); }

  /* database / table */
  .db { padding:22px 36px 90px; min-width:0; }
  .db-head { display:flex; align-items:center; gap:12px; }
  .db-icon { width:38px; height:38px; border-radius:9px; background:var(--surface-2); display:grid; place-items:center; font-size:20px; }
  .db-title { font-size:27px; font-weight:700; letter-spacing:-.02em; outline:none; }
  .db-desc { color:var(--muted); font-size:13px; margin-top:2px; }
  .views { display:flex; align-items:center; gap:2px; border-bottom:1px solid var(--line); margin:16px 0 0; }
  .view-tab { display:flex; align-items:center; gap:6px; padding:8px 11px; font-size:var(--fs-ui); font-weight:500; color:var(--muted);
    border-bottom:2px solid transparent; margin-bottom:-1px; transition:color .12s; }
  .view-tab.active { color:var(--fg); border-bottom-color:var(--accent); }
  .view-tab:hover { color:var(--fg); } .view-tab svg { width:14px; height:14px; }
  .toolbar { display:flex; align-items:center; gap:2px; padding:10px 0; }
  .toolbar .spacer { flex:1; }
  .tbtn { display:flex; align-items:center; gap:6px; padding:5px 9px; border-radius:var(--radius-sm); color:var(--fg-soft); font-size:13px; font-weight:500; }
  .tbtn:hover { background:var(--hover-2); color:var(--fg); }
  .tbtn.on { color:var(--accent); }
  .tablewrap { border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; box-shadow:var(--shadow-sm); }
  .tablescroll { overflow-x:auto; }
  /* fixed layout + max-content: each <col> width is authoritative, so the table
     is exactly the sum of its columns and resizing one column never redistributes
     width to its neighbours. min-width:100% fills the container when columns are
     narrow, with the slack absorbed only by the trailing auto (filler) column. */
  table.grid { border-collapse:collapse; table-layout:fixed; width:max-content; min-width:100%; }
  table.grid th, table.grid td { border-right:1px solid var(--line); border-bottom:1px solid var(--line); padding:0; text-align:left; }
  table.grid th:last-child, table.grid td:last-child { border-right:0; }
  table.grid tbody tr:last-child td { border-bottom:0; }
  thead th { background:var(--surface); position:relative; user-select:none; font-weight:600; color:var(--fg-soft); }
  .colhead { display:flex; align-items:center; gap:7px; padding:9px 11px; font-size:13px; cursor:pointer; }
  .colhead:hover { background:var(--hover); }
  .colhead .ti { color:var(--muted); } .colhead .ti svg { width:14px; height:14px; }
  .colhead .nm { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .col-resizer { position:absolute; top:0; right:-4px; width:7px; height:100%; cursor:col-resize; z-index:2; touch-action:none; }
  .addcol { min-width:46px; } .addcol .colhead { justify-content:flex-start; color:var(--muted); }
  /* trailing filler column: empty canvas to the right of the data, not a real cell */
  table.grid td.filler { border-right:0; border-bottom:0; background:transparent; }
  body.col-resizing { user-select:none; cursor:col-resize; }
  table.grid .selcell { width:38px; min-width:38px; max-width:38px; text-align:center; }
  table.grid .gripcol, table.grid .rowgrip { width:26px; min-width:26px; max-width:26px; text-align:center; }
  /* relative: anchors the .celledit overlay editor to the cell */
  td.cell-td { position:relative; vertical-align:top; }
  .cell { padding:8px 11px; min-height:37px; cursor:text; word-break:break-word; display:flex; flex-wrap:wrap; gap:3px; align-items:center; }
  /* hover/active tint goes on the <td> (always full row height) not the inner
     .cell (only as tall as its content), so a taller sibling row never leaves a
     gap of un-tinted space at the bottom of the hovered cell. */
  td.cell-td { transition:background .1s; }
  td.cell-td:hover { background:var(--hover); } .cell.center { justify-content:center; }
  tbody tr { transition:background .08s; }
  tbody tr:hover { background:var(--hover); }
  tbody tr.sel { background:var(--accent-soft); }
  /* cell range selection: per-cell fill; the accent rectangle outline is drawn via inline box-shadow on edge cells. Placed after :hover so it wins on equal specificity. */
  td.cell-td.cellsel, td.cell-td.cellsel:hover { background:var(--accent-soft); }
  body.cell-selecting { user-select:none; cursor:cell; }
  body.cell-selecting .cell { cursor:cell; }
  table.grid tr.drop-before td { box-shadow:inset 0 2px 0 0 var(--accent); }
  table.grid tr.drop-after td { box-shadow:inset 0 -2px 0 0 var(--accent); }
  table.grid th.drop-before { box-shadow:inset 2px 0 0 0 var(--accent); }
  table.grid th.drop-after { box-shadow:inset -2px 0 0 0 var(--accent); }
  .rowgrip { color:transparent; cursor:grab; vertical-align:middle; touch-action:none; }
  .rowgrip[aria-disabled="true"] { cursor:not-allowed; }
  tbody tr:hover .rowgrip { color:var(--muted); }
  .colhead { touch-action:none; }
  .drag-source { opacity:.35; }
  body.table-dragging { user-select:none; cursor:grabbing; }
  .drag-ghost { position:fixed; left:0; top:0; z-index:120; pointer-events:none; display:flex; align-items:center;
    padding:7px 11px; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; border:1px solid var(--line-strong);
    border-radius:7px; background:var(--bg); color:var(--fg); box-shadow:var(--shadow-lg); opacity:.94; font-size:13px; }
  .row-ghost { min-height:34px; }
  .col-ghost { justify-content:center; font-weight:600; color:var(--fg-soft); background:var(--surface); }
  .selcell { vertical-align:middle; }
  .selcell input { width:15px; height:15px; accent-color:var(--accent); opacity:0; cursor:pointer; vertical-align:middle; }
  tbody tr:hover .selcell input, tbody tr.sel .selcell input, .selcell input:checked, thead .selcell input { opacity:1; }
  .firstcell { position:relative; width:100%; min-width:0; }
  /* row actions float over the cell on hover, never reserving column width */
  /* right:-5px pulls the button out over the cell's 11px right padding so it
     sits ~6px from the column border instead of ~15px inside it */
  .rowactions { position:absolute; top:0; bottom:0; right:-5px; display:flex; align-items:flex-start;
    padding:1px 0 0; opacity:0; pointer-events:none; }
  tbody tr:hover .rowactions { opacity:1; pointer-events:auto; }
  /* square icon button — "open as page" (Notion-style) */
  .rowopen { width:23px; height:23px; flex:none; display:inline-flex; align-items:center; justify-content:center;
    border:1px solid var(--line); border-radius:6px; background:var(--bg); color:var(--fg-soft); box-shadow:var(--shadow-sm); }
  .rowopen:hover { background:var(--surface-2); color:var(--fg); border-color:var(--line-strong); }
  .rowopen svg { width:14px; height:14px; }
  .chip { display:inline-flex; align-items:center; gap:4px; border-radius:5px; padding:2px 8px; font-size:var(--fs-sm); font-weight:500; white-space:nowrap;
    background:color-mix(in srgb,var(--c) 15%,transparent); color:var(--c); }
  /* data-resolved (not prefers-color-scheme): tracks a manual dark choice too. */
  :root[data-resolved="dark"] .chip { background:color-mix(in srgb,var(--c) 22%,transparent); color:color-mix(in srgb,var(--c) 75%,#fff); }
  .addrow { display:flex; align-items:center; gap:7px; padding:9px 12px; color:var(--muted); font-size:13px; cursor:pointer; border-top:1px solid var(--line); }
  .addrow:hover { background:var(--hover); color:var(--fg-soft); }
  .gridfoot { display:flex; gap:18px; color:var(--muted); font-size:12px; padding:8px 2px; }
  input.inlineedit { width:100%; border:0; outline:2px solid var(--accent); border-radius:4px; padding:7px 9px; background:var(--bg); color:var(--fg); font:inherit; }
  /* Overlay cell editor: floats over the td; the display content underneath
     stays in flow so the row height never changes while editing. Padding on the
     input matches .cell (8px 11px) so the text doesn't shift on entering edit. */
  .celledit { position:absolute; top:0; left:0; width:100%; min-height:100%; z-index:10;
    display:flex; align-items:stretch; background:var(--bg); border-radius:var(--radius-sm);
    box-shadow:0 0 0 2px var(--accent), var(--shadow-md); }
  .celledit input.inlineedit { width:100%; min-width:0; border:0; outline:0; border-radius:inherit;
    padding:8px 11px; background:transparent; }

  /* ---- sites (站点管理) ---- */
  .sites-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(264px, 1fr)); gap:14px; margin-top:6px; }
  .site-card { display:flex; flex-direction:column; gap:13px; padding:16px 16px 14px; background:var(--bg); border:1px solid var(--line);
    border-radius:var(--radius); box-shadow:var(--shadow-sm); cursor:pointer; transition:box-shadow .16s, border-color .16s, transform .16s; }
  .site-card:hover { box-shadow:var(--shadow-md); border-color:var(--line-strong); transform:translateY(-1px); }
  .site-card-head { display:flex; align-items:center; gap:11px; min-width:0; }
  .site-card .si { width:40px; height:40px; border-radius:11px; background:var(--accent-soft); color:var(--accent); display:grid; place-items:center; flex:none; }
  .site-card .si svg { width:20px; height:20px; }
  .site-card-id { min-width:0; }
  .site-card .slug { font-family:var(--mono); font-weight:600; font-size:14.5px; color:var(--fg); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .site-card .ttl { font-size:12px; color:var(--fg-soft); margin-top:1px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .site-card .ttl.muted { color:var(--muted); font-style:italic; }
  .site-addr { display:flex; align-items:center; gap:6px; width:100%; text-align:left; background:var(--surface); border:1px solid var(--line);
    border-radius:var(--radius-sm); padding:6px 9px; color:var(--muted); font-family:var(--mono); font-size:var(--fs-xs); transition:border-color .12s, color .12s; }
  .site-addr svg { flex:none; }
  .site-addr span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .site-addr:hover { border-color:var(--accent); color:var(--accent); }
  .site-card-meta { display:flex; align-items:center; gap:7px; font-size:12px; color:var(--muted); }
  .site-card-meta b { color:var(--fg-soft); font-weight:600; font-variant-numeric:tabular-nums; }
  .site-card-meta .dot { color:var(--line-strong); }
  .site-card-foot { display:flex; align-items:center; gap:6px; padding-top:12px; margin-top:1px; border-top:1px solid var(--line); }
  .site-card-foot .btn-secondary { padding:6px 12px; justify-content:center; }

  .site-empty { text-align:center; color:var(--muted); border:1px dashed var(--line-strong); border-radius:var(--radius); padding:48px 24px; margin-top:8px; }
  .site-empty .ei { font-size:30px; margin-bottom:10px; }
  .site-empty .et { font-size:var(--fs-body); color:var(--fg-soft); margin-bottom:4px; font-weight:600; }
  .site-empty .ed { font-size:var(--fs-sm); margin-bottom:16px; }

  /* site peek: access bar + file manager */
  .acc-link { display:flex; align-items:center; gap:6px; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-sm); padding:7px 8px 7px 11px; margin-bottom:16px; }
  .acc-link .url { flex:1; font-family:var(--mono); font-size:var(--fs-sm); color:var(--fg-soft); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .acc-link button { width:28px; height:28px; display:grid; place-items:center; border-radius:6px; color:var(--muted); flex:none; }
  .acc-link button:hover { background:var(--hover-2); color:var(--fg); }
  .acc-link button.accent { color:var(--accent); }
  .site-meta { display:flex; gap:18px; color:var(--muted); font-size:12px; margin-bottom:20px; }
  .site-meta b { color:var(--fg); font-weight:600; }
  .files-head { display:flex; align-items:center; justify-content:space-between; font-size:var(--fs-micro); font-weight:600; text-transform:uppercase; letter-spacing:.05em; color:var(--muted); margin:0 0 4px; }
  .filerow { display:flex; align-items:center; gap:10px; padding:9px 8px; border-radius:var(--radius-sm); cursor:pointer; border-bottom:1px solid var(--line); }
  .filerow:last-child { border-bottom:0; }
  .filerow:hover { background:var(--hover); }
  .filerow .fi { color:var(--muted); display:grid; place-items:center; flex:none; }
  .filerow .fpath { flex:1; font-family:var(--mono); font-size:var(--fs-sm); color:var(--fg); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .filerow .facts { display:flex; gap:1px; opacity:0; flex:none; }
  .filerow:hover .facts { opacity:1; }
  .filerow .facts button { width:27px; height:27px; display:grid; place-items:center; border-radius:6px; color:var(--muted); }
  .filerow .facts button:hover { background:var(--hover-2); color:var(--fg); }
  .filerow .facts button.del:hover { color:var(--danger); }
  .enc-badge { display:inline-flex; align-items:center; font-family:var(--mono); font-size:10.5px; font-weight:500; letter-spacing:.02em;
    padding:2px 6px; border-radius:5px; background:var(--surface-2); color:var(--fg-soft); border:1px solid var(--line); }
  .enc-badge.blob { color:var(--accent); background:var(--accent-soft); border-color:transparent; }

  /* file preview (inside modal) */
  .preview-box { font-family:var(--mono); font-size:var(--fs-sm); background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius);
    padding:14px 16px; max-height:52vh; overflow:auto; white-space:pre-wrap; line-height:1.6; color:var(--fg); }
  .preview-bin { text-align:center; color:var(--muted); border:1px dashed var(--line-strong); border-radius:var(--radius); padding:40px 20px; }
  .preview-bin .pi { font-size:28px; margin-bottom:8px; }
  .preview-bin .pt { color:var(--fg-soft); font-size:13px; }

  /* in-app site preview (browser-framed iframe) */
  .spv-scrim { position:fixed; inset:0; background:rgba(15,15,25,.5); z-index:85; display:grid; place-items:center; padding:28px;
    opacity:0; pointer-events:none; transition:opacity .16s; animation:spv-in .16s forwards; }
  @keyframes spv-in { to { opacity:1; pointer-events:auto; } }
  .spv-scrim.open { opacity:1; pointer-events:auto; }
  .spv { width:min(1100px, 92vw); height:88vh; background:var(--bg); border-radius:var(--radius-lg); box-shadow:var(--shadow-lg);
    display:flex; flex-direction:column; overflow:hidden; }
  .spv-chrome { display:flex; align-items:center; gap:10px; padding:9px 12px; border-bottom:1px solid var(--line); background:var(--surface); }
  .spv-dots { display:flex; gap:6px; flex:none; }
  .spv-dots i { width:11px; height:11px; border-radius:50%; background:var(--line-strong); }
  .spv-url { flex:1; display:flex; align-items:center; gap:6px; min-width:0; background:var(--bg); border:1px solid var(--line);
    border-radius:7px; padding:5px 10px; color:var(--fg-soft); font-family:var(--mono); font-size:12px; }
  .spv-url svg { color:var(--muted); flex:none; }
  .spv-url span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .spv-btn { display:inline-flex; align-items:center; gap:5px; flex:none; padding:6px 10px; border-radius:7px; color:var(--fg-soft); font-size:var(--fs-sm); font-weight:500; }
  .spv-btn:hover { background:var(--hover-2); color:var(--fg); }
  .spv-btn.icon { padding:6px; }
  /* #fff on purpose: published site content assumes a white canvas, independent
     of the app theme. */
  .spv-frame { flex:1; width:100%; border:0; background:#fff; }

  .selbar { position:fixed; bottom:24px; left:50%; transform:translateX(-50%); z-index:65; display:flex; align-items:center; gap:4px;
    background:var(--fg); color:var(--bg); padding:7px 8px 7px 14px; border-radius:11px; box-shadow:var(--shadow-lg); }
  .selbar .cnt { font-size:13px; font-weight:600; margin-right:6px; }
  .selbar button { display:flex; align-items:center; gap:6px; color:var(--bg); padding:6px 10px; border-radius:7px; font-size:13px; font-weight:500; }
  .selbar button:hover { background:color-mix(in srgb,var(--bg) 25%,transparent); }
  .selbar .del:hover { background:var(--danger); color:#fff; }

  /* record peek */
  .scrim { position:fixed; inset:0; background:rgba(15,15,25,.32); z-index:70; opacity:0; pointer-events:none; transition:opacity .22s; }
  .scrim.open { opacity:1; pointer-events:auto; }
  .peek { position:fixed; top:0; right:0; width:580px; max-width:94vw; height:100%; background:var(--bg); border-left:1px solid var(--line);
    box-shadow:var(--shadow-lg); z-index:71; transform:translateX(100%); transition:transform .24s cubic-bezier(.32,.72,0,1); display:flex; flex-direction:column; }
  .peek.open { transform:none; }
  .peek-head { display:flex; align-items:center; gap:4px; padding:12px 16px; border-bottom:1px solid var(--line); }
  .peek-body { overflow:auto; padding:28px 32px; }
  .peek h2 { font-size:27px; font-weight:700; letter-spacing:-.02em; margin:0 0 20px; outline:none; }
  .proprow { display:flex; gap:8px; align-items:flex-start; margin:1px 0; }
  .proprow .k { width:160px; flex:none; color:var(--muted); display:flex; align-items:center; gap:7px; font-size:13px; padding:7px 8px; border-radius:var(--radius-sm); }
  .proprow .k:hover { background:var(--hover); }
  .proprow .v { flex:1; padding:7px 8px; border-radius:var(--radius-sm); cursor:text; min-height:33px; display:flex; flex-wrap:wrap; gap:3px; align-items:center; }
  .proprow .v:hover { background:var(--hover); }
  .peek-divider { height:1px; background:var(--line); margin:22px 0 18px; }

  /* version history (doc drawer + record peek view) */
  .hist-peek { width:760px; }
  .hist-title { display:flex; align-items:center; gap:6px; font-weight:600; font-size:var(--fs-ui); }
  .hist-toggle { display:flex; align-items:center; gap:5px; font-size:var(--fs-sm); color:var(--muted); cursor:pointer; user-select:none; white-space:nowrap; }
  .hist-toggle input { accent-color:var(--accent); }
  .hist-split { display:flex; flex:1; min-height:0; }
  .hist-list { width:252px; flex:none; overflow:auto; border-right:1px solid var(--line); padding:8px; }
  .hist-item { padding:8px 10px; border-radius:var(--radius-sm); cursor:pointer; }
  .hist-item:hover { background:var(--hover); }
  .hist-item.sel { background:var(--accent-soft); }
  .hist-item.static { cursor:default; border-bottom:1px solid var(--line); border-radius:0; padding:10px 4px; }
  .hist-item.static:hover { background:none; }
  .hist-item .row1 { display:flex; align-items:center; gap:7px; }
  .hist-item .row1 .when { font-weight:600; font-size:var(--fs-ui); }
  .hist-item .row2 { display:flex; gap:8px; margin-top:2px; font-size:var(--fs-sm); color:var(--muted); min-width:0; }
  .hist-item .row2 .what { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .hist-kind { font-size:var(--fs-xs); padding:1px 6px; border-radius:99px; background:var(--surface-2); color:var(--muted); }
  .hist-kind.revert { background:var(--accent-soft); color:var(--accent); }
  .hist-kind.repair { background:var(--danger-soft); color:var(--danger); }
  .hist-now { font-size:var(--fs-xs); padding:1px 6px; border-radius:99px; background:var(--accent); color:var(--accent-fg); }
  .hist-preview { flex:1; overflow:auto; padding:20px 24px; }
  .hist-doc-title { font-size:21px; font-weight:700; letter-spacing:-.02em; margin-bottom:14px; }
  .hist-block { white-space:pre-wrap; font-size:var(--fs-body); line-height:1.65; padding:2px 6px; border-radius:4px; margin:0 -6px 12px; }
  /* line-level diff rows (git-like): pale full-line tint, darker tint on the
     intra-line changed segment; strikethrough only on the deleted segment. */
  .hist-line { white-space:pre-wrap; font-size:var(--fs-body); line-height:1.6; padding:1px 6px; margin:0 -6px; border-radius:3px; }
  .hist-line.add { background:color-mix(in srgb, var(--success) 13%, transparent); }
  .hist-line.del { background:var(--danger-soft); }
  .hist-line.add .seg { background:color-mix(in srgb, var(--success) 32%, transparent); border-radius:2px; }
  .hist-line.del .seg { background:color-mix(in srgb, var(--danger) 28%, transparent); border-radius:2px; text-decoration:line-through; }
  .hist-foot { display:flex; justify-content:flex-end; padding:12px 16px; border-top:1px solid var(--line); }
  .pad { padding:12px; }
  .hist-rec-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; }
  .hist-feed { padding:12px 24px; }
  .hist-recname { font-weight:600; font-size:var(--fs-sm); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .hist-status { font-size:var(--fs-xs); color:var(--muted); flex:none; }
  .hist-field .old, .hist-field .new { max-width:200px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .hist-more { border:0; background:none; color:var(--muted); font-size:var(--fs-sm); cursor:pointer; padding:2px 0; text-align:left; }
  .hist-more:hover { color:var(--fg); }
  .hist-fields { padding:8px 4px 4px; display:flex; flex-direction:column; gap:6px; }
  .hist-field { display:flex; gap:8px; font-size:var(--fs-sm); align-items:baseline; flex-wrap:wrap; }
  .hist-field .fname { color:var(--muted); width:120px; flex:none; }
  .hist-field .old { text-decoration:line-through; color:var(--muted); }
  .hist-field .arr { color:var(--muted); }
  .hist-field .new { font-weight:500; }
  .hist-restore { margin-top:8px; align-self:flex-start; }

  /* menu / popover */
  .menu-layer { position:fixed; inset:0; z-index:90; }
  .pop { position:fixed; background:var(--bg); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow-lg);
    padding:6px; min-width:232px; max-height:70vh; overflow:auto; animation:pop .12s ease; }
  @keyframes pop { from { opacity:0; transform:translateY(-4px); } }
  /* Action-sheet variant: MenuHost (ui.tsx) adds .sheet on phones, where an
     anchored popover clips at the edges and sits under the finger. */
  .pop.sheet { left:8px; right:8px; top:auto; bottom:calc(8px + env(safe-area-inset-bottom));
    min-width:0; max-height:60vh; max-height:60dvh; border-radius:var(--radius-lg);
    animation:sheet-in .18s ease; }
  @keyframes sheet-in { from { opacity:0; transform:translateY(12px); } }
  .pop .lbl { font-size:var(--fs-micro); font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.05em; padding:6px 8px 3px; }
  .pop .item { display:flex; align-items:center; gap:10px; padding:7px 8px; border-radius:var(--radius-sm); width:100%; text-align:left; color:var(--fg); font-size:var(--fs-ui); }
  .pop .item:hover, .pop .item.sel { background:var(--hover-2); }
  .pop .item .lico { width:28px; height:28px; display:grid; place-items:center; border:1px solid var(--line); border-radius:6px; color:var(--fg-soft); flex:none; }
  .pop .item .lico.plain { border:0; width:22px; height:22px; }
  .pop .item .meta { flex:1; min-width:0; }
  .pop .item .t { font-size:var(--fs-ui); } .pop .item .d { font-size:var(--fs-xs); color:var(--muted); display:block; }
  .pop .item .chk { color:var(--accent); margin-left:auto; }
  .pop .item.danger { color:var(--danger); } .pop .item.danger .lico { color:var(--danger); }
  .pop .sep { height:1px; background:var(--line); margin:5px 4px; }
  .pop .typegrid { display:grid; grid-template-columns:repeat(4,1fr); gap:4px; padding:2px 2px 4px; }
  .pop .typegrid .item { flex-direction:column; gap:5px; padding:9px 4px; text-align:center; }
  .pop .typegrid .item .lico { margin:0 auto; }
  .pop input.field { width:100%; border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:7px 9px; outline:none; background:var(--surface); margin:2px; }
  .pop input.field:focus { border-color:var(--accent); }
  .optrow { display:flex; align-items:center; gap:6px; padding:3px 4px; }
  .optrow .chip { flex:1; }
  .optrow .x { width:22px; height:22px; display:grid; place-items:center; color:var(--muted); border-radius:5px; }
  .optrow .x:hover { background:var(--hover-2); color:var(--danger); }

  /* modal */
  .modal-scrim { position:fixed; inset:0; background:rgba(15,15,25,.4); z-index:100; display:flex; align-items:center; justify-content:center;
    opacity:0; pointer-events:none; transition:opacity .15s; padding:20px; }
  .modal-scrim.open { opacity:1; pointer-events:auto; }
  .modal { background:var(--bg); border-radius:var(--radius-xl); box-shadow:var(--shadow-lg); width:440px; max-width:100%; max-height:100%; display:flex; flex-direction:column; overflow:hidden; }
  .modal-head { padding:20px 22px 0; }
  .modal-head h3 { margin:0; font-size:18px; font-weight:700; letter-spacing:-.01em; }
  .modal-head p { margin:6px 0 0; color:var(--muted); font-size:var(--fs-ui); }
  .modal-body { padding:18px 22px; overflow-y:auto; }
  .modal-foot { display:flex; justify-content:flex-end; gap:8px; padding:14px 22px; background:var(--surface); border-top:1px solid var(--line); }
  .field-label { font-size:12px; font-weight:600; color:var(--fg-soft); margin:12px 0 5px; }
  .field-label:first-child { margin-top:0; }
  .text-input { width:100%; border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:9px 11px; outline:none; background:var(--surface); font-size:var(--fs-body); }
  .text-input:focus { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
  /* Checkbox + label row (e.g. the E2EE toggle in "添加同步存储"). */
  .set-check-row { display:flex; align-items:flex-start; gap:8px; font-size:var(--fs-body); color:var(--fg-soft); cursor:pointer; }
  .set-check-row input { margin-top:2px; flex:none; }
  .icon-pick { display:flex; gap:6px; flex-wrap:wrap; }
  .icon-pick button { width:38px; height:38px; border-radius:9px; border:1px solid var(--line); font-size:19px; display:grid; place-items:center; }
  .icon-pick button:hover { background:var(--hover-2); }
  .icon-pick button.sel { border-color:var(--accent); background:var(--accent-soft); }
  .tmpl { display:flex; gap:8px; }
  .tmpl button { flex:1; border:1px solid var(--line); border-radius:var(--radius); padding:12px; text-align:left; }
  .tmpl button:hover { border-color:var(--accent); background:var(--surface); }
  .tmpl button.sel { border-color:var(--accent); background:var(--accent-soft); }
  .tmpl .tt { font-weight:600; font-size:var(--fs-ui); } .tmpl .td { font-size:var(--fs-xs); color:var(--muted); margin-top:2px; }

  /* toast */
  .toasts { position:fixed; bottom:20px; left:20px; z-index:110; display:flex; flex-direction:column; gap:8px; }
  .toast { background:var(--fg); color:var(--bg); padding:10px 14px; border-radius:9px; font-size:13px; box-shadow:var(--shadow-lg);
    display:flex; align-items:center; gap:8px; animation:slidein .2s ease; }
  @keyframes slidein { from { opacity:0; transform:translateX(-12px); } }

  /* misc */
  .empty { display:flex; flex-direction:column; align-items:center; justify-content:center; height:100%;
    color:var(--muted); text-align:center; padding:40px; }

  /* ---- empty state: 知识生长插画 ---- */
  .estate-art { width:240px; height:208px; overflow:visible; animation:idleFloat 5s ease-in-out 1.6s infinite; }
  .estate-art .stroke-a { fill:none; stroke:var(--accent); stroke-width:2.4; stroke-linecap:round; stroke-linejoin:round; }
  .estate-art .stroke   { fill:none; stroke:var(--line-strong); stroke-width:2.4; stroke-linecap:round; stroke-linejoin:round; }
  .estate-art .fill-a       { fill:var(--accent); }
  .estate-art .fill-soft    { fill:var(--accent-soft); }
  .estate-art .fill-surface { fill:var(--bg); }
  .estate-art .ground       { fill:var(--accent); }
  .estate-title { margin:28px 0 0; font-size:18px; font-weight:600; letter-spacing:.2px; color:var(--fg);
    opacity:0; animation:fadeUp .5s ease forwards 1.0s; }
  .estate-hint { margin:9px 0 0; font-size:var(--fs-ui); line-height:1.6; color:var(--muted); max-width:300px;
    opacity:0; animation:fadeUp .5s ease forwards 1.15s; }
  .estate-link { margin:18px 0 0; font-size:var(--fs-body); font-weight:600; color:var(--accent);
    display:inline-flex; align-items:center; gap:6px; padding:9px 8px; border-radius:var(--radius-sm);
    opacity:0; animation:fadeUp .5s ease forwards 1.3s; transition:opacity .15s; }
  .estate-link:hover { opacity:.7; }
  /* intro */
  .draw { stroke-dasharray:100; stroke-dashoffset:100; }
  @keyframes draw     { to { stroke-dashoffset:0; } }
  @keyframes leafGrow { from { opacity:0; transform:scale(.2) rotate(-10deg); } to { opacity:1; transform:scale(1) rotate(0); } }
  @keyframes cardUp   { from { opacity:0; transform:translateY(16px) scale(.96); } to { opacity:1; transform:translateY(0) scale(1); } }
  @keyframes groundIn { to { opacity:.1; } }
  @keyframes glowIn   { to { opacity:.6; } }
  @keyframes fadeUp   { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:translateY(0); } }
  /* idle loops — each 0% equals the settled rest state to avoid a jump */
  @keyframes idleFloat     { 0%,100% { transform:translateY(0); } 50% { transform:translateY(-5px); } }
  @keyframes plantSway     { 0%,100% { transform:rotate(0deg); } 25% { transform:rotate(-1.3deg); } 75% { transform:rotate(1.3deg); } }
  @keyframes leafSwayA     { 0%,100% { transform:rotate(0deg); } 25% { transform:rotate(-2.6deg); } 75% { transform:rotate(2.6deg); } }
  @keyframes leafSwayB     { 0%,100% { transform:rotate(0deg); } 25% { transform:rotate(2.6deg); } 75% { transform:rotate(-2.6deg); } }
  @keyframes groundBreathe { 0%,100% { transform:scale(1); opacity:.10; } 50% { transform:scale(1.07); opacity:.15; } }
  @keyframes glowPulse     { 0%,100% { transform:scale(1); opacity:.6; } 50% { transform:scale(1.1); opacity:.85; } }
  @keyframes particle      { 0% { opacity:0; transform:translate(0,0) scale(.4); } 35% { opacity:.85; transform:translate(2px,-4px) scale(1); } 70% { opacity:0; transform:translate(4px,-9px) scale(.5); } 100% { opacity:0; transform:translate(0,0) scale(.4); } }
  /* wiring */
  .kg-ground { transform-box:fill-box; transform-origin:center; opacity:0;
    animation:groundIn .5s ease forwards .1s, groundBreathe 6s ease-in-out 1.6s infinite; }
  .kg-glow { filter:blur(9px); transform-box:fill-box; transform-origin:center; opacity:0;
    animation:glowIn .6s ease forwards .1s, glowPulse 4.6s ease-in-out 1.6s infinite; }
  .kg-cardB { transform-box:fill-box; transform-origin:center; opacity:0; animation:cardUp .55s cubic-bezier(.2,.8,.2,1) forwards .2s; }
  .kg-cardA { transform-box:fill-box; transform-origin:center; opacity:0; animation:cardUp .55s cubic-bezier(.2,.8,.2,1) forwards .32s; }
  .kg-plant { transform-box:fill-box; transform-origin:50% 100%; animation:plantSway 6s ease-in-out 1.7s infinite; }
  .kg-stem  { animation:draw .9s ease-out forwards .4s; }
  .kg-leaf  { transform-box:fill-box; }
  .kg-grow  { transform-box:fill-box; opacity:0; }
  .kg-leaf.l1 { transform-origin:90% 100%; animation:leafSwayA 4.6s ease-in-out 1.7s infinite; }
  .kg-leaf.l2 { transform-origin:0% 80%;   animation:leafSwayB 5.2s ease-in-out 1.8s infinite; }
  .kg-leaf.l3 { transform-origin:0% 100%;  animation:leafSwayA 5.0s ease-in-out 1.9s infinite; }
  .kg-leaf.l1 .kg-grow { transform-origin:90% 100%; animation:leafGrow .52s cubic-bezier(.18,.9,.24,1.22) forwards .85s; }
  .kg-leaf.l2 .kg-grow { transform-origin:0% 80%;   animation:leafGrow .52s cubic-bezier(.18,.9,.24,1.22) forwards 1.0s; }
  .kg-leaf.l3 .kg-grow { transform-origin:0% 100%;  animation:leafGrow .52s cubic-bezier(.18,.9,.24,1.22) forwards 1.15s; }
  .kg-particle { transform-box:fill-box; transform-origin:center; opacity:0; }
  .kg-particle.p1 { animation:particle 4.5s ease-in-out 1.6s infinite; }
  .kg-particle.p2 { animation:particle 5.2s ease-in-out 2.0s infinite; }
  .kg-particle.p3 { animation:particle 4.8s ease-in-out 2.6s infinite; }
  .kg-particle.p4 { animation:particle 5.6s ease-in-out 3.1s infinite; }
  .kg-particle.p5 { animation:particle 4.2s ease-in-out 2.3s infinite; }
  @media (prefers-reduced-motion: reduce) {
    .estate-art, .estate-art *, .estate-title, .estate-hint, .estate-link { animation:none !important; opacity:1 !important; transform:none !important; }
    .draw { stroke-dashoffset:0 !important; }
    .kg-ground { opacity:.1 !important; }
    .kg-glow { opacity:.6 !important; }
    .kg-particle { opacity:0 !important; }
  }
  .error-bar { margin:12px 24px; padding:10px 14px; background:var(--danger-soft); color:var(--danger); border-radius:var(--radius-sm); font-size:13px; cursor:pointer; }
  .offline-bar { margin:12px 24px 0; padding:8px 14px; background:var(--surface-2); color:var(--fg-soft); border-radius:var(--radius-sm); font-size:12.5px; }
  .search-hit { margin:0 0 8px; padding:10px 14px; background:var(--surface); border-radius:var(--radius-sm); font-size:13px; cursor:pointer; }
  .search-hit:hover { background:var(--surface-2); }
  .search-hit mark { background:transparent; color:var(--accent); font-weight:600; }
  .view-placeholder { padding:40px; text-align:center; border:1px dashed var(--line-strong); border-radius:var(--radius); color:var(--muted); margin-top:8px; }
  .ico.flip { transform:scaleX(-1); }

  /* ---- find in document (Ctrl-F) ---- */
  /* CSS Custom Highlight overlays — no DOM mutation, safe over contentEditable. */
  ::highlight(mh-find-all) { background:color-mix(in srgb, var(--accent) 26%, transparent); border-radius:2px; }
  ::highlight(mh-find-current) { background:var(--accent); color:var(--accent-fg); }
  .find-bar {
    position:fixed; top:58px; right:18px; z-index:40;   /* below the ~50px topbar */
    display:flex; align-items:center; gap:4px;
    padding:5px 6px; background:var(--bg); border:1px solid var(--line-strong);
    border-radius:var(--radius); box-shadow:var(--shadow-lg);
  }
  .find-bar .find-ico { color:var(--muted); margin:0 2px; flex:none; }
  .find-bar input {
    width:200px; max-width:42vw; border:0; outline:0; background:transparent;
    color:var(--fg); font-size:13px; padding:3px 2px;
  }
  .find-bar input::placeholder { color:var(--muted); }
  .find-count { font-size:12px; color:var(--muted); min-width:48px; text-align:right; padding:0 2px; font-variant-numeric:tabular-nums; }
  .find-opt {
    border:1px solid var(--line-strong); background:transparent; color:var(--fg-soft);
    border-radius:var(--radius-sm); font-size:12px; line-height:1; padding:4px 6px; cursor:pointer;
    transition:background .12s, color .12s, border-color .12s;
  }
  .find-opt:hover { background:var(--surface-2); }
  .find-opt.on { background:var(--accent-soft); color:var(--accent); border-color:color-mix(in srgb, var(--accent) 45%, transparent); }
  .find-nav {
    display:grid; place-items:center; width:26px; height:26px; flex:none;
    border:0; background:transparent; color:var(--fg-soft); border-radius:var(--radius-sm); cursor:pointer;
    transition:background .12s, color .12s;
  }
  .find-nav:hover:not(:disabled) { background:var(--surface-2); color:var(--fg); }
  .find-nav:disabled { opacity:.4; cursor:default; }
  .find-nav .find-prev { transform:rotate(180deg); }
  .find-close { color:var(--muted); }
  @media (max-width:560px) {
    .find-bar { left:12px; right:12px; }
    .find-bar input { width:auto; flex:1; max-width:none; }
  }

  /* ---- board (kanban) view ---- */
  .board-wrap { margin-top:4px; }
  .board-bar { display:flex; align-items:center; gap:10px; padding:2px 0 12px; }
  .board { display:flex; align-items:flex-start; gap:12px; overflow-x:auto; padding-bottom:14px; min-height:240px; }
  .board-col { flex:0 0 272px; width:272px; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); display:flex; flex-direction:column; max-height:calc(100vh - 240px); max-height:calc(100dvh - 240px); transition:box-shadow .12s,border-color .12s; }
  .board-col.drop-into { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-soft); }
  .board-col-head { display:flex; align-items:center; gap:8px; padding:10px 10px 8px; }
  .board-col-head .spacer { flex:1; }
  .board-count { color:var(--muted); font-size:12px; font-weight:600; }
  .board-col-head .iconbtn.sm { width:24px; height:24px; }
  .board-col-body { display:flex; flex-direction:column; gap:7px; padding:0 8px 8px; overflow-y:auto; }
  .kcard { background:var(--bg); border:1px solid var(--line); border-radius:var(--radius-sm); padding:9px 10px; box-shadow:var(--shadow-sm);
    cursor:grab; display:flex; flex-direction:column; gap:5px; touch-action:none; transition:border-color .1s,box-shadow .1s; }
  .kcard:hover { border-color:var(--line-strong); }
  .kcard.drag-source { opacity:.4; }
  .kcard.dragging-ghost { position:fixed; left:0; top:0; z-index:120; pointer-events:none; cursor:grabbing;
    box-shadow:var(--shadow-lg); opacity:.95; transform:translate3d(-9999px,0,0); }
  .kcard-title { font-size:var(--fs-ui); font-weight:600; line-height:1.35; word-break:break-word; }
  .kcard-field { display:flex; align-items:center; gap:6px; font-size:var(--fs-sm); color:var(--fg-soft); min-width:0; }
  .kcard-field svg { width:13px; height:13px; color:var(--muted); flex:none; }
  .board-add { display:flex; align-items:center; gap:6px; padding:7px 8px; color:var(--muted); font-size:var(--fs-sm); border-radius:var(--radius-sm); }
  .board-add:hover { background:var(--hover-2); color:var(--fg-soft); }

  /* ---- calendar (month) view ---- */
  .cal { margin-top:4px; display:flex; flex-direction:column; }
  .cal-nav { display:flex; align-items:center; gap:8px; padding:2px 0 12px; }
  .cal-nav .spacer { flex:1; }
  .cal-title { font-size:15px; font-weight:650; min-width:120px; }
  .cal-grid { display:grid; grid-template-columns:repeat(7,1fr); }
  .cal-head { border:1px solid var(--line); border-bottom:0; border-radius:var(--radius) var(--radius) 0 0; background:var(--surface); }
  .cal-wd { padding:8px 10px; font-size:12px; font-weight:600; color:var(--muted); text-align:left; border-right:1px solid var(--line); }
  .cal-wd:last-child { border-right:0; }
  .cal-body { border:1px solid var(--line); border-radius:0 0 var(--radius) var(--radius); overflow:hidden; }
  .cal-week { border-bottom:1px solid var(--line); }
  .cal-week:last-child { border-bottom:0; }
  .cal-day { min-height:108px; border-right:1px solid var(--line); padding:5px 6px; display:flex; flex-direction:column; gap:4px; transition:background .1s; cursor:pointer; }
  .cal-day:last-child { border-right:0; }
  .cal-day:hover { background:var(--hover); }
  .cal-day.dim { background:var(--surface); color:var(--muted); }
  .cal-day.dim:hover { background:var(--hover); }
  .cal-day.drop-into { background:var(--accent-soft); }
  .cal-daynum { display:flex; align-items:center; justify-content:space-between; font-size:var(--fs-sm); font-weight:600; color:var(--fg-soft); }
  .cal-day.dim .cal-daynum { color:var(--muted); }
  .cal-day.today .cal-daynum span:first-child { background:var(--accent); color:var(--accent-fg); width:21px; height:21px; border-radius:50%; display:grid; place-items:center; }
  .cal-add { opacity:0; width:20px; height:20px; display:grid; place-items:center; color:var(--muted); border-radius:5px; transition:opacity .12s; }
  .cal-day:hover .cal-add { opacity:1; }
  .cal-add:hover { background:var(--hover-2); color:var(--fg); }
  .cal-events { display:flex; flex-direction:column; gap:3px; }
  .cal-ev { font-size:12px; padding:2px 7px; border-radius:5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:grab; touch-action:none;
    background:color-mix(in srgb,var(--c) 16%,transparent); color:var(--c); border-left:2px solid var(--c); }
  .cal-ev:hover { filter:brightness(1.04); box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--c) 40%,transparent); }
  :root[data-resolved="dark"] .cal-ev { background:color-mix(in srgb,var(--c) 24%,transparent); color:color-mix(in srgb,var(--c) 78%,#fff); }
  .cal-more { display:block; width:100%; text-align:left; font-size:var(--fs-xs); color:var(--muted); padding:2px 7px; border-radius:5px; }
  .cal-more:hover { background:var(--hover-2); color:var(--fg-soft); }

  /* ---- timeline (gantt) view ---- */
  .tl { margin-top:4px; }
  .tl-toolbar { display:flex; align-items:center; gap:8px; padding:2px 0 12px; }
  .tl-scroll { overflow:auto; border:1px solid var(--line); border-radius:var(--radius); max-height:calc(100vh - 230px); max-height:calc(100dvh - 230px); }
  .tl-canvas { position:relative; }
  .tl-axis { position:sticky; top:0; z-index:4; background:var(--surface); border-bottom:1px solid var(--line); }
  .tl-corner { position:sticky; left:0; z-index:5; height:100%; display:flex; align-items:center; padding:0 12px; font-size:12px; font-weight:600; color:var(--muted);
    background:var(--surface); border-right:1px solid var(--line); }
  .tl-tick { position:absolute; top:0; height:100%; box-sizing:border-box; border-right:1px solid var(--line); display:flex; flex-direction:column; justify-content:flex-end; padding:0 0 4px 4px; }
  .tl-tick.mstart { border-right-color:var(--line-strong); }
  .tl-tick .tl-month { position:absolute; top:5px; left:4px; font-size:10.5px; font-weight:700; color:var(--fg-soft); white-space:nowrap; }
  .tl-tick .tl-dnum { font-size:var(--fs-micro); color:var(--muted); }
  .tl-tick.today .tl-dnum { color:var(--accent); font-weight:700; }
  .tl-row { position:absolute; left:0; right:0; border-bottom:1px solid var(--line); }
  .tl-rowlabel { position:sticky; left:0; z-index:3; height:100%; display:flex; align-items:center; padding:0 12px; font-size:13px; font-weight:500;
    background:var(--bg); border-right:1px solid var(--line); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .tl-item { position:absolute; top:7px; height:22px; box-sizing:border-box; background:var(--accent); color:var(--accent-fg); border-radius:6px;
    display:flex; align-items:center; gap:2px; padding:0 4px; cursor:grab; touch-action:none; box-shadow:var(--shadow-sm); overflow:hidden; }
  .tl-item .tl-label { flex:1; font-size:12px; font-weight:500; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; pointer-events:none; }
  .tl-row:hover .tl-item { box-shadow:0 0 0 1px var(--accent), var(--shadow-sm); }
  /* Edge handles: a small centered round-capped grip inside the colored bar.
     --accent-fg (not white) keeps contrast right in both themes — dark grip on
     the light-purple dark-mode bar, white grip on the blue light-mode bar. */
  .tl-item .tl-h { position:relative; width:9px; align-self:stretch; flex:none; cursor:col-resize; opacity:0; transition:opacity .15s; touch-action:none; }
  .tl-item .tl-h::before { content:""; position:absolute; left:50%; top:50%; width:3px; height:10px;
    transform:translate(-50%,-50%); border-radius:999px;
    background:color-mix(in srgb, var(--accent-fg) 70%, transparent);
    transition:height .15s cubic-bezier(.4,0,.2,1), background .15s; }
  .tl-item:hover .tl-h, .tl-item .tl-h.dragging { opacity:1; }
  .tl-item .tl-h:hover::before, .tl-item .tl-h.dragging::before { height:14px; background:var(--accent-fg); }
  .tl-milestone { position:absolute; top:9px; width:18px; height:18px; transform:rotate(45deg); background:var(--accent); border-radius:3px; cursor:grab; touch-action:none; box-shadow:var(--shadow-sm); margin-left:-9px; }
  .tl-milestone:hover { box-shadow:0 0 0 2px var(--accent-soft), var(--shadow-sm); }
  .tl-track-empty { position:absolute; top:0; right:0; height:100%; cursor:copy; }
  .tl-track-empty:hover { background:var(--hover); }
  .tl-schedule { position:sticky; top:7px; height:22px; display:inline-flex; align-items:center; padding:0 10px; border-radius:6px; font-size:12px;
    color:var(--muted); border:1px dashed var(--line-strong); background:var(--bg); white-space:nowrap; }
  .tl-schedule:hover { color:var(--accent); border-color:var(--accent); }
  .tl-today { position:absolute; top:0; width:2px; background:var(--accent); opacity:.55; z-index:2; pointer-events:none; }
  .tl-guide { position:absolute; top:0; width:0; border-left:1px dashed var(--accent); z-index:6; pointer-events:none; }
  .tl-guide-label { position:absolute; top:2px; left:4px; font-size:var(--fs-micro); font-weight:600; color:var(--accent-fg); background:var(--accent);
    padding:1px 6px; border-radius:5px; white-space:nowrap; box-shadow:var(--shadow-sm); }

  /* mobile */
  /* Gate on a coarse pointer, not width alone: a narrow *desktop* window keeps
     the desktop layout/sizes (no jarring snap to 16px fonts + 40px buttons when
     it crosses 768px), while phones/tablets (and DevTools device mode, which
     emulates coarse) get the touch treatment. JS useIsMobile mirrors this query. */
  @media (max-width: 768px) and (pointer: coarse) {
    /* Full-page navigation, document-scrolled: the active view (home sidebar
       or the picked content view, via body.mobile-content from app.tsx) sits
       in normal flow and the *document* scrolls; the inactive view is
       display:none. This is structural for iOS 26 Safari: its liquid-glass
       bars only composite pixels from the document's scrolled canvas — a
       fixed pane with an inner scroller never paints under the bottom bar,
       so the chrome degrades to a tint sampled once and frozen (opaque pane
       bg) or fallback white (transparent pane); no see-through, and theme
       switches never propagate. In-flow content gets both for free: glass
       blurs live pixels, colors follow theme/navigation in real time.
       (app.tsx owns the scroll handoff between the two views.) */
    body { overflow:auto; }
    #app { display:block; height:auto; }
    .sidebar { width:100% !important; min-height:100dvh; margin-left:0 !important;
      border-right:0; transition:none; }
    body.mobile-content .sidebar { display:none; }
    .main { display:none; }
    body.mobile-content .main { display:flex; min-height:100dvh; overflow:visible;
      animation:page-in .22s cubic-bezier(.4,0,.2,1); }
    .sb-scroll { flex:none; overflow:visible; }
    .content { flex:none; overflow:visible; }
    /* Keep the back-button header pinned while the document scrolls. Its
       background must sit on the sticky box itself: the status-bar tint is
       sampled from edge-touching sticky elements' own background-color — a
       transparent box samples as a fallback white. Each home↔content switch
       toggles the pane's display, a real render-tree entry, so the tint
       re-samples on navigation. */
    .topbar { position:sticky; top:0; z-index:30; background:var(--bg); }
    /* With no sticky element at an edge (home top, all bottoms) the chrome
       derives from the html/body backgrounds and the scrolled canvas — keep
       all of them tracking the active surface so bars and overscroll blend. */
    html:has(body.mobile), body.mobile { background:var(--sidebar); }
    html:has(body.mobile-content), body.mobile-content { background:var(--bg); }
    .sb-head .iconbtn { display:none; }          /* no collapse on mobile */
    .sb-resizer { display:none; }
    .topbar .hamburger { display:grid; }         /* serves as the back button */

    /* Sites/settings move from the bottom footer rows up into the home header
       as icon buttons — no full-width strip eating into the list + safe area. */
    .sb-footer { display:none; }
    .sb-act { display:grid; place-items:center; width:40px; height:40px; flex:none;
      border-radius:var(--radius-sm); color:var(--fg-soft); position:relative; }
    .sb-act:active, .sb-act.active { background:var(--hover-2); color:var(--fg); }
    .sb-act .ico { width:20px; height:20px; }
    .sb-act .nav-dot { position:absolute; top:7px; right:7px; box-shadow:0 0 0 2px var(--sidebar); }

    /* Phone typography: bigger text for a small screen held close. Tap-target
       sizing and the 16px iOS anti-zoom inputs live in the width-independent
       (pointer:coarse) block below — tablets need those too. */
    .navitem { padding:9px 8px; font-size:16px; }
    .navitem .emoji { font-size:18px; }
    .navitem .tw { width:26px; height:26px; }
    .sb-section-head { font-size:12px; }
    .sb-search kbd { display:none; }  /* no hardware keyboard, no shortcut hint */
    /* Search box is hidden until the header search button reveals it; it then
       slides+fades down in. Desktop base (.sb-search{display:flex}) is untouched,
       so search stays always-on there. reduced-motion is handled globally. */
    .sb-search { display:none; }
    .sb-search.open { display:flex; animation:search-reveal .22s cubic-bezier(.32,.72,0,1); }
    @keyframes search-reveal { from { opacity:0; transform:translateY(-8px); } }
    .btn { font-size:15px; }
    .crumb { font-size:16px; }
    .pop .item { font-size:16px; }
    .pop .item .t { font-size:16px; }

    /* Document: bigger body text, tighter side padding for narrow screens. */
    .doc { padding:24px 18px calc(36vh + env(safe-area-inset-bottom)); }
    .doc-title { font-size:30px; }
    .doc .editable { font-size:16px; }
    /* 16px (not 14): a focused code textarea below 16px makes iOS auto-zoom. */
    .codeblock { --code-fs:16px; }
    .block .gutter { display:none; }
    /* Anchor/TOC jumps: clear the mobile topbar (49px min + notch inset);
       the desktop 60px estimate leaves blocks half-hidden behind it. */
    .block { scroll-margin-top:calc(49px + env(safe-area-inset-top) + 8px); }
    /* Find bar clears the taller mobile topbar (49px min + notch inset). */
    .find-bar { top:calc(49px + env(safe-area-inset-top) + 8px); }
    .db { padding:16px 14px 90px; }
    .peek { width:100%; }
    /* history drawer: the side-by-side list/preview doesn't fit a phone — stack. */
    .hist-split { flex-direction:column; }
    .hist-list { width:auto; max-height:38%; border-right:0; border-bottom:1px solid var(--line); }

    /* Safe areas (viewport-fit=cover): keep chrome clear of the notch / home bar. */
    .sb-head { padding-top:calc(14px + env(safe-area-inset-top)); }
    .topbar { padding-top:calc(10px + env(safe-area-inset-top)); }
    /* no footer on mobile, so the list itself clears the home indicator */
    .sb-scroll { padding-bottom:calc(24px + env(safe-area-inset-bottom)); }

    /* Overlays: dialogs become bottom sheets (centered cards fight the soft
       keyboard), and fixed-bottom chrome stays clear of the home indicator. */
    .modal-scrim { align-items:flex-end; padding:0; }
    .modal { width:100%; max-height:92vh; max-height:92dvh;
      border-radius:var(--radius-xl) var(--radius-xl) 0 0;
      padding-bottom:env(safe-area-inset-bottom);
      animation:sheet-up .22s cubic-bezier(.32,.72,0,1); }
    .toasts { left:12px; right:12px; bottom:calc(12px + env(safe-area-inset-bottom)); }
    .toast { justify-content:center; }
    .selbar { bottom:calc(16px + env(safe-area-inset-bottom)); max-width:calc(100vw - 24px); }
  }
  @keyframes sheet-up { from { transform:translateY(100%); } }
  /* In-flow stand-in for the old two-pane slide: only the entering view
     animates (the other is display:none, document-scroll layout above). */
  @keyframes page-in { from { transform:translateX(28px); opacity:0; } }

  /* Touch ergonomics, decoupled from width: tablets (iPad portrait is 820px+)
     keep the desktop layout above but still tap with fingers, so target sizes,
     drag handles and the iOS anti-zoom input size key off the pointer alone. */
  @media (pointer: coarse) {
    /* iOS Safari auto-zooms the page when a focused field is below 16px; the
       class selectors out-specify the element-level sizes set on these. */
    input, textarea, .text-input, .doc-source, input.inlineedit { font-size:16px; }
    .navitem .acts button { width:34px; height:34px; }
    .iconbtn { width:40px; height:40px; }
    .btn { padding:9px 14px; min-height:40px; }
    .pop .item { padding:11px 10px; }
    /* Column/sidebar resize handles: 7px is a mouse affordance, not a finger's. */
    .col-resizer, .doc-col-resizer, .sb-resizer { width:16px; right:-8px; }
  }

  /* No hover available (touch): controls that only materialize on :hover are
     unreachable, so pin them visible. Width-independent on purpose — this is
     the tablet's lifeline too. Desktops with a mouse are untouched. */
  @media (hover: none) {
    .code-tools { opacity:1; transform:none; pointer-events:auto; }
    .rowactions { opacity:1; pointer-events:auto; }
    .doc-th .doc-col-menu, .cal-add, .filerow .facts,
    .navitem .acts, .sb-section-head .add { opacity:1; }
    table.doc-table .doc-row-del { opacity:1; }
    .selcell input { opacity:1; }
    .rowgrip { color:var(--muted); }
    .tl-item .tl-h { opacity:1; }
    /* Neutralize the stickiest tap-residue tints (a tap "hovers" until the
       next tap elsewhere); transient menus/buttons are left alone. */
    .navitem:hover { background:none; }
    .iconbtn:hover { background:none; }
    tbody tr:hover { background:none; }
    td.cell-td:hover { background:none; }
    .filerow:hover { background:none; }
    .cal-day:hover { background:none; }
    .cal-day.dim:hover { background:var(--surface); }
  }

  /* Quick Notes window (desktop, loaded at #quick). A transparent body lets the
     macOS vibrancy blur show through; a translucent panel keeps text readable.
     The top bar is the window drag region; its buttons opt back out. */
  body.quicknote { background:transparent; }
  /* html carries an opaque bg for the iOS 26 Safari toolbar tint; the vibrancy
     window needs the root transparent again or the blur is walled off. */
  html:has(body.quicknote) { background:transparent; }
  /* The main app lays #app out as a flex row (sidebar + main); the quick-note
     route has a single child, so override to a full-bleed block or the panel
     shrinks to its content width and the window's vibrancy shows through. */
  body.quicknote #app { display:block; width:100vw; height:100vh; height:100dvh; }
  .qn { display:flex; flex-direction:column; width:100%; height:100vh; height:100dvh; overflow:hidden;
    background:color-mix(in srgb, var(--bg) 20%, transparent); }
  .qn-bar { display:flex; align-items:center; gap:6px; padding:4px 10px;
    user-select:none; -webkit-app-region:drag;
    background:color-mix(in srgb, var(--surface) 30%, transparent); }
  /* macOS only: clear the inset traffic lights; Win/Linux frameless has none */
  body.desktop-mac .qn-bar { padding-left:76px; }
  .qn-brand { flex:1; min-width:0; font-size:12px; font-weight:600; color:var(--fg-soft);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .qn-actions { display:flex; gap:2px; -webkit-app-region:no-drag; }
  .qn-actions .iconbtn { width:26px; height:26px; }
  .qn-actions .iconbtn.active { color:var(--accent); background:var(--hover-2); }
  .qn-body { flex:1; overflow:auto; -webkit-app-region:no-drag; }
  .qn-body .doc { max-width:none; margin:0; padding:14px 22px 30vh; }
  .qn-body .doc-title { font-size:24px; margin-bottom:2px; }
  .qn-body .doc-meta { display:none; }
  /* The narrow-width gutter hide is now gated on (pointer:coarse), which this
     desktop window never matches — re-hide explicitly: quick notes offer no
     block insert/drag handles (Enter / slash commands cover insertion). */
  body.quicknote .block .gutter { display:none; }
  /* A native checkbox paints an opaque white box when unchecked, which breaks
     the window's vibrancy blur. Draw a custom box so the unchecked background
     stays transparent; checked falls back to the accent fill + checkmark. */
  body.quicknote .b-todo .marker input {
    appearance:none; -webkit-appearance:none; box-sizing:border-box;
    border:1.5px solid color-mix(in srgb, var(--fg-soft) 55%, transparent);
    border-radius:4px; background:transparent; }
  body.quicknote .b-todo .marker input:checked {
    border-color:var(--accent);
    background:var(--accent) center/10px no-repeat
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5L20 7'/%3E%3C/svg%3E"); }
  /* Compact menus inside the quick-note window only (dropdown + slash command
     share .pop/.item/.lico with the main app; scope under body.quicknote so the
     main app keeps its roomier density). */
  body.quicknote .pop { padding:5px; border-radius:9px; }
  body.quicknote .pop .lbl { padding:4px 8px 2px; font-size:10px; }
  body.quicknote .pop .item { padding:5px 9px; gap:8px; font-size:var(--fs-sm); }
  body.quicknote .pop .item .t { font-size:var(--fs-sm); }
  body.quicknote .pop .item .d { font-size:10.5px; }
  body.quicknote .pop .item .lico { width:22px; height:22px; }
  body.quicknote .pop .item .lico.plain { width:20px; height:20px; }
  body.quicknote .pop .sep { margin:4px 4px; }

  /* Quick Notes settings rows (desktop only). */
  .qn-set-row { display:flex; align-items:center; gap:14px; padding:12px 0; border-top:1px solid var(--line); }
  .qn-set-row:first-of-type { border-top:0; }
  .qn-set-main { flex:1; min-width:0; }
  .qn-set-name { font-weight:600; }
  .qn-set-desc { color:var(--muted); font-size:13px; margin-top:2px; }
  .qn-shortcut { min-width:140px; justify-content:center; font-family:var(--mono); }
  .qn-shortcut.capturing { outline:2px solid var(--accent); color:var(--accent); }

  /* No-origin bootstrap: enroll screen + hydration splash (data-blind shell). */
  .enroll-splash { min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:24px; }
  .enroll-spinner { width:26px; height:26px; border-radius:50%; border:2.5px solid var(--line-strong); border-top-color:var(--accent); animation:enroll-spin .8s linear infinite; }
  @keyframes enroll-spin { to { transform:rotate(360deg); } }
  .enroll { min-height:100dvh; display:flex; align-items:center; justify-content:center; padding:24px; background:var(--bg); }
  .enroll-card { width:100%; max-width:420px; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-md,14px); padding:24px 22px; box-shadow:0 8px 30px rgba(0,0,0,.06); }
  .enroll-title { font-size:19px; font-weight:600; color:var(--fg); }
  .enroll-sub { color:var(--muted); font-size:13px; margin:6px 0 16px; line-height:1.5; }
  .enroll-bucket { margin:4px 0 12px; font-family:var(--mono); font-size:13px; }
  .enroll-err { color:var(--danger); font-size:13px; margin-top:12px; }
  .enroll-go { width:100%; justify-content:center; margin-top:18px; }
  .enroll-hint { font-size:12px; margin-top:14px; line-height:1.5; }

  /* Enroll QR (settings → 同步存储 → 在手机上打开). White bg so the black
     modules scan in any theme. */
  .qr-box { display:flex; justify-content:center; padding:14px; background:#fff; border-radius:10px; }
  .qr-box svg { width:208px; height:208px; display:block; }
