/* Demetra shell layout — top bar / sidebar / main / drawer / footer.
 *
 * The grid container is `#demetra-shell` (the element rendered by app.js
 * carrying data-sidebar-collapsed / data-drawer-open / data-density). Its
 * parent `#root` is just the React mount point — given height: 100% so the
 * shell can fill the viewport via height: 100vh below.
 *
 * Earlier this CSS targeted `#root` directly, which broke the layout because
 * #root's only child is the wrapper div — all named grid areas went unused
 * and the map container collapsed to 0×0 (no tile fetches).
 */

/* Lock the page to the viewport — only the sidebar + drawer scroll vertically.
 * Pre-fix, html/body inherited overflow: visible from the user agent, so any
 * panel content slightly wider or taller than the shell (e.g. the sidebar's
 * 280 px content overflowing its 265 px scrollbar-trimmed column, or a long
 * inspector accordion stretching past the 1fr main row) made the entire
 * window pan up/down or left/right. The shell is a desktop-only fixed layout
 * (per knowledge/design/OLYMPUS_DESIGN_SYSTEM.md) — only the inner sidebar
 * and drawer should scroll, not the whole window. */
html, body, #root { height: 100%; overflow: hidden; }

#demetra-shell {
  display: grid;
  grid-template-rows: var(--topbar-h) 1fr var(--footer-h);
  grid-template-columns: var(--sidebar-w) 1fr var(--drawer-w);
  grid-template-areas:
    "topbar topbar topbar"
    "sidebar main drawer"
    "footer footer footer";
  height: 100vh;
}
#demetra-shell[data-sidebar-collapsed="true"] {
  grid-template-columns: var(--sidebar-w-collapsed) 1fr var(--drawer-w);
}
#demetra-shell[data-drawer-open="false"] {
  grid-template-columns: var(--sidebar-w) 1fr 0;
}
#demetra-shell[data-sidebar-collapsed="true"][data-drawer-open="false"] {
  grid-template-columns: var(--sidebar-w-collapsed) 1fr 0;
}

/* UX sweep item 4 — z-index was 30 (design-system §1.3 topbar tier). As a
 * grid item with a z-index the topbar forms a stacking context, so its
 * dropdowns (pillar switcher, user menu — .demetra-popover) were confined
 * to level 30 and painted *behind* the map overlays (z-index 1000-1001)
 * when they dropped below the bar. Raising the topbar above the map tier
 * lets its dropdowns win; still below modals (.demetra-modal-backdrop, 9999). */
