/* =====================================================================
   THE ASSISTANT, THE SEVERITY BAR, AND THE EXACT BENTO.

   Loaded last. Three corrections from Ram's review of 20 Sep 2026:

   1. No empty grid cells anywhere.
   2. The rendered PDF thumbnails are gone. At card size they were an
      unreadable grey rectangle that broke the dark palette, so the same
      information is now drawn in the site's own language.
   3. The assistant is on every page. It was live at /api/ask the whole
      time and the first v2 build simply did not include it, on a site
      whose entire pitch is AI search.
   ===================================================================== */

/*  The 3-column query that used to sit here was a byte-for-byte copy of
    the one in layout.css, which owns .bento. Two files declaring the same
    grid is a coin toss decided by load order. Only the TINT lives here. */
/* Alternate cells carry a faint tint so six equal tiles do not read as a
   spreadsheet. Nth-child on a 3-column grid gives a checker rhythm. */
.bento-cell:nth-child(2n) { background: var(--bg-2); }
.bento-cell:nth-child(2n):hover { background: var(--bg-3); }

/* ---- severity bar -------------------------------------------------- */
.sevbar {
  display: flex; height: 6px; gap: 2px; width: 100%;
}
.sevbar .seg { display: block; background: currentColor; min-width: 4px; }
.sevbar .s-critical { color: var(--sev-critical); }
.sevbar .s-high     { color: var(--sev-high); }
.sevbar .s-medium   { color: var(--sev-medium); }
.sevbar .s-low      { color: var(--sev-low); }
/*  One engagement was rated on its own report's scale, critical /
    warning / info, rather than C/H/M/L. Those two were dropped
    silently until 20 Sep 2026. Warning sits with high and info with
    low, which is their sense in that report. */
.sevbar .s-warning { color: var(--sev-high); }
.sevbar .s-info    { color: var(--sev-low); }
/* Counts sit beside the bar, so colour is never the only carrier of the
   information. Greyscale and colour-blind readers get the same data. */
.sevbar + .sev { margin-top: 10px; }

/* ---- case page panel (replaces the PDF render) --------------------- */
.case-panel { border: 1px solid var(--rule); padding: 22px 20px; }
.case-panel h2 {
  font: 500 10.5px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--dimmer); margin: 0 0 16px;
}
.case-panel-note {
  font: 400 11px/1.6 var(--mono); color: var(--dimmer); margin: 16px 0 18px;
}

/* ---- machine-view wordmark ----------------------------------------- */
/*  Set in the display face, in the signal colour. The page is otherwise
    entirely monospace, which is the part a machine cares about. */
/*  Scoped with .machine because `.machine p` sets a 12.5px monospace size
    for every paragraph on that page and, at one element plus one class,
    it outranks a bare `.m-wordmark`. */
/*  THE WORDMARK.

    Figlet block letters ("ANSI Shadow"), one line, "GROW WITH RAM".

    SIZING. Every row is exactly 99 characters. A monospace glyph is
    about 0.6em wide, so the block occupies roughly 59.4em. Sizing in vw
    makes it fill the measure and shrink with it instead of overflowing
    on a phone; the ceiling stops it outgrowing the 1040px content column
    on a wide screen.

    NO SCROLLBAR. `overflow-x: auto` on its own is a trap: per spec, when
    one axis is not `visible` the other computes to `auto` rather than
    staying visible. That gave the block a vertical scrollbar it had no
    use for, floating beside the art. Both axes are declared here, and
    the vertical one is hidden outright.

    line-height 1 because box-drawing rows have to touch, letter-spacing
    0 because any tracking separates the strokes and breaks the letters. */
.machine .ascii {
  font-family: var(--mono);
  font-size: clamp(3px, 1.5vw, 14px);
  line-height: 1;
  letter-spacing: 0;
  white-space: pre;
  overflow-x: auto;
  overflow-y: hidden;
  /*  The box-drawing glyphs overrun their line box by about two pixels,
      and `overflow-y: hidden` was shaving the bottom row. Padding rather
      than a taller line-height: anything above line-height 1 separates
      the rows and the letterforms come apart. */
  padding-bottom: 0.25em;
  color: var(--signal);
  margin: 0 0 30px;
}

/* ---- screen-reader only -------------------------------------------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* =====================================================================
   The assistant
   ===================================================================== */

.ai-dock {
  position: fixed; z-index: 96;
  left: max(16px, env(safe-area-inset-left));
  bottom: max(16px, env(safe-area-inset-bottom));
}
.ai-launch {
  font: 600 11px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase;
  background: var(--fg); color: var(--bg); border: 1px solid var(--fg);
  padding: 13px 18px; cursor: pointer; display: inline-flex; align-items: center; gap: 9px;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.ai-launch:hover { background: transparent; color: var(--fg); }
.ai-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--signal); flex: none;
}
/* The dot pulses only while the panel is shut, and only when motion is
   welcome. It is a "this is live" signal, not decoration. */
