/* The colour palette and type stacks live in tokens.css (loaded before this
   file by layout.php). Everything below just consumes those variables. */

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    color: var(--ink);
    background: var(--bg);
    line-height: 1.5;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.muted { color: var(--muted); }
.small { font-size: 0.85rem; }
.error { color: var(--danger); background: #fbeaea; padding: 0.6rem 0.8rem; border-radius: 6px; }

button {
    font: inherit;
    cursor: pointer;
    border: 1px solid var(--line);
    background: var(--panel);
    color: var(--ink);
    padding: 0.4rem 0.8rem;
    border-radius: 6px;
}
button:hover { border-color: var(--muted); }
button.link {
    border: none;
    background: none;
    color: var(--accent);
    padding: 0.2rem 0.4rem;
}
button.danger, .danger { color: var(--danger); }
.icon-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.05rem;
    line-height: 1;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 6px;
}
.icon-btn:hover { border-color: var(--muted); background: var(--bg); }

input[type=text], input[type=email], input[type=password] {
    font: inherit;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--panel);
    color: var(--ink);
}

/* ---- Top bar ---- */
.topbar {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 0.6rem 1rem;
    background: var(--panel);
    border-bottom: 1px solid var(--line);
}
/* The project workspace top bar stacks its title row above the menu bar. */
body.app .topbar { flex-direction: column; align-items: stretch; gap: 0.3rem; }
.topbar-row {
    display: flex;
    align-items: center;
    gap: 0.8rem;
}
.topbar .brand { font-weight: 600; }
/* Editable project title: plain text that sizes to its content and wraps
   long titles, rather than a fixed-width field that truncates. */
.brand-input {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--ink);
    line-height: 1.2;
    padding: 0.1rem 0.4rem;
    border-radius: 6px;
    border: 1px solid transparent;
    overflow-wrap: anywhere;
}
.brand-input[contenteditable]:hover { border-color: var(--line); }
.brand-input:focus { outline: none; border-color: var(--accent); background: var(--bg); }
.topbar.menu-hidden .menubar { display: none; }
.spacer { flex: 1; }
.inline { display: inline; margin: 0; }