.demetra-topbar  { grid-area: topbar;  background: var(--navy); color: #f6f7f9; display: flex; align-items: center; padding: 0 var(--space-4); gap: var(--space-4); z-index: 1100; }
/* Sidebar + drawer: vertical scroll only. overflow-x: hidden was previously
 * missing, so a 280 px column with a 15 px scrollbar (effective inner = 265)
 * would horizontally scroll any 280 px-wide content. The page-level lock
 * above hides the resulting outer pan, but the sidebar still felt
 * scroll-jittery without this. */
.demetra-sidebar { grid-area: sidebar; background: var(--bg-soft); border-right: var(--border-thin); overflow-y: auto; overflow-x: hidden; transition: width var(--dur-base) var(--ease-out); }
.demetra-main    { grid-area: main;    position: relative; overflow: hidden; }
.demetra-drawer  { grid-area: drawer;  background: var(--bg); border-left: var(--border-thin); overflow-y: auto; overflow-x: hidden; transition: width var(--dur-base) var(--ease-out); }
#demetra-shell[data-drawer-open="false"] .demetra-drawer { display: none; }
/* UX sweep item 4 follow-up — the footer Export/Help popovers (.demetra-popover,
 * opening upward via `bottom:100%`) share the topbar's stacking problem: the
 * footer had no z-index, so its popovers sat at the shared .demetra-popover
 * level (60), below the map overlays (z-index 1000-1001). Raising the footer
 * above the map tier lets its popovers win; symmetric with .demetra-topbar. */
.demetra-footer  { grid-area: footer;  background: var(--bg); border-top: var(--border-thin); display: flex; align-items: center; padding: 0 var(--space-4); gap: var(--space-4); font-size: var(--fs-sm); color: var(--muted); z-index: 1100; }

/* Topbar elements
   .switcher and .cmdk are rendered as real <button> elements (TopBar.js
   migrated 2026-05-01 from <span role="button" tabIndex=0>). Reset the
   default browser button border + force font/color inheritance so the
   visual design stays identical to the prior <span> rendering, while
   keyboard handlers + axe contracts come for free. Add a focus-visible
   outline so keyboard users can see where they are. */
.demetra-topbar .logo      { font-weight: 700; letter-spacing: 0.05em; font-size: var(--fs-md); }
.demetra-topbar .switcher  { background: var(--navy-deep); padding: var(--space-1) var(--space-2); border: 0; border-radius: var(--radius-sm); font: inherit; font-size: var(--fs-sm); color: inherit; cursor: pointer; }
.demetra-topbar .crumb     { color: #9ca3af; font-size: var(--fs-sm); }
.demetra-topbar .crumb b   { color: #fff; }
.demetra-topbar .right     { margin-left: auto; display: flex; gap: var(--space-2); align-items: center; }
.demetra-topbar .cmdk      { background: var(--navy-deep); padding: var(--space-1) var(--space-2); border: 0; border-radius: var(--radius-sm); font: inherit; color: #9ca3af; font-size: var(--fs-xs); cursor: pointer; }
.demetra-topbar .switcher:focus-visible,
.demetra-topbar .cmdk:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* Sidebar */
.demetra-sidebar .sb-section { padding: var(--space-2) var(--space-3); border-bottom: var(--border-thin); }
/* Phase 2.1 C5: explicit background/border reset. .sb-label is a <button>;
   without an explicit background, WebKit defaults to its UA #c0c0c0 button
   background, giving --muted (#4b5563) on it = 4.15:1 — failing AA. Setting
   background:transparent makes contrast match the sidebar surface across
   all browsers. */
.demetra-sidebar .sb-label { display: flex; align-items: center; justify-content: space-between; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); padding: var(--space-1) 0; background: transparent; border: none; }
.demetra-sidebar .sb-label.active { color: var(--navy); font-weight: 700; }
.demetra-sidebar .sb-label .chip { background: #e5e7eb; color: var(--charcoal); font-size: var(--fs-xs); padding: 1px 6px; border-radius: 10px; }

/* Drawer */
.demetra-drawer > .drawer-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3); border-bottom: var(--border-thin); }
.demetra-drawer > .drawer-head h2 { margin: 0; font-size: var(--fs-md); color: var(--navy); font-weight: 600; }
.demetra-drawer > .drawer-body { padding: var(--space-3); }

/* Footer */
.demetra-footer .right { margin-left: auto; display: flex; gap: var(--space-3); }
.demetra-footer a, .demetra-footer button { color: var(--charcoal); text-decoration: none; cursor: pointer; background: none; border: none; font-size: var(--fs-sm); }

/*
 * Overlay theming (QA finding C1, fix sweep 2026-05-02)
 * ------------------------------------------------------
 * Symptom: dropdowns + modals reported white-on-white.
 *
 * Diagnosis (per overlay):
 *
 *   1. Command palette  (CommandPalette.js)        -> uses DemetraModal
 *   2. Layer library    (AddLayerPanel.js)         -> uses DemetraModal
 *   3. Full report      (FullReport.js)            -> uses DemetraModal
 *      All three above rely on .demetra-modal. Pre-fix it set
 *      `background: var(--bg)` (#fff) but NO `color`. Children inherited
 *      `color: var(--ink)` from <body>, so contrast was correct against
 *      a white background — but inheritance-fragile. If the modal ever
 *      mounted inside a dark container (topbar, drawer-head with .navy
 *      colour, future portal anchor) the body's --ink override stops
 *      cascading and text becomes the parent's near-white color. Fix:
 *      explicit `color: var(--ink)` on .demetra-modal + head + body.
 *
 *   4. Switch-pillar dropdown   (TopBar.js .switcher)    -> NOT rendered
 *      pre-fix; `onSwitchPillar` was never wired in app.js. The trigger
 *      button existed but no menu surfaced. New: rendered as a
 *      .demetra-popover anchored under the trigger.
 *
 *   5. User menu               (TopBar.js "User ▾")      -> NOT rendered
 *      pre-fix; `onUserMenu` never wired. Same fix as #4.
 *
 *   6. Export menu             (Footer.js Export button) -> NOT rendered
 *      pre-fix; `onExport` was a no-op `() => {}`. Same fix.
 *
 *   7. Help & methodology popover (Footer.js ? button)   -> NOT rendered
 *      pre-fix; `onHelp` was `alert(...)`. Replaced with a
 *      .demetra-popover.
 *
 * Note: tokens.css has no `--text` token; the project uses `--ink` for
 * primary text (see `html, body` rule in tokens.css). All explicit
 * `color:` declarations below use --ink.
 *
 * Why a shared .demetra-popover class: dropdowns 4-7 above are absolute-
 * positioned divs (NOT modals — no backdrop, dismiss on outside click).
 * A shared class keeps spacing/shadow/typography uniform and — critically —
 * pins `background: var(--bg)` + `color: var(--ink)` so popovers are
 * readable regardless of which container they render inside. The topbar
 * has `color: #f6f7f9` set on its container; without explicit colour,
 * child popovers would inherit that near-white and become invisible on
 * the white popover surface.
 */

/* Modal */
/* UX sweep item 3 — z-index was 50 (design-system §1.3 modal tier). But
 * Demetra's Leaflet map overlays (.demetra-map-hud, .dm-map-legend, the
 * basemap switcher) sit at z-index 1000-1001 to clear Leaflet's own panes
 * (max 700), so at 50 the command palette and every other Modal.js dialog
 * opened *behind* the map chrome. 9999 clears the map tier and matches the
 * sibling backdrop class .demetra-modal-overlay (components.css). */
.demetra-modal-backdrop { position: fixed; inset: 0; background: rgba(15,23,42,0.4); z-index: 9999; display: flex; align-items: flex-start; justify-content: center; padding: var(--space-8); }
.demetra-modal { background: var(--bg); color: var(--ink); border-radius: var(--radius-lg); width: 100%; max-width: var(--modal-max-w); max-height: calc(100vh - var(--space-10)); overflow: auto; box-shadow: var(--shadow-lg); }
.demetra-modal-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-4); border-bottom: var(--border-thin); }
.demetra-modal-head h3, .demetra-modal-head h4 { color: var(--ink); margin: 0; }
.demetra-modal-body { padding: var(--space-4); color: var(--ink); }

