:root {
  color-scheme: dark;
  --bg: #1a1820;
  --panel: rgba(255, 255, 255, 0.04);
  --border: rgba(255, 255, 255, 0.08);
  --text: #d0cdd8;
  /* Was a bare near-white. The platform's light theme redefines --bright but
     NOT --text-bright, so the near-white leaked into light and painted
     white-on-white (1.13:1 on the top-bar buttons -- see the note in
     sheet.css, which worked around it locally instead of fixing it here).
     Follow the platform token in both themes; the literal stays as a
     fallback if base.v1.css ever fails to load. */
  --text-bright: var(--bright, #f2f0f8);
  --accent: #c8a86e;
  --danger: #f4839a;
  --ok: #7ed59d;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, "Segoe UI", sans-serif;
}

a { color: var(--accent); }

h1, h2, h3 { font-family: Georgia, serif; color: var(--text-bright); margin: 0 0 12px; }

button, .btn {
  font: inherit;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--text-bright);
  border-radius: 6px;
  padding: 8px 16px;
}
button:hover, .btn:hover { border-color: var(--accent); }
button.primary {
  background: var(--accent);
  color: #1a1820;
  font-weight: 700;
  border: none;
}
button.danger { color: var(--danger); }
button:disabled { opacity: 0.5; cursor: not-allowed; }

input[type="text"], input[type="email"], input[type="password"] {
  font: inherit;
  /* --panel, NOT a hardcoded #14121a. That literal was a dark-era colour and
     survived the 2026-06-16 light flip, while `color` below correctly follows
     --text-bright — which is DARK in light mode. The result was dark text on a
     near-black box: the spreadsheet's cell editor MEASURED 1.08:1 in the
     default theme, i.e. you could not see what you were typing.
     This selector is (0,1,1) and beat .sg-editor at (0,1,0), so the app's own
     token-based styling never got a look in. --panel is the shared surface and
     the ctheme engine rebinds it, so this tracks every paid theme too. */
  background: var(--panel, #ffffff);
  border: 1px solid var(--border);
  color: var(--text-bright);
  border-radius: 6px;
  padding: 10px 12px;
  width: 100%;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border);
}

/* flex:1 so short pages (empty doc list, login form) push the shared
   #dl-footer (appended after .container by chrome.v1.js) down to the
   true bottom of the viewport instead of it trailing right under sparse
   content — standard sticky-footer pattern, paired with body's flex
   column above. */
.container { max-width: 900px; margin: 0 auto; padding: 32px 24px; flex: 1; }

/* The ecosystem default (chrome.v1.css: 48px margin-top, 32/36px padding)
   is sized for a full marketing page; trim it down for this app. */
#dl-footer { margin-top: 24px; padding: 18px 16px 22px; }

.doc-list { display: flex; flex-direction: column; gap: 8px; margin-top: 24px; }
.doc-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.doc-row .title { font-weight: 600; color: var(--text-bright); }
.doc-row .meta { font-size: 12px; opacity: 0.7; margin-top: 2px; }
.doc-row .actions { display: flex; gap: 8px; }
.doc-row a.open { flex: 1; text-decoration: none; color: inherit; }

.empty-state { text-align: center; padding: 60px 20px; opacity: 0.7; }

.modal-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,0.5);
  display: flex; align-items: center; justify-content: center; z-index: 50;
}
.modal {
  background: #1f1d27; border: 1px solid var(--border); border-radius: 12px;
  padding: 24px; width: 420px; max-width: 90vw;
}
.modal .row { display: flex; gap: 8px; margin-top: 16px; }
.share-link-box {
  display: flex; gap: 8px; margin-top: 12px;
}
.share-link-box input { flex: 1; }

/* Editor */
/* Not height:100vh on .editor-shell directly: the shared chrome shell
   (master architecture) reserves body padding-top/padding-bottom for its
   fixed top bar and footer via `!important` — a flat 100vh here ignores
   that and overflows the real viewport by however much the bars take up
   (measured ~84px live before this fix). Making body the flex container
   means editor-shell's flex:1 fills whatever space is ACTUALLY left after
   body's own padding, chrome present or not — verified against a live
   screenshot, not just reasoned about, since this exact class of chrome-vs-
   fixed-height conflict is easy to get wrong on paper. */
/* height, not min-height: flex:1 children need a DEFINITE container size to
   compute their own available space against — min-height only sets a floor,
   so the chain below just hugs content (including .editor-surface's
   min-height:1000px) instead of clipping it into a scrollable region. Safe
   with the global `* { box-sizing: border-box }` reset above: body's own
   chrome-injected padding is subtracted from this height, not added to it. */
body.editor-page { display: flex; flex-direction: column; height: 100vh; }
.editor-shell { display: flex; flex-direction: column; flex: 1; min-height: 0; }
/* Matches the platform chrome bar's (#dl-chrome-bar, chrome.v1.css) size
   and format exactly: same height var, same frosted-glass background +
   blur, same font, same --dlc-* text/border/accent tokens — reads as a
   continuation of that bar rather than the app's own dark-mode chrome.
   Values fall back to the light-theme defaults chrome.v1.css ships if
   that stylesheet hasn't loaded (e.g. local dev, blocked cross-origin by
   this app's own CSP) so the bar still renders sanely on its own. */