/* ---- Auth ---- */
.auth {
    max-width: 360px;
    margin: 8vh auto;
    background: var(--panel);
    padding: 2rem;
    border: 1px solid var(--line);
    border-radius: 10px;
}
.auth h1 { margin-top: 0; }
.auth label { display: block; margin: 1rem 0 0.3rem; }
.auth input { width: 100%; }
.auth button[type=submit] { margin-top: 1.2rem; width: 100%; background: var(--accent); color: #fff; border-color: var(--accent); }

/* ---- Project list ---- */
.container { max-width: 760px; margin: 2rem auto; padding: 0 1rem; }
.new-project { display: flex; gap: 0.5rem; margin: 1rem 0 2rem; }
.new-project input { flex: 1; }
.project-list { list-style: none; padding: 0; }
.project-row {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 0.8rem 1rem;
    margin-bottom: 0.6rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}
.project-row-main { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.project-title { font-size: 1.1rem; font-weight: 600; }
.project-collabs { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shared-head { font-size: 1.1rem; margin-top: 2rem; }
/* Home dashboard cards (your writing + platform) */
.dash { display: flex; gap: 1rem; flex-wrap: wrap; margin: 0.5rem 0 1.8rem; }
.dash-card { flex: 1 1 240px; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 0.8rem 1rem; }
.dash-card h2 { font-size: 1rem; margin: 0 0 0.5rem; }
.dash-card .stats-list { margin: 0; }
.dash-card .stats-list li:last-child { border-bottom: none; }
/* ---- Themed confirm/alert dialog (ui.js) ---- */
.np-dialog-box { max-width: 26rem; }
.np-dialog-msg { margin: 0 0 1.2rem; line-height: 1.55; white-space: pre-wrap; }
.np-dialog-actions { display: flex; justify-content: flex-end; gap: 0.9rem; align-items: center; }
.np-dialog-ok { background: var(--accent); color: #fff; border: none; border-radius: 8px; padding: 0.5rem 1.2rem; font: inherit; font-weight: 600; cursor: pointer; }
.np-dialog-ok:hover { background: var(--accent-deep); }
.np-dialog-ok.danger { background: var(--danger); color: #fff; }
.np-dialog-ok.danger:hover { background: color-mix(in srgb, var(--danger) 85%, #000); }
/* ---- Admin ---- */
.admin-tabs { display: flex; gap: 0.4rem; border-bottom: 1px solid var(--line); margin: 0 0 1.2rem; }
.admin-tabs a { padding: 0.4rem 0.8rem; color: var(--muted); border-bottom: 2px solid transparent; }
.admin-tabs a:hover { text-decoration: none; color: var(--ink); }
.admin-tabs a.active { color: var(--ink); border-bottom-color: var(--accent); font-weight: 600; }
.tab-badge { display: inline-block; min-width: 1.1rem; padding: 0 0.35rem; margin-left: 0.15rem; font-size: 0.7rem; font-weight: 700; line-height: 1.2rem; text-align: center; color: #fff; background: var(--danger); border-radius: 999px; vertical-align: middle; }

/* Mobile admin nav: a single grouped "current section" disclosure that replaces
   the pill row on narrow screens (desktop keeps .admin-tabs). No JS — <details>. */
.admin-nav-m { display: none; }
.admin-nav-m > summary {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.6rem 0.8rem;
    cursor: pointer;
    font-weight: 600;
    color: var(--ink);
    list-style: none;                 /* hide the default disclosure triangle */
}
.admin-nav-m > summary::-webkit-details-marker { display: none; }
.admin-nav-m .anm-pre { color: var(--muted); font-weight: 400; }
.admin-nav-m .anm-caret { margin-left: auto; color: var(--muted); transition: transform 0.15s ease; }
.admin-nav-m[open] .anm-caret { transform: rotate(180deg); }
.admin-nav-m .anm-panel { border-top: 1px solid var(--line); padding: 0.3rem; }
.admin-nav-m .anm-group {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-weight: 700;
    color: var(--muted);
    background: var(--bg);
    padding: 0.35rem 0.6rem;
    margin: 0.3rem 0 0.15rem;
    border-radius: 4px;
    border-bottom: 1px solid var(--line);
}
/* No gap above the very first subhead (it sits right under the summary rule). */
.admin-nav-m .anm-group:first-child { margin-top: 0; }
.admin-nav-m .anm-panel a {
    display: block;
    padding: 0.65rem 0.7rem;
    border-radius: 6px;
    color: var(--ink);
}
.admin-nav-m .anm-panel a:hover { text-decoration: none; }
.admin-nav-m .anm-panel a.active { background: var(--bg); font-weight: 600; }
.admin-nav-m .anm-panel a.active::before { content: "✓ "; color: var(--accent); font-weight: 700; }
@media (max-width: 768px) {
    .admin-tabs { display: none; }
    .admin-nav-m {
        display: block;
        margin: 0 0 1rem;
        border: 1px solid var(--line);
        border-radius: 8px;
        background: var(--panel);
    }
}
.table-wrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.admin-table th, .admin-table td { text-align: left; padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--line); vertical-align: top; }
.admin-table th { color: var(--muted); font-weight: 600; white-space: nowrap; }
.admin-table td.num, .admin-table th:nth-child(n+3) { text-align: right; white-space: nowrap; }
.admin-table .tag { font-size: 0.65rem; background: var(--accent); color: #fff; padding: 1px 6px; border-radius: 8px; vertical-align: middle; }
.pager { display: flex; align-items: center; gap: 1rem; justify-content: center; margin: 1rem 0; }
.admin-form { max-width: 42rem; }
.admin-form .field { display: block; margin-bottom: 0.8rem; }
.admin-form .field > span { display: block; margin-bottom: 0.25rem; font-size: 0.85rem; color: var(--muted); }
.admin-form input[type="text"],
.admin-form textarea {
    display: block; width: 100%; box-sizing: border-box;
    padding: 0.5rem 0.6rem; font: inherit;
    border: 1px solid var(--line); border-radius: 6px;
    background: var(--panel); color: var(--ink);
}
.admin-form textarea { resize: vertical; min-height: 8rem; line-height: 1.5; }

/* ---- Offline recovery box on the login page ---- */
.offline-recovery { border: 1px solid var(--line); border-radius: 8px; padding: 0.8rem 1rem; margin-bottom: 1.2rem; background: var(--panel); }
.offline-recovery p { margin: 0.3rem 0; }
.offline-recovery #or-resume { margin: 0.6rem 0; }
.offline-recovery .or-list { list-style: none; padding: 0; margin: 0.4rem 0 0; display: flex; flex-direction: column; gap: 0.3rem; }

/* ---- Admin: compact mode ----
   Admin pages are a working tool, not marketing, so they trade the site's airy
   spacing for density. Scoped to body.admin-compact (set in layout.php), so the
   rest of the site is untouched. Everything here just tightens space / sizes. */
body.admin-compact { font-size: 0.9rem; }
body.admin-compact .container { max-width: 960px; margin: 0.9rem auto 2rem; }
body.admin-compact h1 { font-size: 1.25rem; margin: 0 0 0.3rem; }
body.admin-compact h2 { font-size: 1.02rem; margin: 1rem 0 0.35rem; }
body.admin-compact h3 { font-size: 0.9rem; margin: 0.8rem 0 0.3rem; }
body.admin-compact p { margin: 0.3rem 0; }
body.admin-compact p.muted, body.admin-compact .muted.small { font-size: 0.8rem; line-height: 1.4; }
body.admin-compact .admin-tabs { margin-bottom: 0.8rem; }
body.admin-compact .admin-tabs a { padding: 0.3rem 0.6rem; }
body.admin-compact .flash { padding: 0.4rem 0.7rem; margin: 0.5rem 0; }
body.admin-compact form { margin-bottom: 0.5rem; }

/* Stats + feature/check lists */
body.admin-compact .stats-list { margin-bottom: 0.6rem; }
body.admin-compact .stats-list li { padding: 0.28rem 0; }
body.admin-compact .goal-rows { gap: 0.3rem; margin: 0.3rem 0 0.6rem; }

/* Form controls: smaller padding, and let inputs sit inline rather than block */
body.admin-compact input[type=text], body.admin-compact input[type=email],
body.admin-compact input[type=password], body.admin-compact .admin-form input[type="text"],
body.admin-compact .admin-form textarea, body.admin-compact button {
    padding: 0.3rem 0.55rem;
}
body.admin-compact .admin-form .field { margin-bottom: 0.5rem; }
body.admin-compact .admin-form .field > span { margin-bottom: 0.15rem; font-size: 0.8rem; }
body.admin-compact .admin-form textarea { min-height: 5.5rem; line-height: 1.45; }

/* Users table: denser rows and a slightly smaller face */
body.admin-compact .admin-table { font-size: 0.8rem; }
body.admin-compact .admin-table th, body.admin-compact .admin-table td { padding: 0.3rem 0.45rem; }
body.admin-compact .pager { margin: 0.6rem 0; gap: 0.7rem; }

/* Maintenance page */
body.admin-compact .button-link { padding: 0.3rem 0.6rem; }

/* ---- Workspace ---- */
/* Workspace page fills the viewport exactly; the editor scrolls internally so
   the footer (word-count link) stays put regardless of top-bar height. */
/* 100dvh tracks the *visible* viewport as Safari's toolbar shows/hides (100vh
   includes the area behind it, which causes the footer to be over/under-lapped). */
body.app { height: 100vh; height: 100dvh; overflow: hidden; display: flex; flex-direction: column; }
body.app .topbar { flex: 0 0 auto; }
.workspace { display: flex; flex: 1; min-height: 0; position: relative; }
.binder {
    width: 280px;
    flex-shrink: 0;
    background: var(--panel);
    border-right: 1px solid var(--line);
    overflow-y: auto;
    padding: 0.5rem;
    font-size: 0.8rem;            /* binder uses a smaller font than the editor */
}
.binder-section { margin-bottom: 0.3rem; }
.section-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.2rem 0.2rem 0.3rem;
}
.section-title {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.72rem;
    color: var(--muted);
}
.section-title .muted { font-weight: 400; text-transform: none; letter-spacing: 0; }
/* Clickable section title (opens the top-level corkboard, Scrivener-style). */
.section-title-btn {
    border: 0;
    background: transparent;
    cursor: pointer;
    font-family: inherit;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.05rem 0.15rem;
    border-radius: 4px;
}
.section-title-btn:hover { color: var(--ink); background: var(--hover, rgba(0, 0, 0, 0.05)); }
.section-cork-ic { font-size: 0.85rem; opacity: 0.7; }
.section-actions { margin-left: auto; display: flex; gap: 0.3rem; }
.section-actions button { font-size: 0.72rem; padding: 0.15rem 0.4rem; }
.binder-divider { border: none; border-top: 1px solid var(--line); margin: 0.5rem 0; }

.tree { list-style: none; margin: 0; padding-left: 0.8rem; }
.tree[data-section] { padding-left: 0; }
.tree-item {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    border-radius: 5px;
    padding: 0.12rem 0.25rem;
    position: relative;        /* anchor for the absolute lock indicator */
    /* Long-press to drag on touch: don't select text or pop the iOS callout. */
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}
.tree-item:hover { background: var(--bg); }
.tree-item.open { background: #e6f0ea; }
.tree-item.selected { outline: 1px dashed var(--accent); }
.tree-toggle {
    width: 1.5rem;
    flex-shrink: 0;
    cursor: pointer;
    color: var(--muted);
    font-family: monospace;
    font-size: 0.7rem;
    text-align: center;
    user-select: none;
}
.tree-label { flex: 1; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tree-actions { opacity: 0; display: flex; }
.tree-item:hover .tree-actions { opacity: 1; }
.tree-actions .ad { font-weight: 700; }
/* Mobile-only overflow button; hidden on desktop (hover actions used there). */
.tree-more { display: none; }

/* A row drawn ahead of the server: the name and type are known, the id isn't
   yet. Dimmed and inert (no hover actions, no drag), with a small spinner where
   the status dot would sit. */
/* Inert: no click target, and invisible to the drag-and-drop hit test, so a
   drag in progress treats it as empty space rather than an undroppable row. */
.tree-item.pending { opacity: 0.65; pointer-events: none; }
.tree-spinner {
    flex: none;
    width: 11px; height: 11px;
    margin-left: 0.35rem;
    border: 2px solid var(--line);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: np-spin 0.7s linear infinite;
}

/* Drag & drop (drop-indicator model) */
.tree-item[draggable="true"] .tree-label { cursor: grab; }
/* The dragged row just dims; nothing is moved until you drop. */
.tree-item.dragging { opacity: 0.4; }
/* A thin line shows where it will land (inset shadow → no layout shift). */
.tree-item.drop-before { box-shadow: inset 0 2px 0 0 var(--accent); }
.tree-item.drop-after { box-shadow: inset 0 -2px 0 0 var(--accent); }
/* Dropping into a folder / into an (empty) section highlights the target. */
.tree-item.drop-inside { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 5px; }
.tree.drop-root { outline: 2px dashed var(--accent); outline-offset: -2px; border-radius: 6px; }
/* Empty sections keep a small height so they're always a valid drop target
   (no reflow-on-drag needed — that used to abort the drag). */
.tree:empty { min-height: 1.4rem; }

/* Collaborator read-only notice while the owner has the project offline. */
.offline-locked-banner {
    background: #eef2ff;
    color: #3730a3;
    border-bottom: 1px solid #c7d2fe;
    padding: 0.55rem 1.2rem;
    font-size: 0.9rem;
    text-align: center;
}
body.dark .offline-locked-banner { background: #23264a; color: #c3caf5; border-bottom-color: #3a3f6b; }

/* "Keep available offline" control on the project list */
.row-offline { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.7rem; margin-top: 0.3rem; }
.offline-toggle { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.85rem; color: var(--muted); cursor: pointer; }
.offline-status { color: var(--muted); }

/* Offline mode: gray out features that need the server (compile/export/import,
   sharing, version history, word-count stats). They re-enable when back online. */
body.offline-mode .online-only { opacity: 0.4; pointer-events: none; cursor: default; }

/* Reorder handle — the reliable touch drag target. touch-action:none means a
   touch starting here always drags and never scrolls or taps. */
.tree-grip {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 30px;
    align-self: stretch;
    padding: 2px 4px;
    color: var(--muted);
    cursor: grab;
    opacity: 0.5;
    touch-action: none;
}
.tree-grip svg { pointer-events: none; }   /* the span is always the touch target */
.tree-grip:hover { opacity: 0.9; }
.tree-grip:active { cursor: grabbing; }
/* With a mouse the whole row drags, so the handle is just clutter — touch
   devices keep it as their reliable drag target. */
@media (hover: hover) and (pointer: fine) {
    .tree-grip { display: none; }
}

/* The "+" row action: a tiny fixed-position menu (new chapter / new scene). */
.tree-add-menu {
    position: fixed;
    z-index: 60;
    min-width: 10rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 6px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
    padding: 0.25rem;
}

/* ---- Mobile row action sheet (the "⋯" menu) ---- */
.row-sheet-wrap { position: fixed; inset: 0; z-index: 70; }
.sheet-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.4); }
.tree-add-menu.row-sheet {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    min-width: 0;
    border-radius: 14px 14px 0 0;
    padding: 0.4rem 0.5rem calc(0.5rem + env(safe-area-inset-bottom));
    box-shadow: 0 -6px 22px rgba(0, 0, 0, 0.28);
}
.row-sheet .menu-item { padding: 0.9rem 0.8rem; font-size: 1.05rem; border-radius: 8px; }
.row-sheet .menu-item.danger { color: var(--danger); }

/* ---- Binder search ---- */
.binder-search { padding: 0.5rem; }
#binder-search,
.replace-bar input {
    width: 100%;
    padding: 0.4rem 0.55rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--panel);
    color: var(--ink);
    font: inherit;
}
.search-case { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.5rem; font-size: 0.8rem; color: var(--muted); cursor: pointer; }
.search-case input { width: auto; flex: none; margin: 0; }
.replace-bar { display: flex; gap: 0.4rem; align-items: center; margin-top: 0.4rem; }
/* The display:flex above otherwise overrides the hidden attribute. */
.search-case[hidden], .replace-bar[hidden] { display: none; }
.replace-bar input { flex: 1; }
.replace-bar #replace-btn { flex: none; white-space: nowrap; }
.search-results { list-style: none; margin: 0; padding: 0; }
.search-result { display: flex; gap: 0.45rem; align-items: flex-start; padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--line); }
.search-result .sr-check { margin-top: 0.2rem; flex: none; }
.search-result-body { flex: 1; min-width: 0; cursor: pointer; }
.search-result:hover { background: var(--bg); }
.search-result-title { font-size: 0.88rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search-result-snippet { font-size: 0.8rem; color: var(--muted); margin-top: 0.1rem; line-height: 1.35; }
.search-result-snippet mark { background: #ffe58a; color: inherit; padding: 0 1px; border-radius: 2px; }
.search-msg { padding: 0.5rem 0.6rem; }
.binder.searching .binder-section,
.binder.searching .binder-divider { display: none; }
body.dark .search-result-snippet mark { background: #6b5d2a; color: #f0e6c0; }

/* ---- Dot+name picker (custom dropdown for label/status in the item dialog) ---- */
.cs { position: relative; }
.cs-button, .cs-opt {
    display: flex; align-items: center; gap: 0.5rem;
    width: 100%; text-align: left; font: inherit; color: var(--ink); cursor: pointer;
}
.cs-button {
    padding: 0.4rem 0.6rem; border: 1px solid var(--line); border-radius: 6px; background: var(--panel);
}
.cs-caret { margin-left: auto; color: var(--muted); font-size: 0.8em; }
.cs-menu {
    position: absolute; left: 0; right: 0; top: 100%; margin-top: 3px; z-index: 50;
    background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18); max-height: 240px; overflow: auto; padding: 2px;
}
.cs-menu[hidden] { display: none; }
.cs-opt { padding: 0.4rem 0.55rem; border: 0; background: transparent; border-radius: 4px; }
.cs-opt:hover { background: var(--bg); }
.cs-dot { width: 11px; height: 11px; border-radius: 50%; flex: none; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15); }
.cs-dot-none { background: transparent; box-shadow: inset 0 0 0 1px var(--line); }
.cs-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- Labels & Status ---- */
/* Label dot sits in the toggle gutter, just left of the name — absolutely
   positioned so it never shifts the title (same trick as the lock icon). */
.tree-dot { position: absolute; left: 1rem; top: 50%; transform: translateY(-50%); width: 9px; height: 9px; border-radius: 50%; }
/* Sits in the (empty) toggle gutter so it never shifts the scene title. */
.tree-lock { position: absolute; left: 0.3rem; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; color: var(--accent); cursor: default; }
.scriv-lock-note { padding: 0.15rem 1.2rem 0.3rem; color: var(--accent); }
/* Status shown as a small dot after the name (hover to see the name) to save
   room for the title; full name lives in the title tooltip. */
.tree-status { flex: none; width: 9px; height: 9px; border-radius: 50%; margin-left: 0.35rem; cursor: default; }
.cork-card.has-label { border-left-width: 4px; border-left-style: solid; }
.cork-card-status {
    float: right; font-size: 0.62rem; color: #fff; padding: 2px 6px; border-radius: 8px;
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
}
.tax-list { display: flex; flex-direction: column; gap: 0.4rem; margin: 0.3rem 0 0.6rem; }
.tax-row { display: flex; align-items: center; gap: 0.5rem; }
.tax-row input[type="color"] { width: 2rem; height: 1.7rem; padding: 0; border: 1px solid var(--line); border-radius: 5px; background: none; }
.tax-row .tax-name { flex: 1; min-width: 0; font: inherit; padding: 0.3rem 0.45rem; border: 1px solid var(--line); border-radius: 5px; background: var(--panel); color: var(--ink); }
/* Binder Trash section: restore (↩) and delete-forever (🗑) always visible. */
.binder-trash .section-title { color: var(--muted); }
.trash-item .tree-actions { opacity: 1; display: flex; gap: 0.15rem; }
.trash-item .tree-actions .link { font-size: 0.9rem; padding: 0 0.25rem; }
.trash-empty { padding: 0.2rem 0.6rem; }

.editor-pane {
    flex: 1;
    display: flex;
    flex-direction: column;
    position: relative;
    background: var(--panel);
}
.doc-title-row { display: flex; align-items: center; }
.doc-title {
    flex: 1;
    min-width: 0;
    border: none !important;
    background: transparent;       /* was defaulting to white in dark mode */
    color: var(--ink);
    font-size: 1.2rem;
    font-weight: 400;
    padding: 1rem 1.2rem 0.5rem;
    border-radius: 0;
}
.doc-title:disabled { color: var(--muted); }
/* Hamburger to the left of the scene name: hide/show the editing toolbar. */
.doc-menu-btn { flex: none; margin: 0.5rem 0.2rem 0 1rem; }
.editor-pane.toolbar-hidden #toolbar { display: none; }
/* Word-count / daily-goal dialog */
.stats-list { list-style: none; padding: 0; margin: 0 0 1rem; }
.stats-list li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.45rem 0; border-bottom: 1px solid var(--line); }
.progress { height: 10px; background: var(--bg); border: 1px solid var(--line); border-radius: 6px; overflow: hidden; margin: 0.3rem 0; }
.progress-bar { height: 100%; width: 0; background: var(--accent); transition: width 0.25s ease; }
.goal-rows { display: flex; flex-direction: column; gap: 0.45rem; margin: 0.4rem 0 0.9rem; }
.site-footer { text-align: center; color: var(--muted); font-size: 0.85rem; padding: 2.2rem 1rem; border-top: 1px solid var(--line); margin-top: 2.5rem; }
.site-footer a { color: inherit; text-decoration: underline; }
.site-footer a:hover { color: var(--ink); }
.site-footer .foot-legal { margin-top: 0.45rem; }
.goal-row { display: flex; align-items: center; gap: 0.5rem; }
/* Inside a dialog, `.modal-body label` (0,1,1) out-specifies `.goal-row` (0,1,0)
   and forces display:block — which drops the row out of flex, makes the label a
   plain inline span, and silently discards its width, so the number fields ended
   up wherever the text happened to stop. Re-assert it at higher specificity, the
   same way `label.check` already does two rules down. */
.modal-body label.goal-row { display: flex; align-items: center; gap: 0.5rem; margin: 0; }
.goal-row span { width: 4.5rem; }
.goal-row input[type="number"] { width: 7rem; }
.goal-prog { margin: 0.5rem 0; }
.goal-prog .prog-label { margin-bottom: 0.15rem; }
#editor { flex: 1; overflow-y: auto; border: none; }
/* Scene switch: a spinner over the (emptied) editor while the next scene loads. */
#editor.scene-loading { position: relative; }
#editor.scene-loading::after {
    content: "";
    position: absolute;
    top: 3rem; left: 50%; margin-left: -14px;
    width: 28px; height: 28px;
    border: 3px solid rgba(128, 128, 128, 0.25);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: np-spin 0.7s linear infinite;
    pointer-events: none;
    z-index: 5;
}
@keyframes np-spin { to { transform: rotate(360deg); } }

/* ---- "Being created" card ----
   Sits over the main pane (right of the binder) while the server confirms a new
   scene / chapter the binder is already showing. Transparent and click-through
   so the new row — and everything else — stays visible and usable. */
.creating-overlay {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 280px;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    z-index: 20;
}
.workspace.binder-hidden .creating-overlay { left: 0; }
.creating-card {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.7rem 1.1rem;
    background: var(--panel);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.18);
    font-size: 0.95rem;
    max-width: min(90%, 26rem);
}
.creating-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.creating-spinner {
    flex: none;
    width: 18px; height: 18px;
    border: 2px solid rgba(128, 128, 128, 0.25);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: np-spin 0.7s linear infinite;
}
/* The teaching / "nothing open" card would sit under the creating card and read
   as a contradiction ("start a scene" while one is being made). */
body.creating-item .empty-state { display: none; }
/* Keep clicks out of the editor for the moment it's between scenes — anything
   typed there would be wiped when the new scene loads into it. */
body.creating-item #editor { pointer-events: none; }
@media (max-width: 768px) { .creating-overlay { left: 0; } }
.ql-toolbar.ql-snow { border-left: none; border-right: none; }
/* ID-scoped to beat Quill's `.ql-snow.ql-toolbar button { width:28px }`. */
#toolbar .text-btn {
    width: auto;
    height: auto;
    white-space: nowrap;
    padding: 0.15rem 0.4rem;
    font-weight: 700;
    border: 1px solid var(--line);
    border-radius: 4px;
    background: var(--panel);
    color: var(--ink);
    cursor: pointer;
}
.script-dd { position: relative; }
.dd-menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    margin-top: 2px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 6px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
    min-width: 170px;
    padding: 0.25rem;
    color: var(--ink);
}
.dd-menu[hidden] { display: none; }
/* ID-scoped to override Quill's `.ql-toolbar button { float:left; width:28px }`. */
#script-menu button {
    display: block;
    float: none;
    width: 100%;
    height: auto;
    text-align: left;
    white-space: nowrap;
    border: none;
    background: none;
    padding: 0.4rem 0.55rem;
    border-radius: 4px;
    cursor: pointer;
    font: inherit;
}
#script-menu button:hover { background: var(--bg); }
.ql-container.ql-snow { border: none; font-size: 1.05rem; }
/* position:relative anchors Quill's placeholder (::before, position:absolute
   left:15px) to the centered text column — without it the placeholder resolves
   to the full-width container and the caret lands mid-"Start" in wide view. */
.ql-editor { max-width: 46rem; margin: 0 auto; min-height: 100%; position: relative; }
/* extra right padding keeps footer buttons clear of the fixed theme toggle */
.editor-footer { padding: 0.4rem 3.75rem 0.4rem 1.2rem; border-top: 1px solid var(--line); display: flex; align-items: center; gap: 0.6rem; }

.empty-state {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--muted);
    background: var(--panel);
    text-align: center;
    padding: 2rem;
}

