/* === 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; --overlay: rgba(0, 0, 0, 0.55); --border: 1px solid var(--secondary); --border-dashed: 1px dashed var(--secondary); --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(--link-hover); } .content a { color: var(--link); } .content a: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 ): 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-float {float: right;} .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[hidden] {display: none;} .danger { color: var(--danger); } .danger:hover { color: var(--danger-hover); } .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: var(--space-5) 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 h1:first-child { margin-top: 0; } .content h2, main > h2 { font-size: 1.4rem; border-bottom: var(--border-dashed); padding-bottom: var(--space-1); } .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; } /* === Embedded images === Wiki-style figure box: a bounded, framed thumbnail with an optional caption. The fixed width matches the 300px thumbnail request so the box never scales the image up. left/right float so body text wraps; center is a plain block. */ .embed { margin: var(--space-2) 0; width: 300px; max-width: 100%; padding: var(--space-2); background: var(--bg-panel); border: var(--border); } .embed-left { float: left; margin-right: var(--space-4); } .embed-right { float: right; margin-left: var(--space-4); } .embed-center { margin-inline: auto; } .embed .embed-link { display: block; } .embed img { display: block; width: 100%; height: auto; } .embed figcaption { margin-top: var(--space-2); color: var(--text-muted); font-size: var(--font-sm); line-height: 1.4; } /* === 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; } .actions-special > .btn {text-align: left;} /* Header actions carry an icon and a label: the mobile dropdown shows the label, the inline desktop bar (see responsive block) the icon. */ .btn-icon { display: none; } .btn-icon svg { display: block; } /* === 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; /* Keep the toolbar in reach on long pages: stick it to the top of the center column's scroll viewport (just under the header). Mobile overrides this to a keyboard-hugging bottom bar (see responsive block). */ position: sticky; top: 0; z-index: 30; } .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%; } /* Stretch the editable surface to fill the mount. Without this the contenteditable is only as tall as the text, so clicking in the empty region below a short document lands on the (non-editable) scroller and places no caret. Filling it means a click anywhere maps to the nearest position — the end of the document. */ .editor-cm .cm-content { min-height: 60vh; } /* === 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); } /* === 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; } /* === Optional Sidebar (right side) === */ .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; } .panel-sidebar { padding: var(--space-2) var(--space-3); font-size: var(--font-sm); border: none; } /* === Table of contents ===*/ .toc { float: right; width: 15rem; max-width: 45%; margin: 0 0 var(--space-3) var(--space-4); padding: var(--space-2) var(--space-3); font-size: var(--font-sm); max-width: 60vh; overflow-y: auto; } .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-close::before, .overlay-close::after { content: none; } .overlay-close:hover { background: var(--bg-panel-hover); color: var(--primary-hover); } .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-active > .tree-name { color: var(--secondary); } .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; } .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; } /* Tree sidebar (persistent navigation) */ .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); } .tree-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: var(--space-2); font-size: var(--font-sm); 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); } /* Calendar events and weight under a diary day heading. */ .diary-day-cal { margin: var(--space-3) 0 0; } .diary-day-cal p { margin: 0; } /* === Calendars === Header maintenance chip + dropdown, and the calendars folder page. */ .maint-toggle { display: inline-flex; align-items: center; } .maint-count { margin-left: 0.3rem; } .maint-toggle.is-idle { color: var(--text-muted); } .maint-menu { min-width: 20rem; max-width: calc(100vw - 2rem); padding: var(--space-2) var(--space-3); white-space: normal; } /* Two columns so dates line up; an empty when-cell keeps the grid intact. */ .maint-list { display: grid; grid-template-columns: max-content 1fr; column-gap: var(--space-2); row-gap: 0.15rem; font-size: var(--font-sm); } .maint-list > .muted { grid-column: 1 / -1; } .maint-list + .panel-header { margin-top: var(--space-3); } .maint-when { color: var(--text-muted); white-space: nowrap; } .maint-all { margin-top: var(--space-3); padding: 0.3rem 0 0; border-top: var(--border-dashed); } .cal-scroll { overflow-x: auto; } .cal-table .nowrap { white-space: nowrap; } .cal-error { color: var(--danger); font-size: var(--font-sm); } .cal-sync { margin-top: var(--space-3); } /* === 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) { .tree-sidebar, .sidebar { display: none; } header { grid-template-columns: auto 1fr auto; } .search-form { width: 100%; max-width: none; justify-self: stretch; } .actions-menu .btn-block { min-height: 2.75rem; padding: 0.8rem var(--space-4); border-top: var(--border-dashed); } .actions-menu > .btn-block:first-child, .actions-special > .btn-block:first-child { border-top: none; } .actions-menu .btn-block:hover, .actions-menu .btn-block:active { background: var(--bg-panel-hover); } } /* Show the actions menu items directly in the bar in desktop size */ @media (min-width: 1101px) { .actions-toggle, .actions-special {display: none;} .actions, .actions-menu, .actions.dropdown-menu.is-open {display: contents;} .actions-menu .btn-block { width: auto; padding: 0; align-items: center; } .actions-menu .btn-icon { display: inline-block; } .actions-menu .btn-label { display: none; } } @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; } .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); } body.edit-mode .editor-toolbar { position: fixed; left: 0; right: 0; top: auto; 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)); } body.edit-mode main { padding: 0; } .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; } .toc {float: none; width: auto; max-width: none; margin: 0 0 var(--space-4);} }