.editor-topbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
  /* min-height, not height: a fixed height let wrapped rows (narrow
     screens, many toolbar buttons) render outside the box and overlap
     .editor-page-wrap below — caught by measuring the export button's
     real position (y:190) against the topbar's own claimed bottom edge
     (y:74), not by eyeballing a screenshot where it wasn't obvious. */
  min-height: var(--dlc-bar-h, 40px);
  padding: 4px 16px;
  background: var(--dlc-bg-glass, linear-gradient(180deg, rgba(255,255,255,0.55), rgba(255,255,255,0.16) 60%, rgba(255,255,255,0)), rgba(243,241,250,0.55));
  backdrop-filter: blur(32px) saturate(160%) brightness(104%);
  -webkit-backdrop-filter: blur(32px) saturate(160%) brightness(104%);
  border-bottom: 1px solid var(--dlc-border, rgba(60,56,84,0.15));
  box-shadow: 0 1px 0 var(--dlc-rim, rgba(255,255,255,0.75)) inset, 0 4px 18px -8px var(--dlc-bar-shadow, rgba(60,56,84,0.16));
  font-family: var(--dlc-sans, -apple-system, "Segoe UI", sans-serif);
  font-size: 14px;
  color: var(--dlc-text, #3a3848);
}
.editor-topbar .btn, .editor-topbar button {
  color: var(--dlc-text, #3a3848);
  background: transparent;
  border-color: var(--dlc-border, rgba(60, 56, 84, 0.15));
  font-family: inherit;
  padding: 4px 12px;
}
.editor-topbar .btn:hover, .editor-topbar button:hover { border-color: var(--dlc-accent, #b8911e); }
/* Small square icon button (the eraser "clear saved data" reset) — centers
   its inline SVG; the SVG strokes follow the bar's text colour via currentColor. */
.editor-topbar .icon-btn { display: inline-flex; align-items: center; justify-content: center; padding: 4px 9px; }
.editor-topbar .icon-btn svg { display: block; }
.editor-topbar #resetBtn:hover { color: var(--danger, #f4839a); border-color: var(--danger, #f4839a); }
.editor-topbar .inline-toolbar button.active {
  border-color: var(--dlc-accent, #b8911e); color: var(--dlc-accent, #b8911e);
}
.editor-topbar input.doc-title {
  flex: 1; min-width: 120px; background: transparent; border: none;
  color: var(--dlc-text-bright, #1c1a26);
  font-size: 14px; font-family: inherit;
}
.editor-topbar input.doc-title::placeholder { color: var(--dlc-text-dim, #6e6c7e); }
.editor-topbar input.doc-title:focus { outline: none; border-bottom: 1px solid var(--dlc-accent, #b8911e); }
.editor-topbar .save-status { color: var(--dlc-text-dim, #6e6c7e); }
.save-status { font-size: 12px; opacity: 0.6; min-width: 90px; }

/* Merged into .editor-topbar itself, between the title and Save/Export,
   instead of shared.html's separate full-width .toolbar row below the
   title bar — smaller buttons since this one now competes for space with
   the title/save/export in a single bar. */
.inline-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; }
.inline-toolbar button { padding: 4px 7px; min-width: 24px; font-size: 13px; font-weight: 700; }
.inline-toolbar .sep { width: 1px; align-self: stretch; background: var(--border); margin: 2px 1px; }

.toolbar {
  display: flex; flex-wrap: wrap; gap: 4px; padding: 8px 16px;
  border-bottom: 1px solid var(--border); background: rgba(0,0,0,0.15);
}
.toolbar button {
  padding: 6px 10px; min-width: 32px; font-weight: 700;
}
.toolbar button.active, .inline-toolbar button.active { border-color: var(--accent); color: var(--accent); }
.toolbar .sep { width: 1px; background: var(--border); margin: 4px 6px; }

/* Lives inside .editor-page-wrap now, right after .editor-surface (moved
   there in editor.html) — was previously a full-width strip above the
   toolbar, permanently squeezing the editing area exactly like #dl-footer
   used to. Sized to match the document card above it rather than the
   footer's full-width treatment, since this note is about the document,
   not site-wide chrome. */
.local-banner {
  max-width: 760px;
  margin: 24px auto 0;
  padding: 10px 16px;
  font-size: 13px;
  background: rgba(200, 168, 110, 0.12);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
}
/* This banner is a 12% gold wash (rgba(200,168,110,.12)) over --bg, which
   composites to ~rgb(239,233,233). base's link catch-all paints --accent-text
   there at 4.17-4.29:1. Rebind the token for the subtree -- the documented
   idiom -- so the catch-all and any app rule inside it both follow. */
html:not([data-theme="dark"]) .local-banner { --accent-text: var(--accent-text-strong); }
.local-banner a { font-weight: 600; }

.editor-page-wrap { flex: 1; overflow-y: auto; padding: 32px 16px; }
/* editor.js/shared.js relocate the shared #dl-footer in here (after
   .editor-surface) once chrome.v1.js appends it to <body> — on this
   fixed-100vh flex layout, leaving it as a body-level sibling squeezes
   .editor-shell's flex:1 by the footer's height instead of it reading as
   the end of the document. Tightened further since it now sits right
   under the document card rather than a full page. */
.editor-page-wrap #dl-footer { margin-top: 32px; padding: 16px 16px 8px; }
/* The sheet matches a real US Letter page: 8.5in x 11in at 96px/in = 816 x
   1056, with 1in (96px) margins. `width` (not just max-width) fixes the page
   size so it reads as an actual printout, and `max-width:100%` lets it shrink
   to fit narrow screens instead of overflowing (a fixed 816 would force the
   mobile shrink-to-fit zoom). min-height is exactly one page; it grows by
   content past that. box-sizing:border-box (global reset) means the 96px
   padding is the page margin, inside the 816x1056 sheet. */
.editor-paper {
  position: relative;
  width: 816px; max-width: 100%; margin: 0 auto 40px;
}
/* The paper. One .page-sheet per page, stacked behind the text with a real
   gutter between them, so the document reads as a stack of Letter pages
   instead of one endless roll.

   This sits OUTSIDE the contenteditable on purpose. The document is saved as
   surface.innerHTML and re-sanitised against a tag allowlist server-side, so
   page furniture injected into the editable region would either be persisted
   as if the user typed it or silently stripped on the round trip. Splitting
   the text itself across one contenteditable per page would mean
   re-implementing selection, undo and paste across page boundaries — this
   keeps the single editing surface exactly as it was.

   Flex + gap means the sheets position themselves: no per-page geometry has
   to be generated, editor.js only has to append or remove divs. */
.page-layer {
  position: absolute; top: 0; left: 0; right: 0;
  display: flex; flex-direction: column; gap: 28px;
  pointer-events: none;   /* clicks land on the text above, not the paper */
  z-index: 0;
}
.page-sheet {
  flex: none; height: 1056px;
  background: #fdfcf9;
  border-radius: 4px; box-shadow: 0 4px 24px rgba(0,0,0,0.35);
}
/* Sizes itself, because shared.html (the share-link view) uses .editor-surface
   WITHOUT the .editor-paper wrapper — moving the width onto the wrapper alone
   stretched that page's sheet to the full width of the scroll pane. The
   wrapper takes over only where it actually exists. */
.editor-surface {
  position: relative; z-index: 1;
  width: 816px; max-width: 100%; margin: 0 auto 40px;
  background: #fdfcf9; color: #1c1a22;
  min-height: 1056px; padding: 96px;
  border-radius: 4px; box-shadow: 0 4px 24px rgba(0,0,0,0.35);
  line-height: 1.5; font-size: 16px;
}
.editor-paper > .editor-surface { width: 100%; margin: 0; }
/* Once pagination is running the sheets below supply the paper, so the
   surface stops drawing its own — otherwise its single tall background
   would paint straight over the gutters. Kept as a class rather than
   removed outright so the un-paginated fallback (narrow screens, or a
   browser without constructable stylesheets) still looks exactly as it
   did before. */
.editor-paper.paginated .editor-surface {
  background: transparent; box-shadow: none; border-radius: 0;
}
.editor-paper:not(.paginated) .page-layer { display: none; }
/* Phones don't print — drop the rigid page height and the wide margins so the
   sheet stays usable (and never wider than the viewport) on a small screen. */
@media (max-width: 620px) {
  .editor-surface { padding: 40px 22px; min-height: 78vh; }
}
/* Make an actual print/PDF export come out as Letter with 1in margins. */
@page { size: letter; margin: 1in; }
.editor-surface:focus { outline: none; }
/* Tight, document-like vertical rhythm. The browser default <p> margin
   (1em top + 1em bottom) stacked on EVERY paragraph, so pasted notes — lots
   of short lines and blank lines — sprawled with ~1.5 blank lines between
   each and looked broken. A small bottom-only margin + 1.5 line-height reads
   like a real document. `div` is covered too in case a browser emits <div>s
   instead of <p> on Enter. */
.editor-surface p, .editor-surface div { margin: 0 0 0.35em; }
.editor-surface ul, .editor-surface ol { margin: 0.15em 0 0.4em; }
.editor-surface h1 { color: #1c1a22; font-size: 28px; margin: 0.4em 0 0.3em; }
.editor-surface h2 { color: #1c1a22; font-size: 22px; margin: 0.55em 0 0.25em; }
.editor-surface h3 { color: #1c1a22; font-size: 18px; margin: 0.55em 0 0.25em; }
/* The shared site chrome paints headings for the DARK page background:
   html[data-theme="dark"].dl-chrome-present h1,h2,h3,h4 { color:#f4f2fa
   !important }. That !important also lands on headings inside the document,
   which is on white paper — measured at 1.08:1 against #fdfcf9, i.e. all but
   invisible, and only in dark mode (light mode was fine, which is why it
   survived). Body text was never affected because chrome doesn't restyle <p>.

   Overridden here rather than in the shared chrome: that rule is right for
   every other page on the platform, and the paper is what makes this editor
   the exception. The id beats the chrome selector's specificity outright
   instead of relying on stylesheet order. */
html.dl-chrome-present #surface h1,
html.dl-chrome-present #surface h2,
html.dl-chrome-present #surface h3,
html.dl-chrome-present #surface h4 { color: #1c1a22 !important; }
.editor-surface > *:first-child { margin-top: 0; }
.editor-surface blockquote {
  border-left: 3px solid #c8a86e; margin: 0 0 0.5em 4px; padding-left: 16px; color: #514d5c;
}
.editor-surface a { color: #8a6a30; }

/* Alignment as classes, not inline style="text-align:...": execCommand's
   justifyLeft/Center/Right/Full sets a style attribute, which this app's
   CSP (style-src 'self', no unsafe-inline) silently refuses to render —
   confirmed by actually checking getComputedStyle after using the button,
   not just checking that the markup round-tripped. Classes go through the
   same 'self' stylesheet and aren't affected. */
.align-left { text-align: left; }
.align-center { text-align: center; }
.align-right { text-align: right; }
.align-justify { text-align: justify; }

/* ---------- Editor v2 content formatting ----------
   Every rule below is class-based on purpose: the CSP is style-src 'self'
   with no unsafe-inline, so an inline style="" attribute silently doesn't
   render (that's the whole reason alignment above is class-based too). */

/* Indent as classes, not execCommand's inline margin-left (CSP-blocked). */
.indent-1 { margin-left: 32px; }
.indent-2 { margin-left: 64px; }
.indent-3 { margin-left: 96px; }
.indent-4 { margin-left: 128px; }
.indent-5 { margin-left: 160px; }
.indent-6 { margin-left: 192px; }
.indent-7 { margin-left: 224px; }
.indent-8 { margin-left: 256px; }

/* Highlight swatches (on <mark>) and text-colour swatches (on <span>),
   tuned for the cream document surface (#fdfcf9, dark text). */
mark.hl-yellow { background: #fdf19a; color: inherit; }
mark.hl-green  { background: #bdeec0; color: inherit; }
mark.hl-pink   { background: #ffc7d9; color: inherit; }
mark.hl-blue   { background: #bfe3ff; color: inherit; }
span.fg-red    { color: #c0392b; }
span.fg-orange { color: #c26a1c; }
span.fg-green  { color: #2e7d46; }
span.fg-blue   { color: #2265b8; }
span.fg-purple { color: #7a3fb0; }
span.fg-gray   { color: #6b6675; }

.editor-surface pre {
  background: #f4f2ec; color: #2a2833;
  padding: 12px 14px; border-radius: 6px; margin: 0 0 12px;
  overflow-x: auto; white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 14px;
}
.editor-surface code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 0.92em;
  background: #eeece6; padding: 1px 5px; border-radius: 4px;
}
.editor-surface pre code { background: none; padding: 0; font-size: inherit; }
.editor-surface hr { border: none; border-top: 1px solid #d8d4c8; margin: 20px 0; }

/* Checklist: a <ul class="task-list"> whose <li>s draw a class-based
   checkbox via ::before (no <input> — the sanitizer would strip it and its
   checked state wouldn't persist). A click in the left gutter toggles the
   `checked` class (see editor.js). */
.editor-surface ul.task-list { list-style: none; padding-left: 6px; }
.editor-surface ul.task-list li { position: relative; list-style: none; padding-left: 30px; }
.editor-surface ul.task-list li::before {
  content: ""; position: absolute; left: 2px; top: 0.3em;
  width: 16px; height: 16px; box-sizing: border-box;
  border: 1.6px solid #6b6675; border-radius: 4px;
}
.editor-surface ul.task-list li.checked::before {
  content: "\2713"; color: #fff; background: #3aa06a; border-color: #3aa06a;
  font-size: 12px; line-height: 15px; text-align: center;
}
.editor-surface ul.task-list li.checked { color: #8a8790; text-decoration: line-through; }

/* Find & replace highlighting via the CSS Custom Highlight API — styles the
   match ranges WITHOUT mutating the DOM (nothing to strip before save, and
   no inline styles for the CSP to block). */
::highlight(find-match)   { background: #ffe08a; color: #1c1a22; }
::highlight(find-current) { background: #c8a86e; color: #1c1a22; }

/* ---------- Editor v2 toolbar/UI chrome ---------- */

/* Find & replace bar: a real flex row between the topbar and the page, so
   opening it pushes the document down rather than covering it. */
.find-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 6px 16px; border-bottom: 1px solid var(--dlc-border, rgba(60,56,84,0.15));
  background: rgba(0,0,0,0.15);
}
.find-bar input[type="text"] { width: auto; flex: 1; min-width: 110px; max-width: 240px; padding: 6px 10px; }
.find-bar button { padding: 6px 10px; }
.find-count { font-size: 12px; opacity: 0.7; min-width: 60px; }

/* Text-colour / highlight swatch dropdowns in the toolbar. */
.swatch-wrap { position: relative; display: inline-flex; }
.swatch-menu {
  position: absolute; left: 0; top: 34px; z-index: 20;
  display: grid; grid-template-columns: repeat(4, 22px); gap: 6px;
  background: #1f1d27; border: 1px solid var(--border); border-radius: 8px; padding: 8px;
}
.swatch {
  width: 22px; height: 22px; min-width: 0; padding: 0; border-radius: 5px;
  border: 1px solid rgba(255,255,255,0.25); cursor: pointer;
}
.swatch-menu-fg .swatch { display: grid; place-items: center; font-weight: 800; font-size: 13px; background: #14121a; }
/* Swatch preview colours come from these class rules (not inline styles) so
   each swatch shows the colour/highlight it applies. The palette mirrors the
   fg-*/hl-* rules above and the sanitizer allowlist — keep the three in sync. */
.swatch.fg-red { color: #c0392b; }
.swatch.fg-orange { color: #c26a1c; }
.swatch.fg-green { color: #2e7d46; }
.swatch.fg-blue { color: #2265b8; }
.swatch.fg-purple { color: #7a3fb0; }
.swatch.fg-gray { color: #6b6675; }
.swatch.hl-yellow { background: #fdf19a; }
.swatch.hl-green { background: #bdeec0; }
.swatch.hl-pink { background: #ffc7d9; }
.swatch.hl-blue { background: #bfe3ff; }
.swatch.swatch-none {
  grid-column: 1 / -1; width: auto; height: auto; padding: 4px 0;
  font-size: 12px; background: transparent; color: var(--text); text-align: center;
}

.doc-stats { font-size: 12px; opacity: 0.6; white-space: nowrap; }

/* Inline link editor — a small floating card positioned at the caret. */
.link-popover {
  position: fixed; z-index: 60; width: 280px; max-width: 92vw;
  background: #1f1d27; border: 1px solid var(--border); border-radius: 10px;
  padding: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.45);
}
.link-popover input[type="text"] { margin-bottom: 10px; }
.link-popover-actions { display: flex; gap: 6px; }
.link-popover-actions button { padding: 6px 10px; flex: 1; }

@media print {
  .editor-topbar, .toolbar, .find-bar, .swatch-menu, .link-popover, .no-print, #dl-footer { display: none !important; }
  .editor-page-wrap { overflow: visible; padding: 0; }
  /* @page already supplies the Letter size + 1in margins, so the sheet itself
     resets to fill that content box (no double margin, no fixed page height). */
  .editor-surface { box-shadow: none; max-width: none; width: auto; min-height: 0; margin: 0; padding: 0; }
  /* The screen's paper and its min-height are simulation — the printer draws
     the real pages. editor.js emits a matching `break-before: page` for every
     block it pushed on screen, so the printed pagination lands on exactly the
     same blocks (the geometry already agrees: 1056px - 2x96px padding = 864px
     of content per screen page, and 11in - 2x1in of @page margin = 9in = the
     same 864px in print). */
  .editor-paper { width: auto; max-width: none; margin: 0; }
  .page-layer { display: none; }
  body { background: #fff; }
}

.auth-err { color: var(--danger); font-size: 13px; min-height: 18px; margin-top: 8px; }
.auth-form { display: flex; flex-direction: column; gap: 12px; max-width: 360px; margin: 60px auto; }
.auth-flip { cursor: pointer; opacity: 0.8; text-align: center; }

/* Utility classes exist so nothing needs an inline style="" attribute —
   the CSP is script-src/style-src 'self' with no 'unsafe-inline'. */
.hidden { display: none !important; }
.link-plain { text-decoration: none; }
.export-menu-wrap { position: relative; }
.export-menu {
  position: absolute; right: 0; top: 36px; background: #1f1d27;
  border: 1px solid var(--border); border-radius: 8px; padding: 6px;
  z-index: 10; min-width: 160px;
}
.export-menu button {
  display: block; width: 100%; text-align: left; border: none; background: none;
}

/* The ".doc-belownav" card and its styles were removed 2026-08-07 — it
   duplicated the standard /files footer that sits right below it. See the
   note in editor.html and dl-site.editor-nav.js. */

/* ══════════════════════════════════════════════════════════════════════
   2026-08-10 — COMPACTION + TWO-STAGE HOVER PASS
   Append-only: every rule below re-declares an existing selector at equal or
   higher specificity and wins on order, so the original blocks (and their
   comments, which explain WHY several of these values exist) stay intact.
   ══════════════════════════════════════════════════════════════════════ */

/* ── 1. Menu surfaces were dark-era hardcodes ──────────────────────────
   .export-menu / .swatch-menu / .modal / .link-popover all shipped
   background:#1f1d27. Since the 2026-06-16 light flip that is a near-black
   card carrying dark text: the Export dropdown MEASURED 1.46:1 in the light
   theme (14.48:1 in dark), i.e. effectively invisible in the platform's
   DEFAULT theme. --panel is the shared card surface (#ffffff light,
   #25232d dark) and the ctheme engine rebinds it per paid theme, so this
   tracks all 43 themes instead of one. */
.export-menu, .swatch-menu, .modal, .link-popover {
  background: var(--panel, #ffffff);
  box-shadow: 0 10px 30px -6px rgba(28, 26, 38, 0.28);
}
.swatch { border: 1px solid var(--border, rgba(60, 56, 84, 0.14)); }
.swatch-menu-fg .swatch { background: var(--bg, #f4f2fa); }

/* ── 2. The bar itself ─────────────────────────────────────────────────
   The 8px/12px gaps and 16px padding were set when this bar held about six
   controls. It now holds twenty, so they are the difference between one row
   and two. */
.editor-topbar { gap: 3px 7px; padding: 3px 12px; }
.editor-topbar .btn, .editor-topbar button { padding: 4px 10px; }
.editor-topbar .iconish { padding: 4px 9px; }
.editor-topbar input.doc-title { min-width: 84px; font-size: 13.5px; }
.save-status { min-width: 0; }
.doc-stats { font-size: 11.5px; }

/* Active state used --dlc-accent (#b8911e) as TEXT, which is 2.9:1 on white.
   The platform split that token on 2026-08-07 precisely for this: --accent-text
   is the ink (4.9:1), --dlc-accent stays the fill and keeps the border. */
.editor-topbar .inline-toolbar button.active {
  border-color: var(--dlc-accent, #b8911e);
  color: var(--accent-text, #866933);
}

/* ── 3. One toolbar line at every width ────────────────────────────────
   The toolbar NEVER wraps — it scrolls. That is what takes a 390px phone from
   four stacked rows of buttons to a single strip. Wrapping is still left to
   .editor-topbar, so a wide viewport collapses the whole bar onto one 40px
   line and a narrow one drops just the toolbar to a second line. */
.inline-toolbar {
  display: flex; flex-wrap: nowrap; align-items: center; gap: 1px;
  min-width: 0; overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.inline-toolbar::-webkit-scrollbar { display: none; }
.inline-toolbar button { padding: 3px 6px; min-width: 22px; font-size: 13px; }
.inline-toolbar .sep { margin: 3px 3px; }

/* ── 4. Dropdown clusters ──────────────────────────────────────────────
   ★ These menus are position:FIXED, not absolute. Their .dd-wrap parents live
   inside .inline-toolbar, which is now an overflow-x scroller — an absolutely
   positioned child would be CLIPPED by that scroll box. Fixed takes them out
   of it entirely; editor.js sets left/top from the button's rect. Writing
   el.style.left via CSSOM is not blocked by this app's style-src 'self' CSP
   (only style="" ATTRIBUTES in markup and inline <style> are), which the link
   popover already relies on. */
.dd-wrap { position: relative; display: inline-flex; }
.dd-menu {
  position: fixed; left: 0; top: 0; right: auto; z-index: 60;
  min-width: 168px; padding: 5px;
  background: var(--panel, #ffffff);
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  border-radius: 9px;
  box-shadow: 0 12px 34px -8px rgba(28, 26, 38, 0.34);
}
.export-menu { position: fixed; right: auto; top: 0; }
.swatch-menu { position: fixed; left: 0; top: 0; }

.inline-toolbar .dd-btn { font-weight: 600; display: inline-flex; align-items: center; gap: 3px; }
.dd-cur { max-width: 88px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-btn-icon .dd-cur { max-width: none; font-size: 14px; }
.dd-caret { opacity: 0.5; font-size: 9px; line-height: 1; }

.editor-topbar .dd-menu button, .dd-menu button {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  width: 100%; text-align: left; white-space: nowrap;
  border: 1px solid transparent; background: none;
  padding: 6px 9px; border-radius: 6px;
  font-weight: 500; font-size: 13px; min-width: 0;
  color: var(--text, #3a3848);
}
.editor-topbar .dd-menu button:hover, .dd-menu button:hover {
  background: var(--card-hover, #f6f4fc); border-color: transparent;
}
.editor-topbar .dd-menu button.active, .dd-menu button.active {
  color: var(--accent-text, #866933); font-weight: 700;
}
.dd-s { opacity: 0.45; font-size: 11px; font-weight: 400; }
.dd-lbl { display: inline-flex; align-items: center; gap: 9px; }
.dd-lbl .ai, .dd-cur .ai { display: block; flex: none; }
/* The style menu previews what each option looks like — cheaper to read than
   the words "Heading 2". */
.dd-p-h1 { font-size: 17px; font-weight: 800; }
.dd-p-h2 { font-size: 15px; font-weight: 700; }
.dd-p-h3 { font-size: 13.5px; font-weight: 700; }
.dd-p-quote { font-style: italic; opacity: 0.85; }
.dd-p-pre { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }

/* ── 5. Reclaim the gutter above the paper ─────────────────────────────── */
.editor-page-wrap { padding: 20px 16px; }

/* ── 6. Outline panel ──────────────────────────────────────────────────
   Costs nothing when shut, which is the whole point in a bar this crowded. */
.outline-panel {
  position: fixed; left: 0; top: var(--dlc-bar-h, 40px); bottom: 0; width: 262px;
  z-index: 45; overflow-y: auto; padding: 0 0 16px;
  background: var(--panel, #ffffff);
  border-right: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  box-shadow: 8px 0 30px -12px rgba(28, 26, 38, 0.3);
}
.outline-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 12px; font-size: 12px; letter-spacing: 0.06em;
  text-transform: uppercase; opacity: 0.7;
  border-bottom: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  position: sticky; top: 0; background: var(--panel, #ffffff);
}
.outline-head .icon-btn { padding: 2px 8px; border: none; background: none; font-size: 16px; }
.outline-list { display: flex; flex-direction: column; padding: 6px; }
.outline-list button {
  text-align: left; border: 1px solid transparent; background: none;
  padding: 5px 8px; border-radius: 6px; font-size: 13px; line-height: 1.35;
  color: var(--text, #3a3848); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis;
}
.outline-list button:hover { background: var(--card-hover, #f6f4fc); }
.outline-list button.lvl-1 { font-weight: 700; }
.outline-list button.lvl-2 { padding-left: 20px; font-weight: 500; }
.outline-list button.lvl-3 { padding-left: 34px; font-weight: 400; opacity: 0.85; }
.outline-empty { padding: 14px 14px 4px; font-size: 12.5px; opacity: 0.6; line-height: 1.5; }

/* ── 7. Focus mode ─────────────────────────────────────────────────────
   Hides the platform bars (which reserve body padding — hence !important on
   the padding reset) and leaves the editor bar, so the page is still
   editable. Fully client-side and reversed by Escape. */
body.focus-mode #dl-chrome-bar,
body.focus-mode #dl-footer,
body.focus-mode #dl-bottom-nav { display: none !important; }
body.focus-mode { padding-top: 0 !important; padding-bottom: 0 !important; }
body.focus-mode .outline-panel { top: 0; }
.focus-exit {
  position: fixed; right: 14px; bottom: 14px; z-index: 70;
  padding: 7px 14px; border-radius: 999px; font-size: 12.5px;
  background: var(--panel, #ffffff);
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  color: var(--text, #3a3848);
  box-shadow: 0 8px 24px -6px rgba(28, 26, 38, 0.34);
}

/* ── 8. Shortcut sheet ─────────────────────────────────────────────────── */
.modal-wide { width: 560px; }
.shortcut-grid {
  display: grid; grid-template-columns: 1fr auto; gap: 7px 20px;
  font-size: 13px; max-height: 58vh; overflow-y: auto; padding-right: 4px;
}
.shortcut-grid .sc-head {
  grid-column: 1 / -1; font-size: 11px; letter-spacing: 0.06em;
  text-transform: uppercase; opacity: 0.55; margin-top: 10px;
}
.shortcut-grid .sc-head:first-child { margin-top: 0; }
.shortcut-grid kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px;
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  border-radius: 5px; padding: 1px 6px; white-space: nowrap;
  background: var(--bg, #f4f2fa);
}

/* ── 9. Narrow widths ──────────────────────────────────────────────────
   order:9 pushes the toolbar below the document controls; flex-basis 100%
   gives it the full line. Without the order it would land on line 2 and
   shove Save/Export down to line 3 — the opposite of the goal. */
@media (max-width: 899px) {
  .inline-toolbar {
    flex: 1 0 100%; order: 9; padding-bottom: 2px;
    /* Fade the ends so it reads as scrollable rather than cut off. Only here:
       at wide widths the strip fits and a fade would just dim real buttons. */
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  }
  .doc-stats { display: none; }
  .editor-page-wrap { padding: 12px 10px; }
  /* Touch targets stay finger-sized even though the bar got shorter. */
  .inline-toolbar button { min-height: 30px; padding: 4px 8px; }
  .outline-panel { width: min(84vw, 300px); }
}
@media (max-width: 620px) {
  .editor-topbar input.doc-title { min-width: 60px; }
  .modal-wide { width: 92vw; }
}

/* Nothing in this pass should survive into a print/PDF export. */
@media print {
  .outline-panel, .focus-exit, .dd-menu { display: none !important; }
}

/* ── 2026-08-10 follow-up (measured, not predicted) ────────────────────
   flex-basis fix: the bar still broke to two rows from 1180px down to 900px.
   With flex-wrap, lines are broken using each item's HYPOTHETICAL size — its
   flex-basis — BEFORE shrinking is considered, so a content-sized toolbar
   claims a line of its own instead of shrinking into the one above. A small
   basis keeps it on the line; it then grows into the space left over, and the
   overflow-x scroller absorbs whatever still does not fit. */
@media (min-width: 900px) {
  .inline-toolbar { flex: 1 1 240px; }
}
/* Buttons measured 23px tall at 1180px — which is an iPad in LANDSCAPE, a
   touch device. Viewport width was the wrong signal for touch sizing. */
@media (pointer: coarse) {
  .inline-toolbar button { min-height: 32px; }
  .editor-topbar .btn, .editor-topbar button { min-height: 32px; }
  .dd-menu button { min-height: 34px; }
}

/* The title input was flex:1 — it GREW into the slack the toolbar needed, so
   the toolbar scrolled at 1400px while the title sat 400px wide holding
   Untitled document. A basis it can shrink from, and no grow, hands the
   leftover space to the toolbar instead. Measured: this is what takes the
   strip from scrolling at 1400 to fitting. */
.editor-topbar input.doc-title { flex: 0 1 210px; }

/* Correction: the 210px basis above was unconditional, which pushed a 390px
   phone from a 76px bar to 111px — the title claimed 210px it did not have.
   Both the title basis and the toolbar basis only make sense on the widths
   that hold one row; below that the title goes back to filling its line.
   The toolbar basis drops to 140 so that at exactly 900px the hypothetical
   sizes still sum under the container and it scrolls instead of wrapping. */
.editor-topbar input.doc-title { flex: 1 1 auto; }
@media (min-width: 900px) {
  .inline-toolbar { flex: 1 1 140px; }
  .editor-topbar input.doc-title { flex: 0 1 210px; }
}
/* flex:1 is flex:1 1 0% — a ZERO basis, which is why the original shrank
   freely on a phone. 'auto' basis let the input claim its intrinsic ~170px
   and wrap the bar again (measured: 390px went 76 -> 111). Restore the zero. */
.editor-topbar input.doc-title { flex: 1 1 0%; }
@media (min-width: 900px) {
  .editor-topbar input.doc-title { flex: 0 1 210px; }
}

/* View controls (outline / focus / shortcuts) sit beside Save and Export
   rather than at the tail of the scrolling formatting strip, where they were
   measured 141px past the visible edge at 1180px. */
.bar-tools { display: flex; align-items: center; gap: 1px; flex: none; }
.bar-tools button { padding: 3px 7px; min-width: 24px; font-size: 13px; font-weight: 700; }
.bar-tools button.active {
  border-color: var(--dlc-accent, #b8911e);
  color: var(--accent-text, #866933);
}

/* ── Authoritative layout for the bar (supersedes the flex values probed
   above; they are left in place because each carries the measurement that
   produced it). The formatting strip and the view controls are wrapped in
   .tool-row so they are ONE flex item: as two items they could wrap onto
   different lines, which put a 390px phone on three rows. */
.tool-row { display: flex; align-items: center; gap: 3px; min-width: 0; flex: 1 1 140px; }
.inline-toolbar { flex: 1 1 0%; }
.bar-tools { flex: none; }
@media (max-width: 899px) {
  .tool-row { flex: 1 0 100%; order: 9; }
  .inline-toolbar { flex: 1 1 0%; order: 0; }
}

/* ── Stacking: the bar must own a layer above the document ──────────────
   .editor-topbar carries backdrop-filter, which creates a STACKING CONTEXT
   even at position:static. Every menu inside it is therefore trapped: a
   z-index of 60 only orders it within the bar, while the bar itself paints at
   an effective z-index of 0 — and #surface is position:relative;z-index:1, so
   the document painted over every dropdown.
   Latent since the toolbar was merged into this bar: the old Export menu had
   the same z-index:10 and got away with it only because the paper started at
   y=145 and the short menu ended right about there. Compaction moved the paper
   up to y=100 and the overlap became real.
   Giving the bar its own positioned layer lifts the whole subtree — menus
   included — above the surface, while staying below the modals (50) and the
   platform chrome bar. */
.editor-topbar { position: relative; z-index: 30; }

/* Focus mode's padding reset lost on SPECIFICITY, not order: chrome.v1.css has
   html.dl-chrome-present body{padding-top:var(--dlc-bar-h)!important} at
   (0,1,2), and body.focus-mode is only (0,1,1). Between two !important author
   declarations specificity decides first, so the bar's 40px survived and the
   paper never moved (measured: paperTop stayed 100 with the chrome hidden).
   Matching the chrome's own selector shape and adding our class outranks it. */
html.dl-chrome-present body.focus-mode,
html body.focus-mode {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/* ── Status line at the foot of the scroll pane ────────────────────────
   Word count + save state were ~320px of the top bar with a real document
   loaded ('404 words - 2291 chars - 2 pages' plus 'Saved on this device'),
   which is what pushed Insert and Find off the end of the toolbar at 1400px.
   Sticky here they stay visible while typing and cost the bar nothing.
   pointer-events:none so the strip can never swallow a click meant for the
   paper underneath it. */
.doc-status {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; justify-content: flex-end; align-items: center; gap: 10px;
  margin: 4px auto 0; max-width: 816px; padding: 5px 2px;
  font-size: 11.5px; line-height: 1.3; pointer-events: none;
  color: var(--dlc-text-dim, #6e6c7e);
}
.doc-status .doc-stats,
.doc-status .save-status {
  opacity: 0.75; min-width: 0; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  background: var(--bg, #f4f2fa); border-radius: 999px; padding: 2px 9px;
}
.doc-status .save-status:empty { display: none; }
@media (max-width: 899px) { .doc-status { font-size: 11px; gap: 6px; } }

/* Outline: JS sets `top` from the editor bar's real bottom edge (see
   positionOutline) — the value here is only the pre-open fallback. */
.outline-panel { top: 80px; }
/* From 1200px there is room to slide the page across so the panel never
   covers the paper: 1200 - 278 - 32 = 890, still wider than the 816px sheet,
   so the page breaks are untouched. Below that it stays a drawer, because
   narrowing the sheet would re-flow every break in the document. */
@media (min-width: 1200px) {
  body.outline-open .editor-page-wrap { padding-left: 278px; }
}

/* The shortcut sheet scrolled internally with no visible scrollbar, so the
   last four entries (undo, redo, Ctrl+/ and Escape) were simply absent —
   inside the one panel whose entire job is discoverability. Two label/key
   pairs per row halves the height and uses width the modal already had.
   Section headings keep spanning the full width via grid-column: 1 / -1. */
@media (min-width: 620px) {
  .modal-wide { width: 640px; }
  .shortcut-grid { grid-template-columns: 1fr auto 1fr auto; gap: 7px 16px; max-height: 66vh; }
  .shortcut-grid .sc-head { grid-column: 1 / -1; }
}
/* On a phone the sheet is two columns and always taller than the modal (23
   rows vs ~658px), and it cuts at a row boundary — which looks like the end
   of the list rather than the middle of it. Fade the bottom edge so it reads
   as scrollable. Only below 620px, where the overflow is unconditional. */
@media (max-width: 619px) {
  .shortcut-grid {
    -webkit-mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent 100%);
    mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent 100%);
  }
}

/* ══════════════════════════════════════════════════════════════════════
   2026-08-10 — TABLES
   ══════════════════════════════════════════════════════════════════════ */

/* The sheet is paper in BOTH themes (chrome's dark heading override had to be
   beaten back off #surface for exactly this reason), so these are document
   ink colours rather than theme tokens — matching the hr/blockquote rules the
   document already ships. Keep in sync with DOC_CSS in editor.js, which is
   what a standalone .html export carries. */
#surface table.doc-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 14px;
  /* margin lives on the bare .doc-table class, NOT here: paginate() moves a
     block with a generated  rule at
     specificity (1,1,0), and anything set on this (1,1,1) selector outranks
     it and silently discards the page break. */
}
#surface table.doc-table td,
#surface table.doc-table th {
  border: 1px solid #d8d4c8;
  padding: 6px 9px;
  vertical-align: top;
  text-align: left;
  min-width: 34px;
  color: #1c1a22;
}
#surface table.doc-table th { background: #f3f0e6; font-weight: 700; }
#surface table.doc-table.doc-table-plain td,
#surface table.doc-table.doc-table-plain th {
  border: none; padding: 4px 8px; background: none;
}
/* Alignment classes already exist for blocks; cells opt into the same ones. */
#surface table.doc-table td.align-center, #surface table.doc-table th.align-center { text-align: center; }
#surface table.doc-table td.align-right,  #surface table.doc-table th.align-right  { text-align: right; }
#surface table.doc-table td.align-justify,#surface table.doc-table th.align-justify{ text-align: justify; }

/* ── Size picker ───────────────────────────────────────────────────────
   The control IS the preview: hover to size, click to insert. Above the
   Insert dropdown (60) because it is opened from inside it. */
.table-picker {
  position: fixed; z-index: 62; padding: 9px;
  background: var(--panel, #ffffff);
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  border-radius: 10px;
  box-shadow: 0 14px 36px -10px rgba(28, 26, 38, 0.36);
}
.tp-grid { display: grid; grid-template-columns: repeat(10, 17px); gap: 3px; }
.tp-cell {
  width: 17px; height: 15px; min-width: 0; padding: 0; cursor: pointer;
  border-radius: 2px; background: transparent;
  border: 1px solid var(--border, rgba(60, 56, 84, 0.28));
}
.tp-cell.on {
  background: var(--dlc-accent, #b8911e);
  border-color: var(--dlc-accent, #b8911e);
}
.tp-label {
  margin-top: 8px; font-size: 11.5px; text-align: center;
  color: var(--text, #3a3848); opacity: 0.72;
}

/* ── Contextual table toolbar ──────────────────────────────────────────
   z-index sits above #surface (1) and the outline panel (45) but below the
   modal backdrop (50), so a dialog is never competing with it. */
.table-tools {
  position: fixed; z-index: 46; display: flex; align-items: center; gap: 2px;
  padding: 4px; border-radius: 10px;
  background: var(--panel, #ffffff);
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  box-shadow: 0 10px 28px -8px rgba(28, 26, 38, 0.34);
}
.table-tools button {
  padding: 4px 9px; min-width: 0; font-size: 12px; font-weight: 600;
  white-space: nowrap; border-radius: 6px;
  border: 1px solid transparent; background: none;
  color: var(--text, #3a3848);
}
.table-tools button:hover { background: var(--card-hover, #f6f4fc); }
.table-tools button.danger { color: var(--danger, #b3324c); }
.table-tools button.danger:hover { background: rgba(179, 50, 76, 0.1); }
.table-tools .sep {
  width: 1px; align-self: stretch; margin: 2px 4px;
  background: var(--border, rgba(60, 56, 84, 0.14));
}
@media (pointer: coarse) { .table-tools button { min-height: 32px; } }
@media (max-width: 620px) { .table-tools button { padding: 4px 7px; font-size: 11.5px; } }

@media print {
  .table-tools, .table-picker { display: none !important; }
  /* Screen pagination cannot split a table — margins do not apply to
     table-row boxes — but PRINT is paginated by the browser, so this is the
     one place row-level splitting is actually achievable. Ask it not to tear
     a row in half, and to repeat the header on every page. */
  #surface table.doc-table tr { break-inside: avoid; page-break-inside: avoid; }
  #surface table.doc-table thead { display: table-header-group; }
}

/* ── Correction: the mobile scroll-fade broke every dropdown below 900px ──
   mask-image makes an element a CONTAINING BLOCK for position:fixed
   descendants (same family as transform / filter / backdrop-filter), so the
   mask added to .inline-toolbar captured and clipped the style, align and
   insert menus at exactly the widths it applied to. Caught by a phone test
   that could not click Insert > Table.
   The fade was cosmetic; a dead dropdown on every phone and tablet is not. A
   horizontal strip is discoverable by swipe on touch and by the wheel handler
   on desktop, so it goes rather than being replaced with another wrapper that
   would risk the same thing. */
@media (max-width: 899px) {
  .inline-toolbar { -webkit-mask-image: none; mask-image: none; }
}

/* ── The table's MARGIN must lose to the pagination engine ──────────────
   paginate() moves a block by generating 
   — specificity (1,1,0). The table rule above is ,
   which is (1,1,1), so it BEAT the generated rule and the push was silently
   discarded: measured, the table stayed at its natural top and hung 6px over
   the bottom edge of page one. Every other block in the document takes its
   margins from a weaker selector, which is why only tables were affected.
   Declaring the margin on the bare class (0,1,0) hands control back. */
.doc-table { margin: 14px 0; }

/* Seven controls plus separators do not fit 374px of usable width, so the
   bar wraps to two rows on a phone rather than running off the screen. */
@media (max-width: 620px) {
  .table-tools { flex-wrap: wrap; max-width: calc(100vw - 16px); }
  .table-tools .sep { display: none; }
}

/* Status pills measured 3.51-3.96:1 across paid themes (audit, 2026-08-11) —
   under the 4.5 needed for text this size. They were dim-token colour at 0.75
   opacity, i.e. dimmed twice. Keep them visually secondary via the token
   alone and drop the extra opacity. */
.doc-status .doc-stats,
.doc-status .save-status { opacity: 1; }
.doc-status { color: var(--text, #3a3848); }

/* ── Right-click menus (ctxmenu.js) ─────────────────────────────────────
   Same visual language as the spreadsheet's original sheet-tab menu, which
   this replaced — token-based, so it tracks light, dark and all 43 paid
   themes. Only left/top come from JS. */
.dlctx {
  position: fixed;
  z-index: 70;
  min-width: 194px;
  max-width: 300px;
  padding: 5px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--panel, #ffffff);
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  border-radius: 10px;
  box-shadow: 0 14px 36px -10px rgba(28, 26, 38, 0.42);
  font-size: 13px;
  /* A long list (the cell menu) must not run off a short window. */
  max-height: min(78vh, 620px);
  overflow-y: auto;
}
.dlctx-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  text-align: left;
  padding: 7px 10px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text, #3a3848);
  font: inherit;
  font-size: 13px;
  white-space: nowrap;
  cursor: pointer;
}
.dlctx-item:hover:not(:disabled),
.dlctx-item:focus-visible,
.dlctx-item:focus {
  background: var(--card-hover, #f6f4fc);
  outline: none;
}
.dlctx-item:disabled { opacity: 0.38; cursor: default; }
.dlctx-item.danger { color: var(--danger, #b3324c); }
.dlctx-item.danger:hover:not(:disabled),
.dlctx-item.danger:focus { background: rgba(179, 50, 76, 0.1); }
.dlctx-item.checked .dlctx-label::before { content: "\2713\00a0"; }
.dlctx-label { overflow: hidden; text-overflow: ellipsis; }
.dlctx-hint {
  opacity: 0.45;
  font-size: 11px;
  flex: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.dlctx-sep {
  height: 1px;
  margin: 4px 6px;
  background: var(--border, rgba(60, 56, 84, 0.14));
}
.dlctx-header {
  padding: 6px 10px 3px;
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.5;
  color: var(--text, #3a3848);
}
@media (pointer: coarse) {
  /* Opened by long-press on a tablet, where every row is a touch target. */
  .dlctx-item { padding: 10px 12px; }
}
@media print { .dlctx { display: none !important; } }

/* ── First-run "how this works" card (tour.js) ──────────────────────────
   Token-based so it tracks light, dark and the paid themes. z-index above the
   context menu (70) and the auth sheet's scrim sits higher still, so a
   sign-in prompt would always win over a tour. */
.dltour-scrim {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
  background: rgba(12, 11, 18, 0.5);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.dltour-card {
  position: relative;
  width: 100%;
  max-width: 440px;
  max-height: calc(100dvh - 36px);
  overflow-y: auto;
  padding: 26px 24px 18px;
  border-radius: 16px;
  background: var(--panel, #ffffff);
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  color: var(--text, #3a3848);
  box-shadow: 0 24px 64px -12px rgba(12, 11, 18, 0.45);
}
.dltour-x {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 9px;
  background: transparent;
  color: inherit;
  font-size: 22px;
  line-height: 1;
  opacity: 0.5;
  cursor: pointer;
}
.dltour-x:hover { opacity: 1; background: var(--card-hover, #f6f4fc); }
.dltour-title {
  margin: 0 0 8px;
  font-size: 19px;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text-bright, #1c1a26);
}
.dltour-text { margin: 0; font-size: 14.5px; line-height: 1.55; }
.dltour-tip {
  margin: 12px 0 0;
  padding: 9px 11px;
  border-radius: 9px;
  font-size: 13px;
  line-height: 1.5;
  background: var(--bg, #f4f2fa);
  border: 1px solid var(--border, rgba(60, 56, 84, 0.12));
}
.dltour-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 20px;
}
.dltour-dots { display: flex; gap: 5px; }
.dltour-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--border, rgba(60, 56, 84, 0.28));
  cursor: pointer;
}
.dltour-dot.on { background: var(--accent, #b8911e); }
.dltour-count { margin-left: 2px; font-size: 11.5px; opacity: 0.5; margin-right: auto; }
.dltour-btn {
  padding: 8px 14px;
  border-radius: 9px;
  border: 1px solid var(--border, rgba(60, 56, 84, 0.14));
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
}
.dltour-btn:hover:not(:disabled) { background: var(--card-hover, #f6f4fc); }
.dltour-btn:disabled { opacity: 0.35; cursor: default; }
.dltour-btn.primary {
  background: var(--accent, #b8911e);
  border-color: var(--accent, #b8911e);
  /* The accent is a FILL here, so the label must be ink chosen against it
     rather than the theme's text colour. */
  color: #1b1704;
  font-weight: 700;
}
.dltour-btn.primary:hover { filter: brightness(1.06); }
@media (pointer: coarse) {
  .dltour-btn { padding: 11px 16px; }
  .dltour-x { width: 40px; height: 40px; }
}
@media print { .dltour-scrim { display: none !important; } }

/* The card focuses its primary button on every step so Enter advances it. That
   made the browser paint its default focus ring — a heavy black halo in light
   mode, white in dark — around a filled accent button, which reads as a border
   rather than as focus. :focus-visible keeps a deliberate ring for keyboard
   users and shows nothing for the programmatic focus a mouse user never asked
   for. */
.dltour-btn:focus { outline: none; }
.dltour-btn:focus-visible {
  outline: 2px solid var(--text, #3a3848);
  outline-offset: 2px;
}
.dltour-x:focus { outline: none; }
.dltour-x:focus-visible { outline: 2px solid var(--text, #3a3848); outline-offset: 1px; }
.dltour-dot:focus { outline: none; }
.dltour-dot:focus-visible { outline: 2px solid var(--text, #3a3848); outline-offset: 2px; }

/* The generic hover rule .dltour-btn:hover:not(:disabled) is specificity
   (0,3,0) and outranked .dltour-btn.primary at (0,2,0), so HOVERING the
   primary button replaced its accent fill with the neutral card-hover colour —
   it lost its fill exactly while the pointer was on it. Measured: rgb(246,244,
   252) instead of rgb(184,145,30). The old .primary:hover rule set only
   `filter`, so it never defended the background. */
.dltour-btn.primary:hover:not(:disabled),
.dltour-btn.primary:focus-visible {
  background: var(--accent, #b8911e);
  filter: brightness(1.06);
}
