/* The dashboard shell.
 *
 * One page, four regions, all of them on screen at once:
 *
 *   #bar     what you are doing to everything - intake and output
 *   #side    the plan, and the queue it applies to
 *   #stage   the image being looked at
 *   #facts   what happened to it, and how to change that
 *
 * This replaces a set of mutually exclusive screens. Nothing here appears or
 * disappears as a mode: the regions are fixed, and their contents go quiet when
 * there is nothing to say. That is the whole reason the arrangement is a grid of
 * named areas rather than a stack of views - a region cannot move house, so a
 * person only has to learn where a thing is once.
 *
 * Only this file positions anything. The region stylesheets style what is
 * inside their own region and never touch the shell.
 */

/* The app (#app: the bar and the dashboard) fills the first screen exactly,
   as it always has. The document itself is now allowed to be taller: past the
   app sits #about, the page's plain-words explanation of itself. Nothing about
   the app's own layout changed - the viewport-sized grid simply lives on #app
   instead of on body. */
body {
  height: auto;
  min-height: 100dvh;
  overflow-y: auto;
  overflow-x: clip;
}

#app {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  height: 100dvh;
}

/* ------------------------------- the about ------------------------------- */

/* Below the fold on purpose: the app answers "what do I do", this answers
   "what is this" for whoever scrolls to ask - people and crawlers alike. */
#about {
  border-top: 1px solid var(--c-line);
  background: var(--c-sunk);
  padding: var(--s-6) var(--s-4);
}
.about-inner {
  max-width: 680px;
  margin: 0 auto;
  display: grid;
  gap: var(--s-4);
}
#about h1 {
  font-size: 20px;
  line-height: 1.35;
  color: var(--c-ink);
}
/* The use-case pages' FAQ questions (generated by tools/gen_seo_pages.py).
   Reset from the 13px region-label style h2 normally carries, because these
   are prose headings, not chrome. */
#about h2 {
  font-size: 16px;
  line-height: 1.4;
  color: var(--c-ink);
  letter-spacing: 0;
  text-transform: none;
  margin-top: var(--s-2);
}
#about p {
  font-size: 15px;
  line-height: 1.6;
  color: var(--c-ink-2);
  margin: 0;
}
#about a { color: var(--c-ink-2); }

/* Without JavaScript the app is a dead shell; the one paragraph that exists
   says so, and says the privacy promise holds either way. */
#noscript {
  padding: var(--s-4);
  font-size: 15px;
  text-align: center;
  border-bottom: 1px solid var(--c-line);
}

/* ------------------------------- the bar --------------------------------- */

/* Wraps, and has to. The brand plus three nowrap buttons have a min-content width
   of about 500px, and flex items do not shrink below that - so on a 375px phone
   the bar silently propped the entire body grid open to 497px and every region
   under it inherited the overflow. Wrapping to a second line is the honest
   answer; shrinking the buttons would mean truncating the labels. */
#bar {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
  padding: var(--s-2) var(--s-4);
  border-bottom: 1px solid var(--c-line);
  background: var(--c-bg);
}

/* A button, because it opens the help card - but dressed as the wordmark it
   is. People expect a logo to lead somewhere. */
#bar .brand {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-weight: 600;
  color: var(--c-ink);
  text-decoration: none;
  font: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

/* Batch progress, as a hairline along the bottom edge of the bar. It belongs to
   the run rather than to any region, so it lives on the one element that outlives
   every selection.
   Anchored to the bar's own bottom edge rather than offset from its top by a
   guessed height - the guess was 41px against a bar that is 56px tall and taller
   still once it wraps, so the line was drawn floating inside the header. */
#batch {
  position: absolute;
  left: 0; right: 0;
  bottom: -1px;
  height: 2px;
  background: transparent;
  overflow: hidden;
  transition: opacity 0.2s linear;
}
/* Grown with a transform rather than a width. Animating width forces layout on
   every frame of a batch that is already saturating the machine; a scale on the
   compositor costs nothing. */