/* Popover (shared dropdowns: switch-pillar, user menu, export, help).
 * Anchored absolutely inside a relatively-positioned wrapper. Pinned
 * background + colour so it stays readable regardless of parent
 * container colour (notably the topbar which sets near-white text).
 */
.demetra-popover {
  position: absolute;
  background: var(--bg);
  color: var(--ink);
  border: var(--border-thin);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--space-2);
  z-index: 60;
  min-width: 180px;
}
.demetra-popover [role="menuitem"] {
  display: block;
  color: var(--ink);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  background: transparent;
  border: none;
  width: 100%;
  text-align: left;
  font: inherit;
}
.demetra-popover [role="menuitem"]:hover,
.demetra-popover [role="menuitem"]:focus-visible {
  background: var(--bg-soft);
}
.demetra-popover__anchor {
  position: relative;
  display: inline-block;
}

/* Phase 2 — right rail
 *
 * UX sweep item 5 (2026-05-19): the rail is rendered unconditionally in the
 * React tree, but it had no `position` rule. Inside `.demetra-main`
 * (`position: relative; overflow: hidden`) the map fills the cell at
 * 100%×100%, so a statically-positioned flex sibling collapsed / was clipped
 * and only re-appeared after an unrelated reflow (e.g. opening a modal).
 *
 * Fix: pin the rail absolutely to the right edge of the map cell so it is
 * always visible above the Leaflet panes. z-index 1000 clears Leaflet's
 * default panes (z 400) + controls (z 700) — matching `.demetra-map-hud`.
 * A short slide-in keeps the first paint from feeling abrupt. */
