*, *::before, *::after { box-sizing: border-box; } html, body, #root { height: 100%; margin: 0; } body { font-family: var(--font-body); font-weight: var(--font-weight-body); color: var(--color-text); background: var(--color-bg); line-height: 1.6; } h1, h2, h3, h4 { font-family: var(--font-heading); font-weight: var(--font-weight-heading); line-height: 1.25; } code, pre { font-family: var(--font-mono); font-weight: var(--font-weight-mono); } /* A pond's content root (ADR 0016): sets --font-* (via PondFontScope) so its * body text uses the pond's body font; headings and code re-resolve the same * variables through the global rules above. */ .pond-font-scope { font-family: var(--font-body); font-weight: var(--font-weight-body); } a { color: var(--color-accent); } button { font: inherit; } /* Layout skeleton */ .app { display: grid; /* minmax: the topbar row may grow when its controls wrap on narrow viewports (issue #165, WCAG 1.4.10). */ grid-template-rows: minmax(var(--topbar-height), auto) 1fr; height: 100%; } .app-body { display: flex; min-height: 0; /* Grid items default to a min-content minimum; without this the row can force the whole app wider than the viewport (issue #100). */ min-width: 0; } .topbar { display: flex; align-items: center; gap: var(--space-4); padding: 0 var(--space-4); /* Same #100 pattern as .app-body: without this the topbar's min-content width sizes the shared grid column and forces page-level horizontal scrolling on narrow viewports (issue #165, WCAG 1.4.10). */ min-width: 0; border-bottom: 1px solid var(--color-border); background: var(--color-bg); /* Own stacking context above the scrolling `.main` content: the nav comes before `.app-body` in the DOM, so without this the sticky editor toolbar (z-index 20 inside `.main`) paints over the nav's overflow "…" menu, hiding its entries. 30 > the toolbar's 20; modals (1100+) still win. */ position: relative; z-index: 30; } .topbar__brand { font-family: var(--font-heading); font-size: 1.1rem; color: var(--color-text); text-decoration: none; } .topbar__spacer { flex: 1; } /* Skip link (#166, WCAG 2.4.1): first tab stop, visible only on focus. */ .skip-link { position: absolute; left: -9999px; top: 0; z-index: 1200; padding: var(--space-2) var(--space-4); background: var(--color-accent); color: var(--color-accent-contrast); border-radius: 0 0 var(--radius) 0; text-decoration: none; } .skip-link:focus-visible { left: 0; } /* Narrow viewports (issue #165, WCAG 1.4.10): the topbar wraps onto a second row instead of pushing the page wider than the viewport; every control stays visible and reachable. The search button drops to its icon (the aria-label carries the name). The expanded sidebar becomes an overlay above the content — 256 px beside a 320 px viewport would leave the content a sliver and force page-level horizontal scrolling. */ @media (max-width: 40rem) { .topbar { flex-wrap: wrap; row-gap: 0; padding: var(--space-1) var(--space-2); } .topbar__search-text { display: none; } .app-body { position: relative; } .sidebar:not(.sidebar--collapsed) { position: absolute; inset: 0 auto 0 0; z-index: 25; box-shadow: 2px 0 8px rgb(0 0 0 / 0.15); } .sidebar-resizer { display: none; } } .sidebar { width: var(--sidebar-width); flex-shrink: 0; /* Anchor for the absolutely positioned resize handle (#166). */ position: relative; /* Column flex so the trash footer can pin to the bottom (margin-top: auto). */ display: flex; flex-direction: column; border-right: 1px solid var(--color-border); background: var(--color-bg-subtle); padding: var(--space-4); overflow-y: auto; transition: margin-left 0.18s ease-out, opacity 0.15s ease-out; } .sidebar--collapsed { margin-left: calc(-1 * var(--sidebar-width)); opacity: 0; } /* Drag handle on the sidebar's right edge (issue #99). */ .sidebar-resizer { /* Lives inside the nav landmark (#166); straddles the sidebar edge. */ position: absolute; top: 0; bottom: 0; right: -3px; width: 6px; cursor: col-resize; touch-action: none; background: transparent; z-index: 5; } .sidebar-resizer:hover, .sidebar-resizer:focus-visible { background: var(--color-accent); outline: none; } .sidebar__hint { color: var(--color-text-muted); font-size: 0.9rem; } .sidebar__header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-3); } .sidebar__pond-name { font-size: 1rem; margin: 0; } .sidebar__sort { font: inherit; font-size: 0.85rem; border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-bg); padding: var(--space-1) var(--space-2); } .sidebar__pages { list-style: none; margin: 0 0 var(--space-3); padding: 0; } /* Folder view (issue #108): the page tree with collapsible nodes. */ .sidebar__view-toggle { display: flex; gap: var(--space-1); margin-bottom: var(--space-2); } .sidebar__view-btn { font: inherit; font-size: 0.8rem; padding: var(--space-1) var(--space-2); border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-bg); color: var(--color-text-muted); cursor: pointer; } .sidebar__view-btn--active { color: var(--color-text); font-weight: 600; background: var(--color-surface); } /* Favorites (issue #132): the latching filter button carries a small star; golden treatment for the TopBar toggle and favorite tree icons. */ .sidebar__view-btn--favorites { display: inline-flex; align-items: center; gap: var(--space-1); } .sidebar__view-btn--favorites svg { width: 0.85rem; height: 0.85rem; color: var(--color-favorite); } .icon-button--favorite { color: var(--color-favorite); } .sidebar__tree-row { display: flex; align-items: center; gap: var(--space-1); min-width: 0; } .sidebar__tree-row .sidebar__page { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* In the tree, the nested children