/* ============================================================================
   layout.css — app shell, header, navigation, and the section workbench grid
   ========================================================================== */

.app-header {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-5);
  background: color-mix(in srgb, var(--surface-0) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

.brand { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.brand-mark {
  width: 38px; height: 38px; flex: none;
  border-radius: var(--r-md);
  background: linear-gradient(140deg, var(--accent), var(--accent-2));
  box-shadow: var(--glow-accent);
  display: grid; place-items: center;
  color: var(--text-invert); font-weight: 800; font-size: 1.1rem;
}
.brand-text h1 { font-size: 1.02rem; letter-spacing: -0.01em; }
.brand-text p { font-size: var(--fs-xs); color: var(--text-faint); margin-top: 1px; }

.header-controls {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-4);
  flex: 1 1 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.header-controls .msg-field { min-width: 220px; flex: 1 1 240px; max-width: 340px; }
.header-controls .seed-field { width: 140px; }

.app-body {
  display: grid;
  grid-template-columns: var(--nav-w) minmax(0, 1fr);
  gap: 0;
  max-width: var(--maxw);
  margin: 0 auto;
  align-items: start;
}

/* ---- Sidebar nav ---------------------------------------------------------- */
.sidebar {
  position: sticky;
  top: var(--header-h);
  align-self: start;
  height: calc(100vh - var(--header-h));
  overflow-y: auto;
  padding: var(--sp-5) var(--sp-3) var(--sp-6) var(--sp-5);
  border-right: 1px solid var(--border-faint);
}
.nav-group + .nav-group { margin-top: var(--sp-4); }
.nav-group-title {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-faint);
  padding: 0 var(--sp-2);
  margin-bottom: var(--sp-2);
}
.nav-link {
  display: flex; align-items: center; gap: var(--sp-2);
  width: 100%;
  text-align: left;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  background: none;
  color: var(--text-dim);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.nav-link:hover { background: var(--surface-1); color: var(--text); }
/* "You are here" is the most-used state indicator in the exhibit, and every cue
   it had was both faint and colour-only: the tinted fill is 1.27:1 against the
   sidebar, the tinted border 2.54:1 against the sidebar and 1.99:1 against its
   own fill, and the label and index shift by 1.73:1 and 1.82:1. All under the
   3:1 that WCAG 1.4.11 Non-text Contrast asks of a component state, with nothing
   but hue to carry it (1.4.1). The segmented control had exactly this problem
   and was fixed with an accent edge; this is the same treatment, turned to the
   side the reader scans. The 3px bar is 10.39:1 against the sidebar and 8.15:1
   against the tinted fill, and — being the presence of an edge rather than a
   change of hue — it is a non-colour cue too. Fill, border and label colour stay
   as redundant reinforcement. (aria-current="page" is set in js/app.js, so the
   state was always exposed programmatically; this is the visual half.) */
.nav-link[aria-current="page"] {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--text);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  box-shadow: inset 3px 0 0 var(--accent);
}
.nav-link .nav-index {
  font-size: var(--fs-xs); color: var(--text-faint);
  width: 1.4em; text-align: right; flex: none;
}
.nav-link[aria-current="page"] .nav-index { color: var(--accent); }

/* ---- Main / sections ------------------------------------------------------ */
.app-main { min-width: 0; padding: var(--sp-6) clamp(var(--sp-4), 4vw, var(--sp-7)) var(--sp-8); }

.section { max-width: 1120px; margin: 0 auto; }
.section[hidden] { display: none; }

.section-header { margin-bottom: var(--sp-6); max-width: 76ch; }
.eyebrow {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--accent); margin-bottom: var(--sp-2); font-weight: 650;
}
.section-title { font-size: var(--fs-2xl); margin-bottom: var(--sp-2); }
.section-subtitle { font-size: var(--fs-md); color: var(--text-dim); margin-bottom: var(--sp-3); }
.section-lede { font-size: var(--fs-md); color: var(--text-dim); }

/* ---- The three-panel workbench ------------------------------------------- */
.workbench {
  display: grid;
  grid-template-columns: minmax(240px, 300px) minmax(0, 1fr) minmax(280px, 340px);
  gap: var(--sp-4);
  align-items: start;
}
.workbench > .panel { min-width: 0; }
.panel { display: flex; flex-direction: column; gap: var(--sp-4); }
.panel-left { position: sticky; top: calc(var(--header-h) + var(--sp-4)); }
.panel-right { position: sticky; top: calc(var(--header-h) + var(--sp-4)); }

/* Two-column fallback layouts for prose-heavy sections */
.prose-wide { max-width: 80ch; display: flex; flex-direction: column; gap: var(--sp-4); }
.split-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); align-items: start; }

