/* === Fonts === */
@font-face {
    font-family: "Iosevka Etoile";
    src: url("/_/fonts/IosevkaEtoile.woff2") format("woff2");
    font-display: swap;
}
@font-face {
    font-family: "Iosevka Slab";
    src: url("/_/fonts/IosevkaSlab.woff2") format("woff2");
    font-display: swap;
}

/* === Theme === */
:root {
    --bg: #2e2e2e;
    --bg-panel: #434343;
    --bg-panel-hover: #585858;
    --text: #e6e6e6;
    --text-muted: #cfcfcf;
    --primary: #87458a;
    --primary-hover: #d64d95;
    --secondary: #c48401;
    --link: #01b6c4;
    --link-hover: #d6d24d;
    --danger: #c40141;
    --danger-hover: #d03467;
    /* Translucent scrim for badges/overlays sitting on top of media. */
    --overlay: rgba(0, 0, 0, 0.55);

    --border: 1px solid var(--secondary);
    --border-dashed: 1px dashed var(--secondary);
    /* Subtle vertical rail for tree-nesting depth — quieter than --border so
       it reads as a guide, not a divider. */
    --border-guide: 1px solid var(--bg-panel-hover);

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;

    --font-xs: 0.75rem;
    --font-sm: 0.85rem;

    /* Width of the persistent left folder-tree rail (desktop). */
    --tree-width: 15rem;

    /* Comfortable max reading width for the center column's content + footer.
       The shell itself is edge-to-edge; this keeps prose lines readable on
       wide monitors (content stays centered within the center column). */
    --reading-width: 60rem;
}

/* Anchor / TOC jumps are handled by the .center scroll container's own
   scroll-padding-top (the header no longer overlaps content in the app-shell),
   so no html-level scroll padding is needed. */

/* === Base === */
/* App-shell: the body is a full-viewport, non-scrolling grid of two rows —
   the fixed-height header and a 1fr shell that owns all scrolling internally.
   100dvh (not 100vh) so the mobile browser's dynamic toolbar doesn't clip the
   bottom row; overflow:hidden pins the header and lets each shell column scroll
   on its own. */
body {
    background: var(--bg);
    color: var(--text);
    height: 100dvh;
    margin: 0;
    padding: 0;
    overflow: hidden;
    font: 1rem "Iosevka Etoile", monospace;
    display: grid;
    grid-template-rows: auto 1fr;
}
* { box-sizing: border-box; margin: 0; padding: 0; }

a { color: var(--text); text-decoration: none; }
a:hover { color: var(--primary-hover); }
.content a { color: var(--link); }
.content a:hover { color: var(--link-hover); }
.content a.broken { color: var(--primary-hover); text-decoration: line-through; }
.content a.broken:hover { color: var(--link-hover); }

hr { border: none; border-top: var(--border-dashed); margin: var(--space-4) 0; }

/* === Layout primitives ===
   .row and .col are shared flex recipes; gap-* modifiers cover the cases
   where the default rhythm doesn't fit. */
.row { display: flex; align-items: center; gap: var(--space-2); }
.col { display: flex; flex-direction: column; gap: var(--space-3); }
.gap-1 { gap: var(--space-1); }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }
.space-between { justify-content: space-between; }
.divider-dashed { border-bottom: var(--border-dashed); }

/* === Page layout (app-shell) ===
   The shell is a full-height flex row below the header: left rail | center |
   right rail. Each column owns its own vertical scroll (overflow-y:auto +
   min-height:0), so nothing scrolls the page as a whole. Edge-to-edge: no
   centered max-width container. The right rail collapses out of the flex flow
   when empty (:empty { display:none }), letting the center reclaim the width. */
.shell {
    display: flex;
    min-height: 0;
    overflow: hidden;
}
/* Center column: main content plus the footer beneath it, scrolling together.
   Content and footer are held to a comfortable reading width and centered
   within the (edge-to-edge) column. */
.center {
    flex: 1 1 auto;
    min-width: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    scroll-padding-top: var(--space-4);
}
main {
    width: 100%;
    max-width: var(--reading-width);
    padding: var(--space-5) var(--space-4);
    flex: 1 0 auto;
    min-width: 0;
}

