/* AiB Platform — the tool web-app frame: the app grid (rail · stage ·
   panel), the sheet (side panel on wide screens, bottom sheet at 1020 and below),
   the result region and the code block. A tool page composes these; its
   own sheet only adds what is truly its own.

   Ladder: 1180 the three-column grid folds its rail into a strip above ·
   1020 every grid is one column and a .sheet leaves the flow as a bottom
   sheet · 860 / 719 the gaps tighten · 560 the file rows wrap (upload.css).
   Tracks are minmax(0, 1fr) and cells min-width 0 — WebKit hands a bare
   1fr cell its content's one-line width and pushes the page sideways. */

/* ---------- app grid ---------- */
.app-grid {
  /* per-page tuning without new CSS: set these on the grid */
  --app-rail: 236px;
  --app-panel: clamp(300px, 34%, 412px);
  --app-sticky-top: 84px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}
.app-grid > * { min-width: 0; }
.app-grid--rail-stage { grid-template-columns: var(--app-rail) minmax(0, 1fr); }
.app-grid--stage-panel { grid-template-columns: minmax(0, 1fr) var(--app-panel); }
.app-grid--rail-stage-panel { grid-template-columns: var(--app-rail) minmax(0, 1fr) var(--app-panel); }
/* the rail and a plain panel ride along while the stage scrolls */
.app-rail,
.app-panel { position: sticky; top: var(--app-sticky-top, 84px); }
.app-stage { min-width: 0; }

/* laptop: three columns are one too many — the rail becomes a strip
   across the top and its file queue scrolls sideways inside it. A box the
   keyboard cannot reach cannot be scrolled by it: when the queue's rows
   hold no focusable control, give the .file-queue tabindex="0" and an
   aria-label (as .code-block asks) */
@media (max-width: 1180px) {
  .app-grid--rail-stage-panel { grid-template-columns: minmax(0, 1fr) var(--app-panel); }
  .app-grid--rail-stage-panel > .app-rail { position: static; grid-column: 1 / -1; }
  .app-grid--rail-stage-panel > .app-rail .file-queue { display: flex; overflow-x: auto; margin-top: 0; padding-bottom: var(--space-1); }
  .app-grid--rail-stage-panel > .app-rail .file-row { flex: 0 0 auto; min-width: 210px; max-width: 300px; }
}
/* tablet & phone: one column — rail strip, stage, then the panel (or, as
   a .sheet, the panel leaves the flow and waits off-screen) */
@media (max-width: 1020px) {
  .app-grid--rail-stage,
  .app-grid--stage-panel,
  .app-grid--rail-stage-panel { grid-template-columns: minmax(0, 1fr); }
  .app-rail,
  .app-panel { position: static; }
  .app-grid--rail-stage > .app-rail .file-queue { display: flex; overflow-x: auto; margin-top: 0; padding-bottom: var(--space-1); }
  .app-grid--rail-stage > .app-rail .file-row { flex: 0 0 auto; min-width: 210px; max-width: 300px; }
}
@media (max-width: 860px) {
  .app-grid { gap: var(--space-5); }
}
@media (max-width: 719px) {
  .app-grid { gap: var(--space-4); }
  .app-rail .file-row { min-width: 180px; }
}

/* ---------- sheet ---------- */
/* Wide: a sticky paper side panel. At 1020 and below: a bottom sheet that exists
   only while open — off-screen and invisible (out of the tab order) until
   .is-open, then slides up; the grip and Close put it back (the runtime
   wires Escape and focus). It never peeks over the page. The z rung keeps
   it above the cookie pill. */
.sheet {
  position: sticky;
  top: var(--app-sticky-top, 84px);
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - var(--app-sticky-top, 84px) - 24px);
  max-height: calc(100dvh - var(--app-sticky-top, 84px) - 24px);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--paper);
  box-shadow: var(--shadow-card);
}
.sheet-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-5) 22px;
}
.sheet-grip,
.sheet-close { display: none; }

@media (max-width: 1020px) {
  .sheet {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-sheet);
    max-width: 560px;
    max-height: 82dvh;
    margin: 0 auto;
    border-bottom: 0;
    border-radius: var(--radius) var(--radius) 0 0;
    box-shadow: var(--shadow-sheet);
    /* the shadow's reach included, so nothing shows while closed */
    transform: translateY(calc(100% + 48px));
    visibility: hidden;
    transition: transform var(--dur-sheet) var(--ease-out), visibility 0s linear var(--dur-sheet);
  }
  .sheet.is-open { transform: none; visibility: visible; transition-delay: 0s; }
  .sheet-grip {
    display: block;
    flex: 0 0 auto;
    width: 100%;
    padding: 10px 0 6px;
    border: 0;
    background: none;
    cursor: pointer;
    /* the grip's swipe is the sheet's (the runtime closes on a pull down);
       without this a phone takes it as a page scroll */
    touch-action: none;
  }
  .sheet-grip::before {
    content: '';
    display: block;
    width: 44px;
    height: 4px;
    margin: 0 auto;
    border-radius: var(--radius-pill);
    background: var(--hairline-strong);
  }
  .sheet-close {
    display: block;
    position: absolute;
    top: 8px;
    right: 12px;
    padding: 6px 10px;
    border: 0;
    background: none;
    color: var(--grey);
    font-family: var(--font-mono);
    font-size: var(--fs-2xs);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    cursor: pointer;
    transition: color var(--dur-fast);
  }
  .sheet-close:hover { color: var(--ink); }
  .sheet-body { padding: var(--space-2) 18px calc(18px + env(safe-area-inset-bottom)); }
  /* an open sheet owns the screen: the page under it holds still while the
     runtime marks body.has-open-sheet. The lock sits on html — the document
     scrolls there, and base.css clips html's x-axis, so a body overflow
     would never reach the viewport. */
  html:has(> body.has-open-sheet) { overflow: hidden; }
}
@media (pointer: coarse) {
  .sheet-close { min-height: 40px; }
}

/* ---------- result ---------- */
/* The answer region (role="status" aria-live="polite", the runtime's
   [data-tool-result]): the verdict and one sentence first, then the
   detail, then what to do with it. Empty, it takes no room and no rule —
   but stays in the tree so the live region is there before the answer. */
.result {
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--hairline);
  overflow-wrap: anywhere;
}
.result:empty { margin: 0; padding: 0; border: 0; }
.result:not(:has(> *)) { margin: 0; padding: 0; border: 0; }
.result-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.result-summary { flex: 1 1 260px; min-width: 0; margin: 0; font-size: var(--fs-base); font-weight: 500; line-height: 1.45; }
.result-body { margin-top: var(--space-4); }
.result-body > :first-child { margin-top: 0; }
.result-body > :last-child { margin-bottom: 0; }
.result-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--hairline);
}
/* the head alone (a short verdict) or a callout in place of the head (the
   "could not check" answer) needs no action rule above it */
.result > .callout + .result-actions { border-top: 0; padding-top: 0; margin-top: var(--space-4); }

/* ---------- code block ---------- */
/* JSON, payloads, snippets: ink mono on paper, scrolling sideways inside
   its own box. Give it tabindex="0" when it can overflow, so the keyboard
   can scroll it too. */
.code-block {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: 0;
  text-transform: none;
  white-space: pre;
  overflow-x: auto;
  tab-size: 2;
}
.code-block code { font: inherit; }
.code-block:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
