/*
 * layout.css — ShadowDark DM Companion
 * Page shell, header, mode switcher, main content area, footer.
 * No color values here — all colors reference tokens from base.css.
 */

/* ============================================================
   Page shell
   ============================================================ */

.app-shell {
  /* Vertical-alignment fix (KDL 2026-06-27, Ken): the shell was a 4-row grid
     (`auto auto 1fr auto`) written for header / mode-bar / main / footer. But the
     breadcrumb bar (#app-breadcrumb) was later inserted as a real in-flow child
     BETWEEN the mode-bar and #app-content, making FIVE in-flow grid items against
     only four row tracks. Grid auto-placement then handed the single `1fr` stretch
     track to the BREADCRUMB (the 3rd item), so on sparse pages the breadcrumb
     ballooned to fill all leftover viewport height (~420–585px measured) and
     pushed #app-content — which fell into an implicit `auto` row — DOWN toward the
     footer. With lots of content #app-content filled the space and the bug hid.
     Switching to a flex column makes the growth row EXPLICIT on #app-content
     (flex:1 below) regardless of how many auto-sized chrome rows precede it, so
     content always top-aligns directly under the breadcrumb/mode-bar and the
     footer stays pinned to the bottom. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* The single growth row: #app-content expands to fill the leftover viewport
   height so the footer is pushed to the bottom, while its OWN content stays
   top-aligned (it is a normal block, no internal centering). min-height:0 keeps
   the existing Forge horizontal firewall (min-width:0 below) company — a flex
   item defaults to min-height:auto, which would let very tall content refuse to
   shrink; 0 lets it behave like the old 1fr track. */
.app-shell > #app-content {
  flex: 1 0 auto;
  min-height: 0;
  /* Horizontal firewall, generalized app-wide (Agatha 2026-07-01, mobile sweep).
     #app-content is a flex-column item and a flex item defaults to min-width:auto,
     so any descendant with a large min-content (a wide table, a long non-wrapping
     line, a filter rail) would grow this item PAST the viewport and give the whole
     PAGE horizontal scroll on phones. min-width:0 lets the item stay viewport-bound
     so wide content must distribute/scroll WITHIN its own container instead of
     widening the page. This was previously scoped to Forge only (dashboard); the
     same discipline now applies to every section (Bestiary, Campaigns, Maps,
     Oracle, Buildings, rosters, the builder wizard). Genuinely-wide elements still
     get their own overflow-x:auto wrappers so they scroll rather than clip. */
  min-width: 0;
}

/* ============================================================
   Header
   ============================================================ */

.app-header {
  /* SITE-WIDE top-rhythm tightening (KDL 2026-06-27, Ken): the bottom padding
     was the full --space-lg (~25.5px) and COMPOUNDED with the breadcrumb's top
     padding (~17px) below the mode bar, leaving a ~42px dead band between the
     wordmark and the breadcrumb on every page. Keep the top at --space-lg so the
     wordmark stays uncramped and legible; tighten the bottom to --space-sm so the
     header no longer adds a second full band. Chrome, applies app-wide. */
  padding: var(--space-lg) var(--space-xl) var(--space-sm);
  border-bottom: 1px solid var(--color-border);
}

.app-header__inner {
  max-width: 960px;
  /* #5 — left-anchored, not centered: keep the readable max-width but pin it to the
     left edge of the shell (logo/header reads from the left like the rest of the app). */
  margin: 0 auto 0 0;
  display: flex;
  align-items: baseline;
  gap: var(--space-lg);
  flex-wrap: wrap;
}

.app-title {
  font-family: var(--font-heading);
  font-size: var(--text-h1);
  font-weight: 700;
  color: var(--color-heading);
  letter-spacing: 0.06em;
  line-height: var(--lh-heading);
  cursor: pointer;
}

.app-title:hover {
  opacity: 0.8;
}

.app-subtitle {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  font-style: italic;
  line-height: 1;
}

/* ============================================================
   Mortar Line — the thin divider between header and mode bar
   Implemented via the header border-bottom above.
   The double-rule hr variant is available anywhere via <hr>.
   ============================================================ */

/* ============================================================
   Mode switcher bar
   ============================================================ */

.mode-bar {
  background-color: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  padding: 0 var(--space-xl);
}

.mode-bar__inner {
  /* Full-width row: content menus stay left-anchored (they sit at the start of
     the flex row), while the right-pushed Profile menu (margin-left:auto) lands
     flush to the viewport's right edge — minus only the .mode-bar horizontal
     padding (var(--space-xl)). The old 960px cap pinned Profile to the right of
     a 960px column, not the viewport, which is what Ken asked to fix. The header
     and footer keep their own 960px inner independently. */
  width: 100%;
  margin: 0;
  display: flex;
  gap: 0;
}