/* === Header / footer ===
   Header is the app-shell's fixed top row (grid row 1 of <body>): full width,
   never scrolls. Three-column grid (breadcrumbs left, search centre, actions
   right) so the centre stays reserved even when search is hidden in editor
   mode; the far-right actions column hosts the [ACTIONS] dropdown. position +
   z-index keep the header (and its open dropdown) painting above the shell.
   Mobile (≤1100px) collapses to a compact three-column layout — see responsive
   block below. */
header {
    position: relative;
    z-index: 40;
    background: var(--bg);
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--border-dashed);
    display: grid;
    grid-template-columns: 1fr minmax(0, 50rem) 1fr;
    grid-template-areas: "crumbs search actions";
    align-items: center;
    gap: var(--space-2);
}
/* Footer rides at the end of the center column's content (scrolls with it, not
   pinned to the viewport). Held to the same reading width as main so its top
   border delimits the content, not the whole shell. */
footer {
    width: 100%;
    max-width: var(--reading-width);
    padding: var(--space-3) var(--space-4);
    border-top: var(--border-dashed);
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.breadcrumb { grid-area: crumbs; gap: var(--space-1); min-width: 0; }
.header-actions { grid-area: actions; justify-content: flex-end; flex-wrap: wrap; }
.logo { width: 1.1em; height: 1.1em; vertical-align: center; }

/* === Panel ===
   Bordered container recipe shared by listings, sidebar widgets, the tree
   picker, the floating TOC. .panel-floating raises the background for menus
   and modals that sit over content. */
.panel { border: var(--border); background: var(--bg); }
.panel-floating { background: var(--bg-panel); }
.panel-header {
    font-size: var(--font-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    border-bottom: var(--border-dashed);
    padding-bottom: var(--space-1);
    margin-bottom: 0.4rem;
}
.panel-body {
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    word-break: break-word;
}
.panel-footer {
    padding: 0.6rem var(--space-4);
    border-top: var(--border-dashed);
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
}

/* === Buttons === */
.btn {
    background: none;
    border: none;
    color: var(--text);
    font: inherit;
    cursor: pointer;
    padding: 0;
    text-decoration: none;
    display: inline-block;
    white-space: nowrap;
}
.btn::before { content: "["; color: var(--secondary); }
.btn::after { content: "]"; color: var(--secondary); }
.btn:hover { color: var(--primary-hover); }
.btn-small { font-size: 0.8rem; font-weight: normal; vertical-align: middle; }
.btn-tool { padding: 0 0.15rem; }
.btn-block {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    width: 100%;
    border: none;
    padding: 0.3rem var(--space-3);
    white-space: nowrap;
}
.btn-fab {
    background: var(--bg-panel);
    border: var(--border);
    width: 3rem;
    height: 3rem;
    font-size: 1.5rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.btn-fab::before, .btn-fab::after { content: none; }
.btn-fab:hover { background: var(--bg-panel-hover); color: var(--primary-hover); }
.danger { color: var(--danger); }
.danger:hover { color: var(--danger-hover); }
/* Selected segmented-toggle button (view-settings modal). */
.btn.is-active { color: var(--primary-hover); }

/* === Form controls ===
   .input baseline is shared by search-input, modal inputs, and the editor
   textarea. Hosts layer their own background / font-family / sizing on top. */
.input {
    width: 100%;
    background: var(--bg-panel);
    border: var(--border);
    color: var(--text);
    font: inherit;
    padding: 0.3rem var(--space-2);
    outline: none;
}
.input:focus { border-color: var(--primary-hover); }

/* === Typography utilities === */
.muted { color: var(--text-muted); font-size: var(--font-sm); }
.small { font-size: var(--font-sm); }
.caption {
    font-size: var(--font-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
}
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* === Markdown content === */
.content { margin-bottom: 2rem; }
.content h1, .content h2, .content h3,
.content h4, .content h5, .content h6,
main > h2 {
    color: var(--text);
    margin: 1.25rem 0 var(--space-2);
    line-height: 1.3;
}
.content h1 {
    font-size: 1.75rem;
    border-bottom: var(--border-dashed);
    padding-bottom: var(--space-1);
}
.content h2, main > h2 { font-size: 1.4rem; }
.content h3 { font-size: 1.15rem; }
.content p { margin: var(--space-3) 0; }
.content ul, .content ol { margin: var(--space-3) 0 var(--space-3) var(--space-5); }
.content li { margin: var(--space-1) 0; }
.content blockquote {
    border-left: 3px solid var(--secondary);
    padding: var(--space-1) var(--space-4);
    color: var(--text-muted);
    margin: var(--space-3) 0;
}
.content code {
    font-family: "Iosevka Etoile", monospace;
    font-size: 0.875em;
    background: var(--bg-panel);
    padding: 0.1em 0.35em;
}
.content pre {
    background: var(--bg-panel);
    border: var(--border);
    padding: var(--space-4);
    overflow-x: auto;
    margin: var(--space-3) 0;
}
.content pre code { background: none; padding: 0; }
.content hr { margin: var(--space-5) 0; }
.content img { max-width: 100%; }
.content li:has(> input.task-checkbox:checked) {
    color: var(--text-muted);
    text-decoration: line-through;
}

a.heading-anchor {
    color: var(--text-muted);
    margin-right: 0.4em;
    font-weight: normal;
    text-decoration: none;
}
a.heading-anchor:hover { color: var(--primary-hover); }

/* === Data tables ===
   Shared style for the file listing, search-suggestion dropdown, and
   markdown content tables. .data-table-grid adds per-cell borders + a
   header band for content (markdown) tables. */
.data-table { width: 100%; border-collapse: collapse; }
.data-table th,
.data-table td { padding: 0.4rem var(--space-3); text-align: left; }
.data-table:not(.data-table-grid) tbody tr + tr { border-top: var(--border); }
.data-table tr.is-active { background: var(--bg-panel-hover); }
/* Hover-highlight only on devices with a real pointer. On touch, a tap or
   drag-scroll leaves an emulated :hover stuck on the last-touched row until
   the next tap — distracting while scrolling a listing. */
@media (hover: hover) {
    .data-table:not(.data-table-grid) tbody tr:hover { background: var(--bg-panel-hover); }
}
.data-table tbody tr.is-empty,
.data-table tbody tr.is-empty:hover {
    color: var(--text-muted);
    background: none;
    cursor: default;
}
.data-table-grid th,
.data-table-grid td { border: var(--border); }
.data-table-grid th { background: var(--bg-panel); color: var(--text); }
.content .data-table-grid { margin: var(--space-3) 0; font-size: 0.9rem; }

/* File listing rows */
.list-item { font-size: 0.95rem; }
.list-item > td { padding: 0.6rem var(--space-4); }
.list-item td.icon { width: 1.25rem; text-align: center; }
.list-item td.name { overflow-wrap: anywhere; }
.list-item td.name a { color: inherit; display: block; }
.list-item td.meta {
    color: var(--text-muted);
    font-size: 0.8rem;
    white-space: nowrap;
    text-align: right;
}

/* === Dropdown menu === */
.dropdown { position: relative; }
.dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 100;
    min-width: 9rem;
    display: none;
    background: var(--bg-panel);
    border: var(--border);
}
.dropdown-menu.align-right { left: auto; right: 0; }
.dropdown-menu.open-up { top: auto; bottom: 100%; margin-bottom: 0.4rem; }
.dropdown-menu.is-open { display: block; }
.dropdown-menu.scrollable { max-height: 23rem; overflow-y: auto; }

/* === Suggestion dropdown (header search + editor link picker) ===
   Anchored to a position:relative host. Mirrors .dropdown-menu visuals with
   a dashed border and bg-panel-hover for the active row. */
.suggest-host { position: relative; }
.suggest-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 200;
    background: var(--bg-panel);
    border: var(--border-dashed);
    border-top: none;
    display: none;
}
.suggest-dropdown.is-open { display: block; }
.suggest-row { cursor: pointer; }
.suggest-row > td { padding: 0.4rem 0.6rem; }
.suggest-name, .suggest-path { display: block; }
.suggest-name { color: var(--text); }
.suggest-path { color: var(--text-muted); font-size: 0.8rem; margin-top: 0.1rem; }
.suggest-footer > td { color: var(--link); font-size: var(--font-sm); }

/* === Editor toolbar ===
   Single non-wrapping row that scrolls horizontally (swipe on mobile) rather
   than breaking into stacked rows. A horizontal-scroll container also clips
   overflow-y, so open dropdown menus are pinned to the viewport via JS
   (editor/main.js pinMenu) to escape the clip. */
.editor-toolbar {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--space-1);
    border: var(--border);
    border-bottom: none;
    padding: 0.4rem 0.6rem;
    background: var(--bg-panel-hover);
    overflow-x: auto;
    scrollbar-width: none;
}
.editor-toolbar::-webkit-scrollbar { display: none; }
.editor-toolbar > * { flex-shrink: 0; }
.toolbar-sep {
    width: 1px;
    background: var(--secondary);
    margin: 0 0.2rem;
    align-self: stretch;
}

/* === Edit form === */
.edit-form { display: flex; flex-direction: column; }
/* No rails are rendered while editing, so the editor uses the full center
   column: drop the reading-width cap on main (and the footer) so the toolbar
   and CodeMirror mount span the whole width. */
body.edit-mode main,
body.edit-mode footer { max-width: none; }
/* CodeMirror mount. The .cm-editor visual treatment (border, bg, font, padding)
   lives in the CM theme (editor-build/entry.js), keyed off the same :root
   variables; this only sizes the container. */
.editor-cm { min-height: 60vh; }
.editor-cm .cm-editor { height: 100%; }

/* === Search === */
.search-form {
    grid-area: search;
    display: flex;
    gap: var(--space-1);
    position: relative;
    justify-self: center;
    width: 100%;
    max-width: 40rem;
}
.search-input { font-size: 0.9rem; }
.search-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-4);
    word-break: break-word;
}
.search-card a { color: var(--link); font-size: 1.1rem; }
.search-card a:hover { color: var(--link-hover); }
.search-section {
    padding-bottom: var(--space-2);
    border-bottom: var(--border-dashed);
}