#batch > i {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--c-accent);
  transition: transform 0.2s linear;
}

/* ------------------------------ the regions ------------------------------ */

/* The sidebar breathes with the window: never below 300px, never past 384px,
   and the stage keeps the rest. The old fixed 320px was too tight for 16px
   type - labels wrapped three deep and the plan read as a ransom note. */
#dash {
  display: grid;
  /* --side-w is the person's own width for the panel, written by js/panels.js
     when the edge is dragged and remembered. Unset, the panel breathes with
     the window. */
  grid-template-columns: var(--side-w, clamp(300px, 26vw, 384px)) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) auto;
  grid-template-areas:
    "side stage"
    "side facts";
  min-height: 0;
}

/* ---- focus mode: the comparison, and nothing else -----------------------
   Entered and left with F (or the button on the stage). The regions are not
   destroyed, just out of the way - the plan keeps running the queue. */
body[data-focus="1"] #side,
body[data-focus="1"] #facts,
body[data-focus="1"] #about { display: none; }
body[data-focus="1"] #dash {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "stage";
}

/* ---- the person's own panel sizes ---------------------------------------
   Two handles, written as real separators: draggable with a pointer,
   steppable with arrow keys. Hidden on one-column layouts, where there is
   nothing beside anything to trade space with. */
.pane-handle {
  position: absolute;
  z-index: 5;
  background: transparent;
  transition: background-color var(--dur-fx) var(--ease-fx);
}
.pane-handle:hover,
.pane-handle:focus-visible,
.pane-handle[data-dragging="1"] { background: var(--c-accent); opacity: 0.5; }
#side-handle {
  top: 0;
  bottom: 0;
  right: -3px;
  width: 6px;
  cursor: col-resize;
}
#facts-handle {
  left: 0;
  right: 0;
  top: -3px;
  height: 6px;
  cursor: row-resize;
}
#side, #facts { position: relative; }

/* Pictures first, then the plan, then the one line for the command line.
 *
 * A flex column, deliberately, for two reasons a grid got wrong:
 *
 *   Width - a grid's implicit column is sized by max-content, so one
 *   unwrappable child (the empty state's sentence) silently widened EVERY
 *   region past the sidebar's own track and the stage painted over the
 *   overhang: text sliced mid-word at the panel edge, and a sideways scroll
 *   on phones. Flex cross-axis stretch is exact - children get the sidebar's
 *   width and wrap inside it.
 *
 *   Height - min-height: 0 rows in a height-constrained grid SQUASH instead
 *   of scrolling, and the queue section collapsed to zero with its centred
 *   content spilling over the plan. Here the queue is the one flexible child;
 *   when it cannot fit, the sidebar itself scrolls rather than stacking
 *   regions on top of each other.
 */
#side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  overflow-y: auto;
  /* Never a horizontal scrollbar: anything that cannot fit the panel's width
     wraps or is cut, it does not widen the panel's scroll range. */
  overflow-x: clip;
  border-right: 1px solid var(--c-line);
  background: var(--c-sunk);
}

/* The section label stays while its fields scroll under it, so you always
   know which region you are adjusting. */
#plan-sec > .region-head {
  position: sticky;
  top: 0;
  background: var(--c-sunk);
  z-index: 2;
}
#side > * { min-width: 0; flex: 0 0 auto; }
/* The queue grows into whatever is spare, shrinks to a floor a few rows tall
   (its list scrolls inside), and past that the sidebar scrolls. A floor of 0
   would let flex squash it out of existence on a short window - the exact
   collapse this layout exists to prevent. */
#queue-sec { flex: 1 1 auto; min-height: 200px; }
/* An empty queue is a button and two sentences, not a region-sized void: it
   sits compact, the plan follows immediately, and the leftover space falls
   after the command-line note instead of between the two things a first-time
   visitor has to read in sequence. */
#side:has(#queue-list[hidden]) #queue-sec { flex: 0 0 auto; }
#side:has(#queue-list[hidden]) #cli-note { margin-top: auto; }