/* ---- Show/hide binder ---- */
/* Desktop: shown by default; collapsing hides it inline. */
.workspace.binder-hidden .binder { display: none; }

/* Narrow screens: binder is hidden by default and opens as an overlay. */
@media (max-width: 768px) {
    /* Clear the actual notch/status bar (0 on phones without one), not a guess.
       The workspace flexes to fill the rest so the footer stays put. */
    .topbar { padding-top: calc(0.6rem + env(safe-area-inset-top)); }
    /* Keep the bottom row above the home-indicator. */
    .editor-footer { padding-bottom: calc(0.4rem + env(safe-area-inset-bottom)); }

    .binder {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 30;
        width: 92vw;
        max-width: 460px;
        display: none;
        box-shadow: 2px 0 14px rgba(0, 0, 0, 0.28);
        font-size: 1rem;          /* larger, more tappable binder on phones */
    }
    /* Roomier rows + more breathing room between items on touch. */
    .workspace.binder-open .binder .tree-item {
        padding-top: 0.5rem;
        padding-bottom: 0.5rem;
        margin-bottom: 0.1rem;
    }
    .workspace.binder-open .binder .tree { padding-left: 1rem; }
    .workspace.binder-open .binder .binder-section { margin-bottom: 0.6rem; }
    .workspace.binder-open .binder { display: block; }

    /* Touch has no hover: replace the three inline buttons with one "⋯" that
       opens the bottom action sheet. Trash rows keep their own visible actions. */
    .tree-item:not(.trash-item) .tree-actions { display: none; }
    .tree-item:not(.trash-item) .tree-more {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 2rem;
        height: 2rem;
        flex-shrink: 0;
        font-size: 1.25rem;
        line-height: 1;
    }
}