/* === Floating action button ===
   Standalone FAB buttons (the tree rail, the right rail) are mobile-only and
   stack bottom-right: the tree FAB anchors the bottom, the right-rail FAB sits
   above it. Wrapped FABs (the search actions dropdown) stay visible on desktop
   and, on mobile, sit in the upper slot so they never overlap the tree FAB. */
.fab { position: fixed; bottom: var(--space-4); right: var(--space-4); z-index: 50; }
button.fab { display: none; }
.fab-rail { bottom: calc(var(--space-4) + 3rem + var(--space-2)); }

/* === Companion status === */
.companion-status { margin-left: auto; }
.companion-icon { font-size: 0.9rem; line-height: 1; padding: 0.1rem 0.3rem; }
.companion-on { color: var(--link); }
.companion-off { color: var(--text-muted); }
.companion-flyout { min-width: 14rem; padding: 0.4rem; }
.companion-line { padding: var(--space-1) var(--space-2); font-size: var(--font-sm); }

/* === Photo grid === */
.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 0.4rem;
    margin-top: var(--space-3);
}
.photo-grid a { display: block; line-height: 0; }
.photo-grid img {
    width: 100%;
    height: 140px;
    object-fit: cover;
    display: block;
    background: var(--bg-panel) url("/_/icons/thumb-placeholder.svg") center/2rem no-repeat;
}