.demetra-right-rail {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 1000;
  width: 48px;
  background: var(--surface-2, #fafbfc);
  border-left: 1px solid var(--border, #e3e3e8);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 0;
  gap: 12px;
  flex-shrink: 0;
  animation: demetra-right-rail-in var(--dur-base, 220ms) var(--ease-out, ease-out);
}
@keyframes demetra-right-rail-in {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
  .demetra-right-rail { animation: none; }
}
.demetra-right-rail .rail-icon {
  width: 36px; height: 36px;
  border: 1px solid var(--border, #c8c8d0);
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  color: var(--text-muted, #5b6370);
  padding: 0;
}
/* Active state uses --accent-deep (#3046b8) not --accent (#4a6cf7). The latter
   gives only 4.39:1 against white text (axe color-contrast violation; the
   `.icon-label` at 7.5px is normal-text territory, demanding ≥4.5:1).
   --accent-deep gives 7.80:1 — comfortably AA, with AAA-headroom too. */
.demetra-right-rail .rail-icon.active {
  background: var(--accent-deep, #3046b8);
  color: #fff;
  border-color: var(--accent-deep, #3046b8);
}
.demetra-right-rail .icon-label {
  font-size: 7.5px;
  margin-top: 1px;
  font-weight: 500;
}
.demetra-right-rail .badge-num {
  position: absolute;
  top: -6px; right: -6px;
  background: #d97706;
  color: #fff;
  font-size: 8px;
  border-radius: 10px;
  padding: 1px 5px;
  font-weight: 600;
  line-height: 1.2;
}
.demetra-right-rail .badge-dot {
  position: absolute;
  top: 2px; right: 2px;
  width: 8px; height: 8px;
  background: #d97706;
  border-radius: 50%;
  border: 1.5px solid #fff;
}
.demetra-right-rail .rail-icon:focus-visible {
  outline: 2px solid var(--focus, #2563eb);
  outline-offset: 2px;
}

/* Phase 2 — resize handle */
.demetra-resize-handle {
  flex-shrink: 0;
  background: transparent;
  position: relative;
}
.demetra-resize-handle.vertical {
  width: 4px; height: 100%; cursor: ew-resize;
  border-left: 1px solid var(--border, #d0d3da);
  border-right: 1px solid var(--border, #d0d3da);
}
.demetra-resize-handle.horizontal {
  width: 100%; height: 4px; cursor: ns-resize;
  border-top: 1px solid var(--border, #d0d3da);
  border-bottom: 1px solid var(--border, #d0d3da);
}
.demetra-resize-handle::after {
  content: '';
  position: absolute;
  background: var(--text-muted, #94a3b8);
  border-radius: 2px;
  opacity: 0.5;
}
.demetra-resize-handle.vertical::after {
  top: 50%; left: 0;
  width: 4px; height: 28px;
  transform: translateY(-50%);
}
.demetra-resize-handle.horizontal::after {
  left: 50%; top: 0;
  height: 4px; width: 28px;
  transform: translateX(-50%);
}
.demetra-resize-handle:hover::after { opacity: 1; background: var(--accent, #4a6cf7); }
.demetra-resize-handle:focus-visible {
  outline: 2px solid var(--focus, #2563eb);
  outline-offset: 2px;
}

/* Phase 3a follow-up: absolute placement on sidebar (right edge) +
   drawer (left edge). Both parents need position:relative; the handle
   sits over the panel border. z-index lifts above panel content so the
   pointer hits the handle, not whatever scrolled behind it. */
.demetra-sidebar { position: relative; }
.demetra-sidebar > .demetra-resize-handle.vertical {
  position: absolute; right: 0; top: 0; height: 100%; width: 6px;
  border-left: none; border-right: none; z-index: 5;
}
.demetra-sidebar.collapsed > .demetra-resize-handle.vertical { display: none; }
.demetra-drawer { position: relative; }
.demetra-drawer > .demetra-resize-handle.vertical {
  position: absolute; left: 0; top: 0; height: 100%; width: 6px;
  border-left: none; border-right: none; z-index: 5;
}

/* Phase 2 — sidebar collapse + rail */
.demetra-sidebar.collapsed { padding: 8px 0; }
.demetra-sidebar .sidebar-head {
  padding: 4px 8px;
  text-align: right;
  border-bottom: 1px solid var(--border, #e3e3e8);
}
.demetra-sidebar .sidebar-collapse-btn,
.demetra-sidebar .sidebar-expand-btn {
  width: 24px; height: 22px;
  border: 1px solid var(--border, #c8c8d0);
  border-radius: 3px;
  background: #fff;
  cursor: pointer;
  font-family: var(--mono, monospace);
  font-size: 12px;
  color: var(--text-muted, #5b6370);
}
.demetra-sidebar .sidebar-collapse-btn:focus-visible,
.demetra-sidebar .sidebar-expand-btn:focus-visible {
  outline: 2px solid var(--focus, #2563eb);
  outline-offset: 1px;
}
.demetra-sidebar.collapsed .sidebar-expand-btn { margin: 4px auto; display: block; }

/* Phase 2 Task C1 — recents pills in top bar.
   Mounted between the crumb and the right-aligned (.right) controls.
   Active pill uses the accent token so it stays in sync with the rest
   of the design system (dark top bar + light selection chip). */
.demetra-topbar .demetra-recents {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  margin-left: 12px;
  font-size: 11px;
}
.demetra-topbar .demetra-recents .label {
  color: var(--text-muted, #94a3b8);
  font-size: 10px;
}
.demetra-topbar .demetra-recents .recent-pill {
  background: rgba(255, 255, 255, 0.08);
  color: #c4d0ff;
  padding: 2px 8px;
  border-radius: 11px;
  border: none;
  cursor: pointer;
  font-family: var(--mono, monospace);
  font-size: 10px;
}
.demetra-topbar .demetra-recents .recent-pill:hover {
  background: rgba(255, 255, 255, 0.15);
}
.demetra-topbar .demetra-recents .recent-pill.active {
  background: var(--accent, #4a6cf7);
  color: #fff;
}
.demetra-topbar .demetra-recents .recent-pill:focus-visible {
  outline: 2px solid var(--focus, #2563eb);
  outline-offset: 2px;
}

/* Phase 2 Task C2 — keyboard-shortcuts help button.
   Sits between the ⌘K button and the User menu in the topbar's right slot.
   Slimmer than .cmdk so the `?` glyph reads as a help affordance, not a
   command-palette trigger. */
.demetra-topbar .help-btn {
  background: transparent; border: 1px solid rgba(255,255,255,0.2);
  color: #c4d0ff; padding: 2px 8px; border-radius: 3px;
  cursor: pointer; font-size: 11px; margin-left: 4px;
}
.demetra-topbar .help-btn:hover { background: rgba(255,255,255,0.1); }
.demetra-topbar .help-btn:focus-visible { outline: 2px solid var(--focus, #2563eb); outline-offset: 2px; }