.mode-btn {
  /* Reset button defaults */
  appearance: none;
  background: none;
  border: none;
  cursor: pointer;

  /* Layout */
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-lg);

  /* Typography — Cinzel: nav labels are UI chrome, 1rem uppercase */
  font-family: var(--font-heading-ui);
  font-size: var(--text-h5);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--ls-cinzel-caps);
  color: var(--color-text-muted);

  /* Border — bottom accent line, inactive state */
  border-bottom: 3px solid transparent;

  /* Transition for the bottom border reveal */
  transition:
    color var(--transition-ui),
    border-color var(--transition-ui);
}

.mode-btn:hover {
  color: var(--color-text);
}

.mode-btn[aria-pressed="true"],
.mode-btn.is-active {
  color: var(--color-accent);
  border-bottom-color: var(--color-accent);
}

.mode-btn:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* Inline SVG icon inside mode button */
.mode-btn__icon {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  color: currentColor;
}

/* ============================================================
   Main content area
   ============================================================ */

#app-content {
  /* Fluid content shell: fill the viewport (minus the shell padding) instead of
     pinning to a fixed 960px. Grids (Treasure/Bestiary), the GM Screen columns,
     and most pages now use the available width and add columns on wider screens.
     Large-viewport accommodation (KDL 2026-06-30, Ken): the cap was 1600px, which
     left a dead band on big monitors. Raised to 2200px so wide content (card
     grids, GM Screen columns, item/roster lists) keeps growing into the available
     width on large displays; the `100% - 2*space-xl` term still gutters every
     viewport so nothing touches the edge. Reading-heavy pages (Lore RAW) keep
     their own tighter inner measure (below), and the two map BUILDERS go fully
     fluid (body.maps-editor below) where horizontal room matters most. */
  max-width: min(100% - 2 * var(--space-xl), 2200px);
  width: 100%;
  /* #5 — left-anchored content column (was centered via margin auto). */
  margin: 0 auto 0 0;
  /* SITE-WIDE top spacing (2026-06-23): tighten the top edge to --content-pad-top
     so pages sit close under the mode bar / breadcrumb; sides + bottom keep
     --space-xl. One token (base.css) drives this app-wide. */
  padding: var(--content-pad-top) var(--space-xl) var(--space-xl);
}

/* When the breadcrumb bar is VISIBLE (depth >= 2) it already supplies the top
   gap under the mode bar, so collapse #app-content's own top pad to avoid a
   double band. The bar lives immediately before #app-content in the shell. */
#app-breadcrumb:not([hidden]) + #app-content {
  padding-top: 0;
}

/* Forge (Characters) content firewall. #app-content is the 1fr row of the
   .app-shell grid, and grid items default to min-width:auto — so when a
   descendant has a large min-content (the dashboard topbar runs flex-wrap:nowrap
   with single-line identity meta), the grid track would expand past the viewport,
   giving the whole page horizontal scroll and defeating the dashboard's
   single-row "..." collapse (the topbar never sees overflow). min-width:0 lets
   the track stay viewport-bound so the dashboard's internal flex must distribute
   within it and the action buttons collapse as intended. Scoped to forge so no
   other section's layout is touched. (Measure-topbar revision 2026-06-07.) */
body[data-section="forge"] #app-content {
  min-width: 0;
}

/* Lore-only wider content column.
   The other sections (Forge / Roll Tables / Encounters / Tables / Bestiary)
   were designed around the 960px shell — leave them untouched. Lore's reading
   view runs a two-measure system (prose 62ch + tables/embeds 86ch, see
   lore.css); the 960px cap squeezed the reading leaf below 86ch so wide tables
   (Weapons 7-col, Titles, per-tier spells) had no room and hit the
   .sd-dtable__wrap horizontal scroll. `applySection` already mirrors the active
   section onto <body data-section>, so we scope off that stable hook — no JS
   change. 1360px gives the TOC rail (≤18rem) + gap + a reading leaf wide enough
   for the widest core table (Weapons, 7 columns incl. the 16rem Properties cell
   ≈ 858px) plus all padding, with no horizontal scroll at a ~1280px+ desktop;
   min(…, 100%) keeps it from forcing page-level horizontal overflow on narrow
   viewports (it shrinks to the viewport, where the ch-based prose/table measures
   self-disable and the .sd-dtable__wrap scroller remains the last-resort net). */
body[data-section="lore"] #app-content {
  max-width: min(1360px, 100%);
}