/* === Thumbnail listing grid ===
   File-listing variant of .photo-grid: responsive tiles that pair a thumbnail
   (or a file/folder icon for non-thumbnailable entries) with a truncated
   name label beneath. */
.thumb-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: var(--space-3);
    margin-top: var(--space-3);
}
.thumb-tile {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    color: var(--text);
    border: var(--border);
    background: var(--bg-panel);
    padding: var(--space-2);
}
.thumb-tile:hover { background: var(--bg-panel-hover); color: var(--primary-hover); }
.thumb-img {
    width: 100%;
    height: 150px;
    object-fit: cover;
    display: block;
    background: var(--bg) url("/_/icons/thumb-placeholder.svg") center/2rem no-repeat;
}
/* Wrapper so a video tile can overlay a play badge on its extracted frame. */
.thumb-media { position: relative; display: block; }
.thumb-play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    padding-left: 0.15rem;
    border-radius: 50%;
    background: var(--overlay);
    color: var(--text);
    pointer-events: none;
}
.thumb-icon {
    height: 150px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 3rem;
    color: var(--secondary);
}
.thumb-label { font-size: var(--font-sm); }

.empty { padding: var(--space-4); text-align: center; }

/* === Scrollbars === */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #111; }
::-webkit-scrollbar-thumb { background: var(--primary); }
::-webkit-scrollbar-thumb:hover { background: var(--primary-hover); }