/* ---- Theme toggle button (global, fixed) ---- */
.focus-toggle,
.theme-fab {
    position: fixed;
    right: 14px;
    bottom: 14px;
    z-index: 60;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: var(--panel);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    color: var(--ink);
}

/* ---- Distraction-free mode: hide all chrome but the editor + the toggle ---- */
body.focus-mode .topbar,
body.focus-mode .binder,
body.focus-mode #toolbar,
body.focus-mode .editor-footer,
body.focus-mode .doc-title-row,
body.focus-mode #lock-banner { display: none !important; }
body.focus-mode .ql-editor { max-width: 42rem; }
/* The chrome is hidden, so give the text some breathing room from the top. */
body.focus-mode #editor { padding-top: 36px; }

/* ---- Dark mode ---- (palette vars live in tokens.css; these are component tweaks) */
body.dark .project-row,
body.dark .auth { background: var(--panel); }
body.dark .tree-item.open { background: #34423a; }

/* Quill adapts to dark: recolor toolbar icons, pickers, and content chrome. */
body.dark .ql-snow .ql-stroke { stroke: var(--ink); }
body.dark .ql-snow .ql-fill { fill: var(--ink); }
body.dark .ql-snow .ql-picker { color: var(--ink); }
body.dark .ql-snow .ql-picker-options {
    background: var(--panel);
    border-color: var(--line);
}
body.dark .ql-editor.ql-blank::before { color: var(--muted); }
body.dark .ql-snow.ql-toolbar { border-color: var(--line); }

/* ---- Corkboard ---- */
.corkboard { display: none; flex: 1; overflow-y: auto; padding: 1.2rem; background: var(--bg); }
.workspace.corkboard-mode .editor-pane { display: none; }
.workspace.corkboard-mode .corkboard { display: block; }
.cork-head { margin-bottom: 1rem; display: flex; align-items: center; gap: 0.8rem; }
.cork-head .spacer { flex: 1; }

/* ---- Scrivenings (stacked chapter editors) ---- */
.scrivenings { display: none; flex: 1; min-height: 0; flex-direction: column; background: var(--panel); }
.workspace.scriv-mode .editor-pane,
.workspace.scriv-mode .corkboard { display: none; }
.workspace.scriv-mode .scrivenings { display: flex; }
.scriv-head { display: flex; align-items: center; gap: 0.6rem; padding: 0.3rem 1.2rem; border-bottom: 1px solid var(--line); }
.scriv-head h2 { margin: 0; font-size: 0.9rem; font-weight: 600; color: var(--muted); }
.scriv-head .spacer { flex: 1; }
.scriv-body { flex: 1; overflow-y: auto; padding: 0.4rem 0 1.4rem; }
.scriv-scene { max-width: 46rem; margin: 0 auto; }
/* Seamless: scenes flow with just a little breathing room, no boxy rule. */
.scriv-scene + .scriv-scene { margin-top: 0.9rem; }
/* Titles hidden unless toggled on. */
.scriv-scene-title { display: none; font-size: 0.72rem; font-weight: 600; color: var(--muted); padding: 0 1.2rem 0.25rem; text-transform: uppercase; letter-spacing: 0.04em; }
.scriv-body.show-titles .scriv-scene-title { display: block; }
.scriv-ed .ql-container.ql-snow { border: none; font-size: 1rem; }
.scriv-ed .ql-editor { padding: 0.3rem 1.2rem; }
/* One shared formatting toolbar, fixed above the scrolling scenes. Uses Quill's
   own .ql-toolbar.ql-snow styling + icons so it matches the single-scene editor. */
.scriv-toolbar { border-top: none; padding-left: 1.2rem; }
.scriv-toolbar[hidden] { display: none; }
.scriv-toolbar .st-select {
    font: inherit; font-size: 0.85rem; padding: 0.12rem 0.3rem; vertical-align: middle;
    border: 1px solid var(--line); border-radius: 4px; background: var(--panel); color: var(--ink);
}
/* Obvious on/off toggle in the header. */
.toggle-btn { font: inherit; font-size: 0.8rem; padding: 0.25rem 0.6rem; border: 1px solid var(--line); border-radius: 6px; background: var(--bg); color: var(--ink); cursor: pointer; margin-right: 0.6rem; }
.toggle-btn.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.cork-head h2 { margin: 0 0 0.2rem; }
.cork-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 1rem;
}
.cork-card {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 0.8rem;
    min-height: 150px;
    max-height: 260px;
    overflow: hidden;
    cursor: pointer;
    display: flex;
    flex-direction: column;
}
.cork-card:hover { border-color: var(--muted); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14); }
.cork-card-title {
    font-weight: 600;
    padding-bottom: 0.4rem;
    margin-bottom: 0.4rem;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cork-card-body { font-size: 0.85rem; overflow: hidden; flex: 1; }
.cork-card-body > :first-child { margin-top: 0; }

/* ---- Modal (note editor) ---- */
.modal {
    position: fixed;
    inset: 0;
    z-index: 100;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}
.modal[hidden] { display: none; }
.modal-box {
    background: var(--panel);
    color: var(--ink);
    width: min(640px, 94vw);
    max-height: 86vh;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--line);
    border-radius: 10px;
    overflow: hidden;
}
.modal-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.8rem;
    border-bottom: 1px solid var(--line);
    font-weight: 600;
}
#note-editor { overflow-y: auto; min-height: 220px; max-height: 55vh; }

/* ---- Share modal ---- */
.modal-body { padding: 0.8rem 1rem; overflow-y: auto; }
.modal-body h3 { margin: 1rem 0 0.4rem; font-size: 0.95rem; }
.modal-body h3:first-child { margin-top: 0; }