/* Map Builder workspace (v2) — like Lore, the Maps EDITOR is a full workspace
   tool (left toolbox rail + large central canvas + right legend) that the 960px
   reading shell squeezes. Give it a wider breakout column so the canvas plate is
   large and the three columns sit comfortably. min(…, 100%) avoids forcing
   page-level horizontal overflow on narrow viewports (the workspace stacks to a
   single column under 768px via maps.css).

   Scoped to body.maps-editor (NOT body[data-section="maps"]) so ONLY the editor
   gets the breakout — the Maps HOME / saved-maps selection page renders at the
   default 960px shell like the baseline pages (Forge, Encounters, Bestiary).
   maps.js toggles .maps-editor: added in renderMapsWorkspace, removed in
   renderMapsHome and on leaving the section in applySection. world_map.js sets
   the SAME body.maps-editor for the world-map builder (add line ~3561, remove
   ~3268), so this fluid breakout covers BOTH map builders.

   Large-viewport accommodation (KDL 2026-06-30, Ken): the cap was 1500px, which
   wasted real estate on large monitors for exactly the views that want the most
   horizontal room — the dungeon/map builder canvas plate and the world map. Drop
   the fixed cap and let the workspace use the full available width (the shell's
   #app-content padding still gutters the edges). On wide displays the canvas
   plate and rails get materially more room; the workspace still stacks to one
   column under 768px via maps.css, so small/medium screens are unchanged. */
body.maps-editor #app-content {
  max-width: 100%;
}

/* Mode-driven content transitions */
#app-content.is-transitioning {
  opacity: 0;
  transition: opacity var(--transition-ui);
}

#app-content.is-visible {
  opacity: 1;
  transition: opacity var(--transition-ui);
}

/* ============================================================
   Home screen — module grid
   ============================================================ */

.home-screen {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
}

.home-screen__heading {
  /* Cinzel: structural section label */
  font-family: var(--font-heading-ui);
  font-size: var(--text-h5);
  font-weight: 400;
  letter-spacing: var(--ls-cinzel-caps);
  color: var(--color-text-muted);
}

.module-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-lg);
}

/* Narrow viewports: single column */
@media (max-width: 540px) {
  .module-grid {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   Module view — when a module is active
   ============================================================ */

.module-view {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

.module-view__back {
  align-self: flex-start;
}

.module-view__title {
  font-family: var(--font-heading);
  font-size: var(--text-h2);
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--color-heading);
}

/* Shared inline tagline — one pattern used by EVERY section header so the
   title reads "[Title]  [tagline]" on one row, with the tagline immediately to
   the RIGHT of the title (muted Crimson Pro italic, smaller). It wraps under
   the title only when the row is too narrow. Mirrors the Lore .lore__subtitle
   treatment that predated this so the whole app shares one theme. */
.module-view__tagline {
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--text-base);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--color-text-muted);
  margin: 0;
}

/* Left group: pairs the title + tagline as a single baseline-aligned cluster
   so existing header actions (Create buttons, sort, search) stay pinned to the
   far right via the header's own justify-content: space-between. The group
   itself wraps internally (title -> tagline drops below) before the whole row
   wraps. */
.module-view__head-left {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-sm);
  row-gap: 0;
  min-width: 0;
}

/* ============================================================
   Footer
   ============================================================ */

.app-footer {
  border-top: 1px solid var(--color-border);
  padding: var(--space-md) var(--space-xl);
}

.app-footer__inner {
  max-width: 960px;
  margin: 0 auto 0 0;   /* #5 — left-anchored footer */
}

.app-footer__text {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  font-style: italic;
  line-height: 1.4;
  margin: 0;
}

.app-footer__link {
  color: var(--color-text-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 120ms ease-out;
}

.app-footer__link:hover,
.app-footer__link:focus-visible {
  color: var(--color-accent);
}

/* ============================================================
   Responsive adjustments
   ============================================================ */

/* Mobile/tablet content fills the viewport width.
   #app-content's desktop cap is `max-width: min(100% - 2*space-xl, 1600px)`. The
   `100% - …` is a calc()/min() expression, which makes the box's width INDEFINITE
   for resolving its block children's percentage widths. Result: a child sized
   `width: 100%` (e.g. .item-module / .char-module on the Item Forge + every list
   view) couldn't resolve a definite base and fell back to shrink-to-fit
   (max-content ≈ its widest row), so content filled only ~80% of the column and
   left a dead band on the right at phone widths (Ken's Item Forge screenshot).
   At ≤700px we drop the calc cap to a plain `100%` so the percentage base is
   definite again and content stretches; the existing #app-content padding (below)
   supplies the small symmetric gutters, so no horizontal overflow is introduced.
   Desktop (≥701px) keeps the capped, left-anchored reading column unchanged. */
@media (max-width: 700px) {
  #app-content {
    max-width: 100%;
  }
}

@media (max-width: 640px) {
  .app-header {
    padding: var(--space-md);
  }

  .app-header__inner {
    flex-direction: column;
    gap: var(--space-xs);
  }

  .app-title {
    font-size: var(--text-h2);
  }

  .mode-bar {
    padding: 0 var(--space-md);
  }

  #app-content {
    padding: var(--space-lg) var(--space-md);
  }

  .app-footer {
    padding: var(--space-md);
  }
}