/* === Sidebar (right rail) ===
   Full-height column in the app-shell that scrolls its own overflow (TOC on
   top, page widget(s) below). Collapses out of the flex row when it has no
   content so the center column widens. A dashed separator to main mirrors the
   left tree rail; widgets within drop their panel outlines (see
   .panel-sidebar). */
.sidebar {
    width: 14rem;
    flex-shrink: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-4) 0 var(--space-4) var(--space-2);
    border-left: var(--border-dashed);
}
aside.sidebar:empty { display: none; }

/* Density modifier for panels in the sidebar (smaller font, tighter padding).
   Drops the .panel outline so the rail reads as a clean column separated from
   main by the .sidebar dashed border, matching the left tree rail. Inside the
   mobile Overlay the widgets render as plain full-width content. */
.panel-sidebar {
    padding: var(--space-2) var(--space-3);
    font-size: var(--font-sm);
    border: none;
}

/* === Table of contents ===
   Rendered as a .panel-sidebar block in the right rail (padding + font-size
   come from that density class); toc.js always mounts it there, on both
   desktop and inside the mobile Overlay. */
.toc ul { list-style: none; margin: 0; padding: 0; }
.toc li { margin: 0.15rem 0; }
.toc a {
    color: var(--link);
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.toc a:hover { color: var(--link-hover); }
.toc-h3 { padding-left: 0.8rem; }
.toc-h4 { padding-left: 1.6rem; }

/* === Modal === */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    z-index: 1000;
    padding: var(--space-4);
}
.modal {
    width: 100%;
    max-width: 500px;
    display: flex;
    flex-direction: column;
    margin-top: 6rem;
    position: relative;
}
.modal.is-dragged { margin: 0; }
/* Modal headers use larger font + bright color + drag handle; everything
   else comes from .panel-header. */
.modal .panel-header {
    font-size: var(--font-sm);
    color: var(--text);
    padding: 0.6rem var(--space-4);
    margin-bottom: 0;
    cursor: move;
    user-select: none;
}
/* Modal-scoped input variant: dark bg + slab font + slightly more padding. */
.modal .input {
    background: var(--bg);
    font-family: "Iosevka Slab", monospace;
    padding: 0.4rem 0.6rem;
}

/* === Overlay (full-viewport rail host, mobile) ===
   A distinct component from .modal: it hosts a whole rail (the folder tree or
   the right rail's TOC/widgets) at full screen with its own scroll and a
   top-right close control. overlay.js MOVES the rail node into .overlay-body,
   so the rules below strip the rail's column chrome (fixed width, borders, the
   mobile display:none) and let it render as plain full-width content. */
.overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    background: var(--bg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.overlay-bar {
    display: flex;
    justify-content: flex-end;
    padding: var(--space-2);
    border-bottom: var(--border-dashed);
    flex-shrink: 0;
}
.overlay-close { width: 2.5rem; height: 2.5rem; font-size: 1.5rem; }
.overlay-body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-3) var(--space-4);
    -webkit-overflow-scrolling: touch;
}
.overlay-body .tree-scroll,
.overlay-body .sidebar {
    display: block;
    width: auto;
    max-height: none;
    border: none;
    padding: 0;
    overflow: visible;
}
/* Right rail keeps its column spacing (TOC above widgets) inside the overlay;
   the base .sidebar already sets flex-direction + gap. */
.overlay-body .sidebar { display: flex; }

/* === Tree picker === */
/* Rows are click targets (navigate / toggle), not prose — suppress the
   text-selection highlight that double/drag clicks would otherwise leave,
   matching the persistent .tree-sidebar rail. */