/* Export / Import chooser rows: a stacked title + one-line description each. */
.chooser { display: flex; flex-direction: column; gap: 0.5rem; }
.choice {
    display: flex; flex-direction: column; align-items: flex-start; gap: 0.15rem;
    width: 100%; text-align: left; padding: 0.7rem 0.9rem;
    border: 1px solid var(--line); border-radius: 8px;
    background: var(--panel); color: var(--ink); cursor: pointer;
    font: inherit; text-decoration: none;
}
.choice:hover { border-color: var(--accent); text-decoration: none; }
.choice-title { font-weight: 600; }
.choice-desc { font-size: 0.82rem; color: var(--muted); line-height: 1.35; }
.member-list { list-style: none; margin: 0 0 0.5rem; padding: 0; }
.member-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--line);
}
.member-ctrl { display: flex; gap: 0.5rem; align-items: center; }
.pending-row { padding: 0.4rem 0; border-bottom: 1px solid var(--line); }
.pending-top { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.invite-link { width: 100%; margin-top: 0.3rem; font: inherit; font-size: 0.8rem; padding: 0.3rem 0.45rem; border: 1px solid var(--line); border-radius: 5px; background: var(--bg); color: var(--ink); }
.share-row { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.share-row select, .share-row input {
    font: inherit;
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--panel);
    color: var(--ink);
}
.share-row input[type=email] { flex: 1; min-width: 180px; }
#invite-result input { width: 100%; margin-top: 0.3rem; }

/* ---- Version history modal ---- */
.modal-wide { width: min(900px, 95vw); }
.history-body { display: flex; flex: 1; min-height: 0; overflow: hidden; }
.version-list {
    list-style: none;
    margin: 0;
    padding: 0.4rem;
    width: 250px;
    flex-shrink: 0;
    overflow-y: auto;
    border-right: 1px solid var(--line);
}
.version-list li { padding: 0.4rem 0.5rem; border-radius: 6px; cursor: pointer; line-height: 1.3; }
.version-list li:hover { background: var(--bg); }
.version-list li.sel { background: var(--bg); outline: 1px solid var(--accent); }
.version-pane { flex: 1; display: flex; flex-direction: column; padding: 0.6rem 0.8rem; overflow: hidden; min-width: 0; }
.version-preview {
    flex: 1;
    overflow-y: auto;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--bg);
    margin: 0.4rem 0 0.6rem;
}
.version-preview .ql-editor { min-height: 0; }
#restore-btn { align-self: flex-start; }
.history-back { display: none; }   /* desktop shows both panels; the mobile master-detail (mobile.css) turns this on */

/* ---- Editing lock banner ---- */
.lock-banner {
    background: #fdf3d8;
    color: #6b5800;
    border-bottom: 1px solid var(--line);
    padding: 0.4rem 1.2rem;
    font-size: 0.9rem;
}
.lock-banner[hidden] { display: none; }
.lock-banner button { margin-left: 0.3rem; }
body.dark .lock-banner { background: #3a3526; color: #d9c98c; }

/* ---- Offline / unsaved-work indicators ---- */
/* Fixed, high above everything so an outage is impossible to miss in any mode. */
.net-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 200;
    background: #b45309;
    color: #fff;
    text-align: center;
    padding: calc(0.5rem + env(safe-area-inset-top)) 1rem 0.5rem;
    font-size: 0.9rem;
    line-height: 1.35;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.28);
}
.net-banner[hidden] { display: none; }