@media (prefers-reduced-motion: no-preference) {
  .ai-dot { animation: aipulse 2.6s ease-in-out infinite; }
  .ai-is-open .ai-dot { animation: none; }
}
@keyframes aipulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

.ai-panel {
  position: fixed; z-index: 97;
  left: max(16px, env(safe-area-inset-left));
  bottom: calc(max(16px, env(safe-area-inset-bottom)) + 58px);
  width: min(420px, calc(100vw - 32px));
  /*  A definite height, not just a max. The log is the flexible child and
      it needs a resolved height above it to scroll within. */
  height: min(62vh, 560px);
  display: flex; flex-direction: column;
  background: var(--bg-2); border: 1px solid var(--rule);
  box-shadow: 0 26px 70px rgba(0, 0, 0, 0.55);
}
.ai-panel[hidden] { display: none; }

.ai-head {
  flex: none;
  display: flex; gap: 14px; justify-content: space-between; align-items: flex-start;
  padding: 18px 18px 14px; border-bottom: 1px solid var(--rule-soft);
}
.ai-title {
  margin: 0 0 6px; font: 600 12px/1 var(--mono);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--fg);
}
.ai-sub { margin: 0; font-size: 0.8rem; line-height: 1.5; color: var(--dim); }
.ai-close {
  background: none; border: 0; color: var(--dim); font-size: 22px; line-height: 1;
  cursor: pointer; padding: 0 2px; flex: none;
}
.ai-close:hover { color: var(--fg); }

/*  min-height: 0 is the whole fix.
    A flex item will not shrink below its content size unless you say so,
    so `flex: 1 1 auto` with the default `min-height: auto` let the log
    grow past the panel instead of scrolling inside it. The answer spilled
    out of the top of the box, clipped mid-sentence, with a scrollbar that
    belonged to nothing. */
.ai-log {
  padding: 16px 18px; overflow-y: auto; display: grid; gap: 14px;
  align-content: start;
  flex: 1 1 auto; min-height: 0;
  overscroll-behavior: contain;
}
/*  A visible, styled scrollbar. The default overlay one was a floating
    sliver with no track, which read as a rendering fault. */
.ai-log { scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
.ai-log::-webkit-scrollbar { width: 10px; }
.ai-log::-webkit-scrollbar-track { background: transparent; }
.ai-log::-webkit-scrollbar-thumb { background: var(--rule); border: 3px solid var(--bg-2); }
.ai-msg p { margin: 0; font-size: 0.87rem; line-height: 1.6; }
.ai-you {
  justify-self: end; max-width: 85%;
  background: var(--bg-3); border: 1px solid var(--rule); padding: 10px 13px;
}
.ai-you p { color: var(--fg); }
.ai-bot { max-width: 95%; }
.ai-bot p { color: var(--dim); }
.ai-bot.is-thinking p { color: var(--dimmer); }
.ai-src {
  margin-top: 9px !important; font: 400 10.5px/1.5 var(--mono);
  color: var(--dimmer); border-top: 1px solid var(--rule-soft); padding-top: 8px;
}

.ai-suggest {
  flex: none;
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 0 18px 14px; border-bottom: 1px solid var(--rule-soft);
}
.ai-suggest .chip {
  text-transform: none; letter-spacing: 0; font-family: var(--sans);
  font-size: 11.5px; padding: 7px 10px; cursor: pointer; background: none;
}

.ai-form { flex: none; display: flex; gap: 8px; padding: 14px 18px 10px; }
.ai-form input {
  flex: 1 1 auto; min-width: 0;
  font: 400 14px/1.4 var(--sans); background: var(--bg); color: var(--fg);
  border: 1px solid var(--rule); border-radius: 0; padding: 11px 12px;
}
.ai-form input::placeholder { color: var(--dimmer); }
.ai-form input:focus { outline: none; border-color: var(--signal); }
.ai-form .btn { padding: 11px 16px; }
.ai-note {
  flex: none; margin: 0; padding: 0 18px 16px;
  font: 400 10px/1.5 var(--mono); color: var(--dimmer);
}

/* On a phone the panel is the screen. Anything narrower reads as a toy. */
@media (max-width: 560px) {
  .ai-panel {
    left: 8px; right: 8px; width: auto;
    bottom: calc(max(12px, env(safe-area-inset-bottom)) + 54px);
    max-height: 76vh;
  }
  /* The launcher and the Human/Machine toggle would otherwise sit on the
     same line and crowd each other. */
  .ai-launch { padding: 11px 14px; }
}
.ai-body p { margin: 0 0 9px; }
.ai-body p:last-child { margin-bottom: 0; }
.ai-body ul { margin: 0 0 9px; padding-left: 18px; }
.ai-body li { margin-bottom: 5px; }
.ai-body strong { color: var(--fg); font-weight: 600; }

/*  Once a question has been asked, the suggestions collapse and the head
    tightens. Both were fixed furniture eating the space the answer needs. */
.ai-panel.ai-started .ai-suggest { display: none; }
.ai-panel.ai-started .ai-sub { display: none; }
.ai-panel.ai-started .ai-head { padding-bottom: 12px; }