.tree-picker { max-height: 60vh; overflow-y: auto; user-select: none; }
.tree-row {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.25rem var(--space-1);
    cursor: pointer;
}
.tree-row:hover, .tree-row.is-selected { background: var(--bg-panel-hover); }
.tree-row.is-selected {
    border-left: 3px solid var(--primary);
    padding-left: calc(var(--space-2) - 3px);
}
.tree-row.is-disabled { color: var(--text-muted); cursor: default; }
.tree-row.is-disabled:hover { background: none; }
.tree-chevron { text-align: center; flex-shrink: 0; }
.tree-chevron { width: 1.25rem; color: var(--secondary); }
.tree-chevron.is-leaf { visibility: hidden; }
.tree-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Each nesting level gets a vertical guide rail down its left edge so depth
   stays scannable in the compact view (cf. VS Code / file-explorer trees). */
.tree-children {
    margin-left: var(--space-2);
    padding-left: var(--space-2);
    border-left: var(--border-guide);
}
.tree-selected-path {
    font-size: var(--font-sm);
    padding: var(--space-1) 0;
    word-break: break-all;
}
/* Current-page row in the navigation rail. Mirrors .tree-row.is-selected so the
   two tree surfaces stay visually consistent. */
.tree-row.is-active {
    background: var(--bg-panel-hover);
    border-left: 3px solid var(--primary);
    padding-left: calc(var(--space-2) - 3px);
}
.tree-row.is-active > .tree-name { color: var(--primary-hover); }

/* === Tree sidebar (persistent left navigation rail) ===
   Reuses the .tree-row / .tree-children / .tree-name / .tree-chevron modules.
   Desktop: a full-height flex column in the app-shell (composes with .col)
   holding the tree's own scroll region. Mobile: not laid out inline — its
   content is surfaced through the Overlay via the stacked FABs (see
   responsive). */
/* No right padding on the aside: the scrolling children below reach the
   border-right so their scrollbars sit flush against the divider line (they
   pad their own content off the scrollbar instead). */
.tree-sidebar {
    width: var(--tree-width);
    flex-shrink: 0;
    min-height: 0;
    padding: var(--space-4) 0 var(--space-4) var(--space-4);
    border-right: var(--border-dashed);
}
/* The tree's scroll region: the tree overflows here. Also the node the tree FAB
   moves into the Overlay, so font sizing lives here rather than on the aside. */
.tree-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: var(--space-2);
    font-size: var(--font-sm);
    /* Rows are click targets (navigate / toggle), not prose — suppress the
       text-selection highlight that double/drag clicks would otherwise leave. */
    user-select: none;
}

/* === Movie info box === */
.movie-info { margin: var(--space-3) 0; }
.movie-info::after { content: ""; display: block; clear: both; }
.movie-info .movie-poster {
    float: right;
    max-width: 200px;
    margin: 0 0 var(--space-3) var(--space-4);
}
.movie-info table { width: auto; }
@media (max-width: 600px) {
    .movie-info .movie-poster {
        float: none;
        display: block;
        margin: 0 auto var(--space-3);
    }
}

/* === Diary calendar === */
/* Header row: "Chronological" on the left, the [year ▾] dropdown pushed to the
   right. Composes with .row (flex + centering); space-between splits the two. */
.diary-cal .panel-header { justify-content: space-between; }
.diary-cal-drop .dropdown-menu { min-width: 0; }
/* Per-month caption above each grid, linking to that month's anchor. */
.diary-cal-month {
    font-size: var(--font-sm);
    margin: var(--space-3) 0 0.2rem;
}
.diary-cal-month a { color: var(--link); }
.diary-cal-month a:hover { color: var(--link-hover); }
.diary-cal-grid {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8rem;
    margin-bottom: 0.4rem;
}
.diary-cal-grid th, .diary-cal-grid td {
    text-align: center;
    padding: 0.1rem 0.15rem;
    font-weight: normal;
    color: var(--text-muted);
}
.diary-cal-grid td a { color: var(--link); display: block; }
.diary-cal-grid td a:hover { color: var(--link-hover); }
.diary-cal-grid td.cal-empty a { color: var(--text-muted); }
.diary-cal-grid td.cal-empty a:hover { color: var(--link-hover); }
.diary-cal-grid td.cal-today { background: var(--bg-panel); }
.diary-cal-grid td.cal-current,
.diary-cal-grid td.cal-current a { color: var(--primary-hover); }
.btn-block.cal-current { color: var(--primary-hover); }