/* ---- Responsive ----------------------------------------------------------- */
@media (max-width: 1180px) {
  .workbench { grid-template-columns: minmax(0,1fr); }
  .panel-left, .panel-right { position: static; }
}

/* A pinned panel taller than the space below the header cannot be scrolled to
   its own bottom — scrolling is what pins it — so its last control (usually
   Reset) sits below the fold with focus able to land on it unseen. Above 1180px
   the tallest left panel (DNS: six sliders, a toggle and a button) runs to about
   700px, so only stick when the viewport can actually hold it. Capping the panel
   and scrolling it instead would work too, but that turns it into a scroll
   container, which this project labels as a focusable region — markup this
   stylesheet cannot add.

   The threshold is arithmetic, not taste: the panel's sticky top is
   `--header-h + --sp-4` = 100px + 16px, so the tallest panel needs about 816px
   of viewport to be reachable while pinned. 800px is that number rounded down
   to something legible. It IS high — a 1440x900 laptop lands near 760px of
   viewport once browser chrome is subtracted, so a good share of ordinary
   desktop users get panels that scroll with the page rather than pinning. That
   is a deliberate trade, and it is the direction to err in: an un-pinned panel
   costs everyone a little convenience, while a pinned one with an unreachable
   Reset button costs some people the control entirely. Lower the number only by
   making the tallest panel shorter.

   Classified by the accessibility pass and recorded here so it is not
   re-litigated: this is an AUTHOR ASIDE, not user-facing content. Nothing the
   reader sees mentions pinned panels — the only "sticky" text in the exhibit is
   the protocol-hopping channel describing sticky host traffic, which is
   unrelated — so there is nothing here that has to survive a 320px viewport or
   400% zoom. It is a design rationale for a threshold, it belongs in the
   stylesheet next to the threshold, and it is already there. The arithmetic was
   re-checked when this was recorded: --header-h is 6.25rem (100px), --sp-4 is
   1rem, .panel-left/.panel-right stick at their sum (116px), so ~816px is the
   real requirement and 800px is it rounded down. */
@media (max-height: 800px) {
  .panel-left, .panel-right { position: static; }
}

@media (max-width: 960px) {
  /* Below this width the header's three control fields no longer fit beside the
     brand and wrap onto their own rows; at a 320px viewport (the 400%-zoom
     reflow test) they stack three deep and the header becomes taller than the
     whole viewport. Pinned, it would then leave no reachable content at all —
     WCAG 1.4.10 Reflow. Letting it scroll away costs nothing: the sidebar is
     already a static strip at this width, so nothing depends on the header
     staying put. --header-h goes to 0 so the offsets above collapse with it. */
  :root { --header-h: 0px; }
  .app-header { position: static; }

  .app-body { grid-template-columns: 1fr; }

  /* The desktop nav is four vertical columns. Laying those columns out
     side-by-side and panning them horizontally (the old `overflow-x: auto` +
     `min-width: max-content`) put roughly 810px of navigation in a 288px box and
     made the strip ~480px tall, with two of the four groups off-screen to the
     right and no affordance saying so — content that requires two-dimensional
     scrolling, which is what 1.4.10 forbids. Reflow it instead: each group
     becomes its own wrapping row of chips, so the nav gets shorter as well as
     scroll-free. */
  .sidebar {
    position: static; height: auto; width: 100%;
    border-right: none; border-bottom: 1px solid var(--border-faint);
    display: flex; flex-wrap: wrap; gap: var(--sp-2); overflow-x: visible;
    padding: var(--sp-3) var(--sp-4);
  }
  .nav-group {
    flex: 1 1 100%; min-width: 0;
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2);
  }
  .nav-group + .nav-group { margin-top: 0; }
  .nav-group-title { flex: none; margin-bottom: 0; padding: 0; }
  /* 4px + 4px + a 1.6 line box on --fs-sm clears the 24px minimum target of
     WCAG 2.2 SC 2.5.8 without the chips needing extra spacing. */
  .nav-link { width: auto; padding: var(--sp-1) var(--sp-2); }

  .split-2 { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .header-controls { justify-content: flex-start; }
  .header-controls .msg-field { max-width: none; }
  .section-title { font-size: var(--fs-xl); }
}

/* ---- Footer --------------------------------------------------------------- */
.app-footer {
  max-width: var(--maxw); margin: 0 auto;
  padding: var(--sp-6) clamp(var(--sp-4), 4vw, var(--sp-7));
  border-top: 1px solid var(--border-faint);
  color: var(--text-faint); font-size: var(--fs-sm);
  display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); justify-content: space-between;
}
.app-footer a { color: var(--text-dim); }

/* Per-channel nav glyph. Decorative — aria-hidden in the markup, and the
   section label remains the button's accessible name. */
.nav-icon { font-size: var(--fs-sm); line-height: 1; margin-right: 2px; opacity: 0.9; }