/* The pip-install pointer. Quiet, last, and never in the way. The install
   command has no spaces to break on, so it is allowed to break anywhere
   rather than prop the sidebar open. */
#cli-note {
  padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--c-line);
  font-size: 13px;
  overflow-wrap: anywhere;
}
#cli-note a { color: var(--c-ink-2); }

#stage {
  grid-area: stage;
  position: relative;
  min-height: 0;
  overflow: hidden;
  background: var(--c-sunk);
}

/* Capped, and it scrolls past the cap. The comparison is what the product is for,
   so the detail region is not allowed to grow into the stage's share - at 42vh a
   run whose chips wrapped to three rows left the picture with barely half the
   height it should have had. */
#facts {
  grid-area: facts;
  border-top: 1px solid var(--c-line);
  background: var(--c-bg);
  /* --facts-h is the person's own height for the evidence, written by
     js/panels.js from the top-edge handle. */
  max-height: var(--facts-h, 30vh);
  overflow-y: auto;
}

/* A region's own heading row: the label, then whatever acts on that region. */
.region-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-4) var(--s-4) var(--s-3);
}

/* The plan's fields share the heading's inset, so the labels line up under it
   instead of running into the window edge. */
#plan-fields { padding: 0 var(--s-4) var(--s-5); }

/* Each block inside #facts is a separate concern and says so with a rule above
   it. They are laid out in columns while there is room and stack when there is
   not, so no block is ever the reason the page scrolls sideways. */
.fact-blocks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 0;
  border-top: 1px solid var(--c-line);
}

/* Once there is room, the versions block takes half. Three equal columns wrapped
   seven chips onto four rows, which pushed the last of them below the region's
   scroll line - and the chips are the primary control, so needing to scroll to
   reach one is the control being hidden again by a different mechanism. */
/* minmax(0, ·) floors each track at zero: a bare fr cannot shrink an item
   below its min-content, so one long <option> in the override select was
   silently widening its column and squeezing the chips into a single file. */
@media (min-width: 1100px) {
  .fact-blocks { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); }
}
.fact-blocks > section {
  padding: var(--s-4);
  border-right: 1px solid var(--c-line);
}
.fact-blocks > section:last-child { border-right: 0; }

/* ------------------------------- narrow ---------------------------------- */

/* One column, in the order the work happens: what you are doing, then the
   picture, then the detail. The stage keeps a fixed share of the viewport so
   it never collapses to a sliver on a phone.

   body loses its fixed height here, and that line is the fix for the worst
   bug this file has shipped: with height: 100dvh kept, #dash stayed
   height-CONSTRAINED, min-height: 0 regions were squashed to fit instead of
   the page scrolling, the queue section collapsed to 0px, and its centred
   content painted on top of the plan. A one-column phone layout is a
   document, and a document's height is its content's. */
@media (max-width: 860px) {
  body { overflow: auto; height: auto; min-height: 100dvh; }
  /* Same reasoning, now one element down: a one-column phone layout is a
     document, and a document's height is its content's. */
  #app { height: auto; min-height: 100dvh; }

  /* An inline link in the about prose is a 19px-tall touch target; the floor
     is 44px. The padding grows the touch box and the negative margin hands
     the same pixels straight back to the text layout, so the prose reads
     exactly as before while the finger gets a full-height target. */
  #about a {
    display: inline-block;
    padding: 14px 6px;
    margin: -14px -6px;
  }

  #dash {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    grid-template-areas: "side" "stage" "facts";
  }

  #side {
    border-right: 0;
    border-bottom: 1px solid var(--c-line);
    overflow-y: visible;    /* the page scrolls; a nested scroll would fight it */
  }
  /* The queue list alone stays internally scrollable, capped so twenty rows
     do not push the picture below the fold. */
  #queue-list { max-height: 40vh; }

  #stage { height: 52vh; }
  #facts { max-height: none; overflow: visible; }

  /* One column: there is nothing beside anything to trade space with. */
  .pane-handle { display: none; }
}