/* === Fitness dashboard ===
   Server-rendered inline SVG charts. Geometry comes precomputed from Go;
   colors and strokes are applied here via classes so the inline SVG follows
   the theme palette. */
.fitness-chart { padding: var(--space-3); }
.fitness-chart-header { margin-bottom: var(--space-2); }
.fitness-range { width: auto; font-size: var(--font-sm); }
.fitness-empty {
    border: var(--border-dashed);
    color: var(--text-muted);
    text-align: center;
    padding: var(--space-5);
}
.fitness-svg { display: block; width: 100%; height: auto; }
.fitness-svg .chart-grid { stroke: var(--bg-panel-hover); }
.fitness-svg .chart-axis { stroke: var(--text-muted); }
.fitness-svg .chart-label { fill: var(--text-muted); font-size: var(--font-xs); }
.fitness-svg .chart-line { fill: none; stroke: var(--link); stroke-width: 1.5; }
.fitness-svg .chart-dot { fill: var(--link); }
.fitness-svg .chart-goal { stroke: var(--primary-hover); stroke-dasharray: 4 3; }
.fitness-svg .chart-goal-label { fill: var(--primary-hover); font-size: var(--font-xs); }

/* === Responsive === */
@media (max-width: 1100px) {
    /* Rails are not laid out inline on mobile — their content is surfaced
       through the Overlay via the stacked FABs. The <aside> elements stay in
       the DOM (their JS renders into them and the Overlay moves them in/out);
       we only pull them out of the shell flow here. */
    .tree-sidebar, .sidebar { display: none; }
    /* Compact three-column header: logo left, search stretches the middle,
       actions right. */
    header { grid-template-columns: auto 1fr auto; }
    .search-form { width: 100%; max-width: none; justify-self: stretch; }
    /* Reveal the mobile FAB stack (tree at the bottom, right rail above it).
       The search actions dropdown FAB moves to the upper slot too so it never
       overlaps the tree FAB. */
    button.fab { display: inline-flex; }
    .fab.dropdown { bottom: calc(var(--space-4) + 3rem + var(--space-2)); }
}

@media (max-width: 600px) {
    header, footer { padding: var(--space-2) var(--space-3); }
    main { padding: var(--space-4) var(--space-3); }
    .app-name {display: none;}
    .editor-cm { min-height: 50vh; }
    /* Editing on mobile is full-bleed: drop the main inset so the toolbar and
       editor use the entire viewport width. */
    body.edit-mode main { padding: 0; }
    /* Fingers, not cursors: give every toolbar control a ~44px tap target. */
    .editor-toolbar { gap: var(--space-2); padding: var(--space-2); }
    .editor-toolbar .btn-tool {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 2rem;
        min-height: 2rem;
        padding: 0 var(--space-1);
    }
    /* Pin the toolbar above the on-screen keyboard rather than at the top, which
       is out of thumb reach while typing. interactive-widget=resizes-content
       (layout.html viewport) shrinks the viewport on keyboard open so bottom: 0
       sits directly above it. cm-content reserves matching scroll space so the
       last lines aren't hidden behind the bar. */
    body.edit-mode .editor-toolbar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 50;
        border: none;
        border-top: var(--border);
        padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
    }
    body.edit-mode .cm-content {
        padding-bottom: calc(5rem + env(safe-area-inset-bottom));
    }
    .modal-backdrop { padding: var(--space-2); align-items: flex-start; }
    .modal { max-width: none; margin-top: var(--space-4); }
    .modal .panel-header { cursor: default; }
    /* On mobile, switch .list-item from a table row to a CSS grid so the
       meta cell wraps to its own line indented under the name. */
    .list-item {
        display: grid;
        grid-template-columns: 1.25rem 1fr;
        gap: 0 var(--space-3);
        padding: 0.6rem var(--space-4);
    }
    .list-item > td { padding: 0; }
    .list-item td.icon { grid-row: 1; grid-column: 1; }
    .list-item td.name { grid-row: 1; grid-column: 2; }
    .list-item td.meta { grid-row: 2; grid-column: 2; text-align: left; }
}