/* Per-scene "we found an unsynced backup" prompt, inline above the editor. */
.draft-banner {
    background: #fef3c7;
    color: #92400e;
    border-bottom: 1px solid #f59e0b;
    padding: 0.45rem 1.2rem;
    font-size: 0.9rem;
    display: flex;
    gap: 0.75rem;
    align-items: center;
    flex-wrap: wrap;
}
.draft-banner[hidden] { display: none; }
.draft-banner .link { color: #92400e; font-weight: 600; }
body.dark .draft-banner { background: #3a3018; color: #f0d59a; border-bottom-color: #6b5518; }
body.dark .draft-banner .link { color: #f0d59a; }

/* Concurrency conflict: same layout as the draft banner, but a distinct
   (attention) color so it reads as "decision needed," not "info." */
.conflict-banner { background: #fde2e1; color: #9b1c1c; border-bottom-color: #ef4444; }
.conflict-banner .link { color: #9b1c1c; }
body.dark .conflict-banner { background: #3a1d1d; color: #f6b8b4; border-bottom-color: #7a2020; }
body.dark .conflict-banner .link { color: #f6b8b4; }

/* ---- Import review ---- */
.flash {
    background: #e6f0ea;
    color: var(--ink);
    border-bottom: 1px solid var(--accent);
    padding: 0.5rem 1rem;
    font-size: 0.9rem;
    transition: opacity 0.6s ease;
}
.flash.fade-out { opacity: 0; }
body.dark .flash { background: #2c3a32; }
.import-card {
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 0.8rem 1rem;
    margin-bottom: 0.8rem;
    background: var(--panel);
}
.import-head { display: block; cursor: pointer; }
.import-row { padding: 0.4rem 0.2rem; }
.import-row.warn { color: #8a5a00; }
body.dark .import-row.warn { color: #d9b066; }
.diff {
    white-space: pre-wrap;
    margin-top: 0.5rem;
    padding: 0.6rem 0.8rem;
    border-radius: 6px;
    background: var(--bg);
    line-height: 1.6;
}
.diff ins { background: #cdeccd; color: #14600f; text-decoration: none; }
.diff del { background: #f2cfcf; color: #8a1f1f; text-decoration: line-through; }
body.dark .diff ins { background: #244a24; color: #9fe09f; }
body.dark .diff del { background: #4a2424; color: #e6a4a4; }
.import-actions { display: flex; gap: 1rem; align-items: center; margin: 1rem 0 2rem; }

/* ---- Button-styled link ---- */
.button-link {
    display: inline-block;
    padding: 0.45rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--panel);
    color: var(--ink);
    text-decoration: none;
}
.button-link:hover { border-color: var(--muted); text-decoration: none; }

/* ---- Menu bar ---- */
.menubar { display: flex; gap: 0.1rem; }
.menu { position: relative; }
.menu-btn {
    border: none;
    background: none;
    color: var(--ink);
    padding: 0.3rem 0.7rem;
    border-radius: 5px;
    cursor: pointer;
    font: inherit;
}
.menu-btn:hover { background: var(--bg); border-color: transparent; }
.menu-list {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 40;
    min-width: 210px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 6px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
    padding: 0.25rem;
}
.logout-btn { display: inline-flex; align-items: center; vertical-align: middle; }
/* Goal celebration */
.confetti-layer { position: fixed; inset: 0; pointer-events: none; z-index: 200; overflow: hidden; }
.confetti-piece { position: absolute; top: 0; border-radius: 2px; will-change: transform; }
.goal-toast {
    position: fixed; left: 50%; bottom: 2.5rem; z-index: 210;
    transform: translateX(-50%) translateY(1rem);
    background: var(--accent); color: #fff; font-weight: 600;
    padding: 0.7rem 1.15rem; border-radius: 999px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
    opacity: 0; transition: opacity 0.35s ease, transform 0.35s ease; pointer-events: none;
}
.goal-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.help-link { margin-top: 2.5rem; padding-top: 1rem; border-top: 1px solid var(--line); }
/* Help / how-to page */
.help { max-width: 46rem; }
.help h2 { margin-top: 1.8rem; font-size: 1.15rem; border-bottom: 1px solid var(--line); padding-bottom: 0.3rem; }
.help ul { padding-left: 1.2rem; }
.help li { margin: 0.35rem 0; line-height: 1.5; }
.help code { background: var(--bg); padding: 0.05rem 0.3rem; border-radius: 4px; font-size: 0.9em; }
.menu-list[hidden] { display: none; }
/* Flipped to the right edge when a left-anchored dropdown would run off-screen. */
.menu-list.align-right { left: auto; right: 0; }
.menu-item {
    display: block;
    width: 100%;
    text-align: left;
    border: none;
    background: none;
    color: var(--ink);
    padding: 0.45rem 0.6rem;
    border-radius: 4px;
    cursor: pointer;
    font: inherit;
    text-decoration: none;
}
.menu-item:hover { background: var(--bg); text-decoration: none; }
.menu-sep { border: none; border-top: 1px solid var(--line); margin: 0.25rem 0; }

/* Compile dialog fields */
.modal-body label { display: block; margin: 0.7rem 0 0.2rem; }
.modal-body label.check { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.8rem; }
.modal-body select, .modal-body input[type=text] {
    font: inherit;
    width: 100%;
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--panel);
    color: var(--ink);
}
.modal-body label.check input { width: auto; }

.custom-size { display: flex; gap: 0.6rem; }
.custom-size label { flex: 1; }

.custom-size[hidden] { display: none; }

/* ===== Writing styles (View menu) =====================================
   Typeface / measure / leading presets for the manuscript surface. They set
   TYPOGRAPHY only — paper and ink still come from the light/dark theme, so each
   style works in both. Applied via a body.ws-* class (chosen in the View menu,
   remembered per project), so they also carry into distraction-free mode.
   Appended last so the measure wins over the focus-mode max-width.
   (--ws-serif / --ws-mono live in tokens.css.) */
/* the picker in the View menu */
.menu-label { font-size: 0.7rem; letter-spacing: 0.09em; text-transform: uppercase; color: var(--muted); padding: 0.4rem 0.9rem 0.15rem; }
.menu-item.ws-pick, .menu-item.th-pick { position: relative; padding-left: 1.7rem; }
.menu-item.ws-pick.active::before,
.menu-item.th-pick.active::before { content: "✓"; position: absolute; left: 0.75rem; color: var(--accent); font-weight: 700; }

/* Standard = no class (today's look). The rest reshape the writing surface. */
/* Only typeface/size/leading change between styles — the measure (max-width) is
   left to the shared .ql-editor rule so the column and margins never jump. */
/* Manuscript matches the mock editor's page exactly: the Palatino-family
   serif at the mock's refined book size/leading (was 1.16rem/1.8 — bigger
   than the mock). Same serif stack as --serif, so any device renders it the
   same font the mock shows. */
body.ws-manuscript .ql-editor { font-family: var(--serif); font-size: 1.06rem; line-height: 1.75; }
body.ws-typewriter .ql-editor { font-family: var(--ws-mono); font-size: 1.0rem; line-height: 1.95; }

/* ===== Editor frame: "Studio" =========================================
   Warms the FRAME (topbar + binder) a touch deeper than the editor pane, so the
   writing pane reads as the brighter "page" sitting in the studio. The project
   title goes serif, and a faint quill watermark rests at the top of the binder,
   BEHIND the list (z-index below content) so it never blocks anything. Scoped to
   body.app (the project editor only); it falls away in distraction-free with the
   rest of the frame. Colours still come from the light/dark theme. */
/* One warm material at two brightnesses, straight from the shared tokens: the
   frame (topbar + binder) takes the greige "desk" (--bg); the editor pane takes
   the ivory "page" (--panel). Harmonises in both light and dark automatically. */
body.app .topbar { background: var(--bg); }
body.app .binder { background: var(--bg); position: relative; isolation: isolate; }
body.app .editor-pane { background: var(--panel); }
body.app .brand-input { font-family: var(--ws-serif); font-weight: 600; }

/* The quill is LOCKED to the top of the binder: a sticky, zero-height holder that
   pins to the binder's top edge, so the watermark stays put while the list scrolls.
   z-index below the content, pointer-events off — never blocks. */
body.app .binder-quill { position: sticky; top: 0; height: 0; z-index: -1; pointer-events: none; }
body.app .binder-quill::before {
    content: ""; position: absolute; top: 72px; left: 50%; transform: translateX(-50%);
    width: 190px; height: 320px;
    background: url("/assets/inkwell.png") top center / contain no-repeat;
    opacity: 0.16; mix-blend-mode: multiply;
}
body.dark.app .binder-quill::before { opacity: 0.28; mix-blend-mode: screen; filter: invert(1) hue-rotate(185deg); }

/* Let the quill read through the binder's hover + selected-scene highlights. */
body.app .tree-item:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
body.app .tree-item.open { background: color-mix(in srgb, var(--accent) 15%, transparent); }

/* Distraction-free: the scrollbar is fully invisible so nothing competes with the
   words. The actual scroller is Quill's .ql-editor, so target both it and the
   container. scrollbar-color:transparent (which inherits) is the reliable hide;
   scrollbar-width + the webkit pseudo cover the rest. Scrolling still works via
   wheel / trackpad / keys. */
body.focus-mode #editor,
body.focus-mode #editor .ql-editor { scrollbar-width: none; scrollbar-color: transparent transparent; }
body.focus-mode #editor::-webkit-scrollbar,
body.focus-mode #editor .ql-editor::-webkit-scrollbar { width: 0; height: 0; }

/* A trashed scene can be opened read-only in the editor — hint it's clickable. */
.trash-item .trash-openable { cursor: pointer; }
.trash-item .trash-openable:hover { text-decoration: underline; }

/* ---------------------------------------------------------------------------
   Community forum (SCAFFOLD). Styles both the admin build panel and the gated
   public /community shell. Kept intentionally plain until the feature ships.
   --------------------------------------------------------------------------- */
.empty-hero { text-align: center; padding: 3rem 1rem; max-width: 34rem; margin: 1rem auto; }
.empty-hero h2 { margin: 0 0 0.5rem; }

/* Admin build panel */
.forum-admin-section { border: 1px solid var(--border); border-radius: 10px; padding: 0.8rem 1rem; margin: 0.7rem 0; background: var(--panel, #fff); }
body.dark .forum-admin-section { background: #1f2a24; }
.fas-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; }
.fas-mods { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin-top: 0.6rem; padding-top: 0.6rem; border-top: 1px dashed var(--border); }
.mod-chip { display: inline-flex; align-items: center; gap: 0.2rem; background: var(--accent); color: #fff; border-radius: 12px; padding: 1px 4px 1px 10px; font-size: 0.8rem; }
.mod-chip .link { color: #fff; padding: 0 4px; line-height: 1; }
.mod-add input[type="email"] { padding: 0.25rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; }

/* Public forum shell */
.forum-sections { list-style: none; padding: 0; margin: 1rem 0; }
.forum-section-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.9rem 1rem; border: 1px solid var(--border); border-radius: 10px; margin-bottom: 0.6rem; }
.fsr-title { font-weight: 600; font-size: 1.05rem; text-decoration: none; }
.fsr-title:hover { text-decoration: underline; }

/* ===================================================================== *\
   Minimal editor chrome (from the theme-lab mock): the writing surface
   floats as a paper column in the themed room; the menubar tucks away and
   reveals on hover over the topbar. Desktop only — the phone experience
   (mobile shell / stacked layout) is unchanged. Appended last so these
   override the structural rules above.
\* ===================================================================== */

/* The room behind the paper — same scenes as the dashboard. */
body.app { background: linear-gradient(160deg, #F2ECE1 0%, #EAE2D3 55%, #E7DECE 100%); }
/* Light (day) rooms per palette — the defaults. */
body.app.th-candle { background:
    radial-gradient(70% 60% at 90% 85%, rgba(230, 160, 70, 0.16), transparent 62%),
    linear-gradient(160deg, #F4EBD8 0%, #EFE4CB 55%, #EADCBE 100%); }
body.app.th-beach { background:
    radial-gradient(120% 55% at 100% 30%, rgba(235, 248, 244, 0.85), rgba(205, 232, 226, 0.3) 42%, transparent 68%),
    linear-gradient(165deg, #E8F0EC 0%, #D8E6E2 48%, #CBDDD8 100%); }
body.app.th-noir { background:
    linear-gradient(112deg, transparent 55%, rgba(120, 124, 130, 0.05) 63%, rgba(120, 124, 130, 0.05) 72%, transparent 80%),
    linear-gradient(175deg, #F0F0EE 0%, #E9E9E7 55%, #E1E1DF 100%); }
body.app.th-evergreen { background:
    radial-gradient(70% 50% at 85% 20%, rgba(120, 180, 130, 0.14), transparent 60%),
    linear-gradient(160deg, #EAF0DF 0%, #E1E9D3 55%, #D8E2CA 100%); }
body.app.th-dusk { background:
    radial-gradient(70% 55% at 92% 70%, rgba(255, 170, 130, 0.22), rgba(230, 140, 110, 0.06) 45%, transparent 68%),
    linear-gradient(160deg, #F0E7EF 0%, #E9DCE8 55%, #E2D3E1 100%); }
/* Dark (night) rooms — the 🌙 modifier's variant of each palette. */
body.app.dm.th-candle { background:
    radial-gradient(60% 55% at 88% 88%, rgba(255, 158, 64, 0.34), rgba(200, 110, 40, 0.13) 45%, transparent 70%),
    linear-gradient(135deg, #14100B 0%, #211B14 50%, #3A3021 100%); }
body.app.dm.th-noir { background:
    linear-gradient(112deg, transparent 55%, rgba(226, 232, 238, 0.10) 63%, rgba(226, 232, 238, 0.10) 72%, transparent 80%),
    radial-gradient(110% 60% at 85% 0%, rgba(210, 218, 226, 0.22), transparent 58%),
    linear-gradient(135deg, #121314 0%, #1E1F21 50%, #36383C 100%); }
body.app.dm.th-evergreen { background:
    radial-gradient(70% 50% at 85% 20%, rgba(150, 205, 160, 0.26), rgba(120, 175, 130, 0.08) 42%, transparent 64%),
    linear-gradient(135deg, #0D1411 0%, #19261F 50%, #2F4638 100%); }
body.app.dm.th-dusk { background:
    radial-gradient(70% 55% at 92% 70%, rgba(255, 170, 130, 0.34), rgba(220, 130, 110, 0.11) 45%, transparent 68%),
    linear-gradient(135deg, #1B1726 0%, #2C2740 50%, #4E4569 100%); }

@media (min-width: 761px) {
    /* ---- Menu bar: pinned show/hide by the hamburger to the LEFT of the
       title (menu.js toggles .menu-hidden). In-flow under the title row, so
       revealing it nudges the page down. The old invisible hover-reveal is
       gone -- new users never found it. ---- */
    body.app .topbar { background: var(--panel); border-bottom: 1px solid var(--line); position: relative; z-index: 30; }
    body.app .menubar {
        gap: 0.1rem; padding: 0.12rem 0.9rem 0.35rem;
        animation: np-menubar-in 0.16s ease;
    }
    body.app .topbar.menu-hidden .menubar { display: none; }
    @keyframes np-menubar-in { from { opacity: 0; transform: translateY(-5px); } }
    @media (prefers-reduced-motion: reduce) { body.app .menubar { animation: none; } }
    /* The hamburger glows (marigold) until first use; menu.js adds .glow and
       removes it for good after the first click + one-time teaching modal. */
    body.app #menu-toggle.glow { color: var(--accent); animation: menu-pin-glow 2.4s ease-out infinite; }
    @keyframes menu-pin-glow {
        0%   { box-shadow: 0 0 0 0 rgba(207, 138, 47, 0.55); }
        60%  { box-shadow: 0 0 0 10px rgba(207, 138, 47, 0); }
        100% { box-shadow: 0 0 0 0 rgba(207, 138, 47, 0); }
    }
    @media (prefers-reduced-motion: reduce) { body.app #menu-toggle.glow { animation: none; } }

    /* ---- The paper: title + toolbar + text + footer as one floating column. ---- */
    body.app .editor-pane { background: transparent; align-items: center; padding: 1.1rem 1.4rem 0; }
    body.app .editor-pane { filter: drop-shadow(0 18px 30px rgba(40, 28, 12, 0.25)); }
    body.app .doc-title-row,
    body.app .editor-pane .draft-banner,
    body.app #lock-banner,
    body.app #toolbar,
    body.app #editor,
    body.app .editor-footer { width: min(50rem, 100%); }
    body.app .doc-title-row { background: var(--paper-bg); border: 1px solid var(--paper-line); border-bottom: none; border-radius: 10px 10px 0 0; padding-top: 0.4rem; }
    body.app .doc-title { font-family: var(--serif); font-size: 1.3rem; font-weight: 700; color: var(--paper-ink); }
    body.app #toolbar { border-left: 1px solid var(--paper-line); border-right: 1px solid var(--paper-line); background: var(--paper-bg); text-align: center; }
    body.app #editor { background: var(--paper-bg); border-left: 1px solid var(--paper-line); border-right: 1px solid var(--paper-line); }
    body.app .ql-editor { color: var(--paper-ink); }
    body.app .editor-footer { background: var(--paper-bg); border: 1px solid var(--paper-line); border-top: 1px solid var(--paper-line); border-radius: 0 0 10px 10px; margin-bottom: 1.1rem; padding-right: 1.2rem; color: var(--paper-mut); }
    /* Toolbar controls follow the PAPER's ink, not the room's — the paper can
       be light inside a dark theme (that's the whole point), so the body.dark
       Quill recoloring must not decide these. */
    body.app #toolbar .ql-stroke { stroke: var(--paper-mut); }
    body.app #toolbar .ql-fill { fill: var(--paper-mut); }
    body.app #toolbar .ql-picker-label, body.app #toolbar .ql-picker-item { color: var(--paper-mut); }
    body.app #toolbar .ql-picker-options { background: var(--paper-bg); border-color: var(--paper-line); }
    body.app #toolbar .text-btn { background: transparent; color: var(--paper-mut); border-color: var(--paper-line); }
    /* Empty state sits on the room itself, not on a giant blank card. */
    body.app .empty-state { background: transparent; }
    /* Focus mode strips the paper down to the text block alone. */
    body.focus-mode #editor { border: 1px solid var(--line); border-radius: 10px; margin: 1.2rem 0; }
}

/* Dark-mode modifier rooms for the EDITOR (body.app.dm): the daylight rooms
   after dark. Night themes are excluded via :not() — they keep their own. */
body.app.dm:not(.th-candle):not(.th-noir):not(.th-evergreen):not(.th-dusk):not(.th-beach):not(.th-cherry):not(.th-rainy) { background:
    radial-gradient(70% 60% at 92% 90%, rgba(255, 214, 150, 0.26), rgba(230, 180, 110, 0.08) 45%, transparent 68%),
    linear-gradient(135deg, #171411 0%, #232019 50%, #3A342A 100%); }
body.app.dm.th-beach { background:
    radial-gradient(70% 55% at 88% 12%, rgba(165, 205, 235, 0.24), rgba(140, 180, 215, 0.08) 42%, transparent 65%),
    linear-gradient(135deg, #0C141A 0%, #16222C 50%, #2E4354 100%); }

/* ==== The paper's own palette (ported from the theme-lab mock). The page is
   a surface INDEPENDENT of the room: night themes keep a lit page — warm
   parchment by candlelight, gray stock in Noir — and the dark-mode modifier
   (body.dm) is what dims the paper itself. Defaults = follow the tokens. ==== */
body.app { --paper-bg: var(--panel); --paper-ink: var(--ink); --paper-line: var(--line); --paper-mut: var(--muted); }
body.app.th-candle    { --paper-bg: #EEE2C6; --paper-ink: #33291C; --paper-line: #D9C6A2; --paper-mut: #7E6C4F; }
body.app.th-beach     { --paper-bg: #F6FAF7; --paper-ink: #263635; --paper-line: #D8E4DD; --paper-mut: #5F7672; }
body.app.th-noir      { --paper-bg: #E2E2DF; --paper-ink: #2E2E32; --paper-line: #C6C6C3; --paper-mut: #66666A; }
body.app.th-evergreen { --paper-bg: #EAEEDD; --paper-ink: #26332B; --paper-line: #CDD6BE; --paper-mut: #5C7263; }
body.app.th-dusk      { --paper-bg: #F8F2F7; --paper-ink: #3A3044; --paper-line: #E0D2DF; --paper-mut: #71638A; }
/* Dark mode dims the paper — every theme has a night page. (These come after
   the theme blocks so .dm wins; the .dm.th-* pairs outrank both.) */
body.app.dm           { --paper-bg: #2B2924; --paper-ink: #D5D0C4; --paper-line: #3F3B33; --paper-mut: #95886F; }
body.app.dm.th-candle    { --paper-bg: #242017; --paper-ink: #D9CDB4; --paper-line: #3C352A; --paper-mut: #95886F; }
body.app.dm.th-beach     { --paper-bg: #223140; --paper-ink: #C6D8E2; --paper-line: #35495A; --paper-mut: #7A91A0; }
body.app.dm.th-noir      { --paper-bg: #28282B; --paper-ink: #CFCFCD; --paper-line: #3E3E41; --paper-mut: #8C8C8A; }
body.app.dm.th-evergreen { --paper-bg: #202B24; --paper-ink: #CBDCC9; --paper-line: #35443A; --paper-mut: #7E9284; }
body.app.dm.th-dusk      { --paper-bg: #2C2739; --paper-ink: #D5CBE4; --paper-line: #443C58; --paper-mut: #948BA8; }

/* The page's scrollbar whispers: thin, translucent, tinted to the paper's own
   muted ink so it never fights the theme. (Focus mode already hides it fully.) */
body.app #editor {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--paper-mut) 28%, transparent) transparent;
}

/* ==== Theme chooser modal: cards painted with each theme's REAL palette
   (room gradient + page chip + faux text lines). Under 🌙 (body.dm) every
   card flips to its dark rendition, so the gallery always shows the truth. ==== */
.theme-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.8rem; margin-bottom: 1rem; }
.thcard {
    position: relative; display: flex; flex-direction: column; justify-content: flex-end; gap: 0.55rem;
    min-height: 112px; padding: 0.7rem 0.7rem 0.55rem; text-align: left;
    font: inherit; cursor: pointer; border: 2px solid var(--line); border-radius: 10px;
    background: var(--tc-room);
}
.thcard .mini-page { display: block; border-radius: 4px; padding: 0.5rem 0.55rem 0.55rem; background: var(--tc-page); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12); }
/* Real words, set like the editor's page: the theme's own serif ink. */
.thcard .mini-text {
    display: block;
    font-family: var(--serif, Georgia, serif);
    font-size: 0.72rem; line-height: 1.55;
    color: var(--tc-ink);
}
.thcard .th-name { font-size: 0.85rem; font-weight: 600; color: var(--tc-ink); }
.thcard.active { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); }
.thcard.active::after { content: "✓"; position: absolute; top: 0.35rem; right: 0.55rem; color: var(--tc-ink); font-weight: 700; }

/* Each card wears its NATURAL mood by default — day palettes light, night
   palettes dark. The modal's flip toggle adds .tc-flip to swap EACH card to
   its OPPOSITE mood, so both states are a mix of light and dark. (cherry +
   rainy natural/light are defined with their themes further below.) */
.thcard[data-th="quiet-room"] { --tc-room: linear-gradient(160deg, #F2ECE1, #E7DECE); --tc-page: #F7F4EC; --tc-ink: #2E2A22; }
.thcard[data-th="beach"]      { --tc-room: linear-gradient(165deg, #E8F0EC, #CBDDD8); --tc-page: #F6FAF7; --tc-ink: #2B3B3A; }
.thcard[data-th="candle"]     { --tc-room: linear-gradient(135deg, #14100B, #3A3021); --tc-page: #242017; --tc-ink: #D9CDB4; }
.thcard[data-th="noir"]       { --tc-room: linear-gradient(135deg, #121314, #36383C); --tc-page: #28282B; --tc-ink: #CFCFCD; }
.thcard[data-th="evergreen"]  { --tc-room: linear-gradient(135deg, #0D1411, #2F4638); --tc-page: #202B24; --tc-ink: #CBDCC9; }
.thcard[data-th="dusk"]       { --tc-room: linear-gradient(135deg, #1B1726, #4E4569); --tc-page: #2C2739; --tc-ink: #D5CBE4; }
/* Flipped: each card's OPPOSITE mood. Day themes -> dark; night themes -> light. */
.theme-cards.tc-flip .thcard[data-th="quiet-room"] { --tc-room: linear-gradient(160deg, #2A2721, #1C1915); --tc-page: #2B2924; --tc-ink: #D5D0C4; }
.theme-cards.tc-flip .thcard[data-th="beach"]      { --tc-room: linear-gradient(135deg, #0C141A, #2E4354); --tc-page: #223140; --tc-ink: #C6D8E2; }
.theme-cards.tc-flip .thcard[data-th="cherry"]     { --tc-room: linear-gradient(135deg, #231A1C, #443036); --tc-page: #292323; --tc-ink: #D9CFC9; }
.theme-cards.tc-flip .thcard[data-th="rainy"]      { --tc-room: linear-gradient(135deg, #141C23, #2C3D49); --tc-page: #212C34; --tc-ink: #CBD5DE; }
.theme-cards.tc-flip .thcard[data-th="candle"]     { --tc-room: linear-gradient(160deg, #F4EBD8, #EADCBE); --tc-page: #EEE2C6; --tc-ink: #33291C; }
.theme-cards.tc-flip .thcard[data-th="noir"]       { --tc-room: linear-gradient(175deg, #F0F0EE, #E1E1DF); --tc-page: #E2E2DF; --tc-ink: #2E2E32; }
.theme-cards.tc-flip .thcard[data-th="evergreen"]  { --tc-room: linear-gradient(160deg, #EAF0DF, #D8E2CA); --tc-page: #EAEEDD; --tc-ink: #26332B; }
.theme-cards.tc-flip .thcard[data-th="dusk"]       { --tc-room: linear-gradient(160deg, #F0E7EF, #E2D3E1); --tc-page: #F8F2F7; --tc-ink: #3A3044; }

/* Theme modal commit: one centered, accent-filled button — it must stand
   apart from the panel behind it in every theme, light or dark. */
.themes-actions { display: flex; justify-content: center; padding: 0 1rem 1.15rem; }
#themes-select {
    font: inherit; font-weight: 600; cursor: pointer;
    background: var(--accent); color: #fff; border: none; border-radius: 8px;
    padding: 0.55rem 1.8rem;
}
#themes-select:hover { background: var(--accent-deep); }

/* ==== Cherry Blossom (added 2026-07-18): calm ink garden. Editor rooms,
   papers, and gallery card. Day = rose-washed whites; night = plum-rose. ==== */
body.app.th-cherry { background:
    radial-gradient(120% 70% at 85% 0%, rgba(174, 97, 104, 0.20), transparent 55%),
    radial-gradient(80% 40% at 20% 100%, rgba(150, 145, 150, 0.12), transparent 60%),
    linear-gradient(170deg, #FBF4F2 0%, #F6E9E6 55%, #F0DEDB 100%); }
body.app.dm.th-cherry { background:
    radial-gradient(120% 70% at 85% 0%, rgba(222, 146, 152, 0.17), transparent 55%),
    linear-gradient(135deg, #231A1C 0%, #2B2124 50%, #443036 100%); }
body.app.th-cherry    { --paper-bg: #FBF8F5; --paper-ink: #3A3534; --paper-line: #E7E0D8; --paper-mut: #968E87; }
body.app.dm.th-cherry { --paper-bg: #292323; --paper-ink: #D9CFC9; --paper-line: #403936; --paper-mut: #9C918A; }
.thcard[data-th="cherry"] { --tc-room: linear-gradient(170deg, #FBF4F2, #F0DEDB); --tc-page: #FBF8F5; --tc-ink: #3A3534; }
/* Rainy Day editor rooms + papers + gallery card. */
body.app.th-rainy { background:
    radial-gradient(120% 65% at 82% 0%, rgba(196, 212, 228, 0.5), transparent 58%),
    linear-gradient(170deg, #EEF2F6 0%, #E1E8EF 55%, #D6DFE8 100%); }
body.app.dm.th-rainy { background:
    radial-gradient(120% 70% at 85% 0%, rgba(150, 180, 210, 0.16), transparent 55%),
    linear-gradient(135deg, #141C23 0%, #1C2831 50%, #2C3D49 100%); }
body.app.th-rainy    { --paper-bg: #F5F8FB; --paper-ink: #333B44; --paper-line: #DBE3EB; --paper-mut: #7C8794; }
body.app.dm.th-rainy { --paper-bg: #212C34; --paper-ink: #CBD5DE; --paper-line: #35434F; --paper-mut: #8492A0; }
.thcard[data-th="rainy"] { --tc-room: linear-gradient(170deg, #EEF2F6, #D6DFE8); --tc-page: #F5F8FB; --tc-ink: #333B44; }

/* ==== Theme / dark-mode changes are a slow MOOD SHIFT: one room dissolves
   into the other over 1.2s (View Transitions crossfade, duration stretched).
   Only theme switches trigger view transitions, so this affects nothing
   else. No-API browsers switch instantly. ==== */
::view-transition-old(root), ::view-transition-new(root) {
    animation-duration: 1.2s;
    animation-timing-function: ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}
/* Freeze per-property transitions during the dissolve so the snapshots are
   clean end-states, not mid-fade frames. */
.vt-lock, .vt-lock * { transition: none !important; }

/* ==== Brand-new project (body.project-empty, set in workspace.js when the
   manuscript has zero items): the editor chrome is HIDDEN — a blank editor
   looked typable — and a teaching card stands in its place. ==== */
.empty-state .es-start { display: none; }
body.project-empty .empty-state .es-pick { display: none; }
body.project-empty .empty-state .es-start { display: block; }
body.project-empty .doc-title-row,
body.project-empty #toolbar,
body.project-empty #editor,
body.project-empty .editor-footer { display: none; }
/* Empty-state must be opaque here so nothing shows through the teaching card
   area (the minimal-editor rule made it transparent for the normal case). */
body.project-empty .empty-state { background: transparent; }
.es-card {
    max-width: 25rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: 1.8rem 2rem;
    text-align: center;
    box-shadow: 0 14px 34px rgba(40, 28, 12, 0.12);
}
.es-card .es-quill { font-size: 1.7rem; line-height: 1; color: var(--accent); margin-bottom: 0.6rem; }
.es-card h2 { font-family: var(--serif); font-size: 1.4rem; font-weight: 600; margin: 0 0 0.5rem; color: var(--ink); }
.es-card p { color: var(--muted); line-height: 1.6; margin: 0; }
/* The card adapts: blank project vs. "chapters made, still no writable doc". */
.es-h-folders, .es-p-folders { display: none; }
body.has-containers .es-h-blank, body.has-containers .es-p-blank { display: none; }
body.has-containers .es-h-folders { display: block; }
body.has-containers .es-p-folders { display: block; }

/* Reusable attention pulse (marigold ring) for teaching affordances —
   applied/cleared by window.NPTeachPulse in ui.js. */
.np-pulse { animation: np-teach-pulse 2.4s ease-out infinite; }
@keyframes np-teach-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(207, 138, 47, 0.5); }
    60%  { box-shadow: 0 0 0 12px rgba(207, 138, 47, 0); }
    100% { box-shadow: 0 0 0 0 rgba(207, 138, 47, 0); }
}
@media (prefers-reduced-motion: reduce) { .np-pulse { animation: none; } }

/* Back-to-Projects arrow in the editor topbar: an <a> styled as an icon
   button, matching the ☰ pin beside it. */
.icon-btn.back-btn { text-decoration: none; color: var(--ink); }
.icon-btn.back-btn:hover { text-decoration: none; }

/* Themes-modal flip toggle: highlighted while the cards show their flipped
   (non-default) light/dark. */
#themes-dm[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-deep); }

/* The Themes gallery flip crossfades quicker than the full-page theme dissolve
   (scoped via html.vt-flip during the transition). */
html.vt-flip::view-transition-old(root),
html.vt-flip::view-transition-new(root) { animation-duration: 0.45s; }
