/*
 * app.css — layout only. Every colour, size and space is a token from design.css.
 * @license LQD Research LLC   @author Scott Martin
 *
 * There is not one raw colour in this file, and `check-web.ts` fails the build
 * if one appears. That is the whole mechanism behind "ad-hoc CSS drifts": a
 * second stylesheet is where the drift happened last time, so this one is not
 * allowed to hold a value of its own.
 */

.shell {
  display: grid;
  grid-template-columns: var(--rail-w) var(--side-w) 1fr var(--plan-w);
  height: 100vh;
  overflow: hidden;
}
/* A room with no context collapses the track to zero — it does not HIDE the
   element. A hidden grid child leaves the grid, and everything after it moves up
   a column; that is how the plan panel once ate the whole window. */
.shell[data-side="none"] { grid-template-columns: var(--rail-w) 0 1fr var(--plan-w); }
.shell[data-side="none"] .side { overflow: hidden; border-right: none; }

/* ── Rail ── */
.rail {
  background: var(--surface-sunken);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column; align-items: center;
  padding-top: var(--space-2); gap: var(--space-1);
}
.rail button {
  width: 38px; height: 38px; padding: 0;
  border: 1px solid transparent; background: transparent;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-muted); border-radius: var(--radius);
}
.rail button:hover { background: var(--surface-hover); color: var(--ink); }
.rail button[aria-current="page"] {
  background: var(--accent-quiet); color: var(--accent); border-color: var(--accent-quiet);
}
.rail svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.6; }

/* ── Sidebar ── */
.side {
  background: var(--surface-sunken);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column; overflow: hidden;
}
.side-head { padding: var(--space-2); border-bottom: 1px solid var(--line); }
.side-head input { width: 100%; }
.side-body { overflow-y: auto; padding: var(--space-1); }
.side-item {
  display: block; width: 100%; text-align: left;
  border: none; background: transparent; border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2); color: var(--ink);
  font-family: var(--font-mono); font-size: var(--text-sm);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.side-item:hover { background: var(--surface-hover); }
.side-item[aria-current="true"] { background: var(--accent-quiet); color: var(--accent); }
.side-group { padding: var(--space-2) var(--space-2) var(--space-1); color: var(--ink-faint);
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; }

/* ── Main ── */
.main { display: flex; flex-direction: column; overflow: hidden; background: var(--surface-base); }
.top {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--line); background: var(--surface-raised);
}
.top h1 { margin: 0; font-size: var(--text-xl); font-weight: var(--weight-bold); color: var(--ink-strong); }
.top-right { display: flex; align-items: center; gap: var(--space-2); }
.conn { color: var(--ink-faint); font-size: var(--text-xs); }
.room { flex: 1; overflow: auto; padding: var(--space-4); }

/* ── Grid ──
   Radically familiar: click, arrows, tab to edit, click a header to sort. The
   write path is where this product is allowed to be unlike anything else; the
   grid is not. */
.grid { border-collapse: separate; border-spacing: 0; width: 100%; font-size: var(--text-sm); }
.grid th, .grid td {
  border-bottom: 1px solid var(--line);
  padding: 0 var(--cell-pad); height: var(--row-h);
  text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 320px;
}
.grid thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface-raised); color: var(--ink-muted);
  border-bottom: 1px solid var(--line-strong); cursor: pointer;
  font-weight: var(--weight-medium);
}
.grid thead th .type { color: var(--ink-faint); font-weight: var(--weight-normal); }
.grid tbody tr:hover td { background: var(--surface-hover); }
.grid td[data-dirty="true"] { background: var(--warn-bg); }
.grid td[aria-selected="true"] { outline: 2px solid var(--accent); outline-offset: -2px; }
.grid td.key { color: var(--accent); }
.grid td .null { color: var(--ink-faint); font-style: italic; }
.grid-wrap { background: var(--surface-raised); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: auto; max-height: calc(100vh - 190px); }

.bar { display: flex; align-items: center; gap: var(--gap); margin-bottom: var(--space-3); flex-wrap: wrap; }
.bar .grow { flex: 1; }
.muted { color: var(--ink-muted); }
.faint { color: var(--ink-faint); font-size: var(--text-xs); }

/* ── Plan panel ── */
.plan-panel {
  background: var(--surface-raised); border-left: 1px solid var(--line);
  display: flex; flex-direction: column; overflow: hidden;
}
.plan-head, .plan-foot {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--line);
}
.plan-foot { border-bottom: none; border-top: 1px solid var(--line); }
.plan-foot .primary { margin-left: auto; }
.plan-body { flex: 1; overflow-y: auto; padding: var(--space-2); }
.plan-cost { font-size: var(--text-xs); color: var(--ink-muted); }
.plan-empty { color: var(--ink-faint); padding: var(--space-4); text-align: center; }

.plan-card {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--space-2); margin-bottom: var(--space-2); background: var(--surface-base);
}
.plan-card header { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); }
.plan-card .intent { font-weight: var(--weight-medium); color: var(--ink-strong); flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plan-card pre {
  margin: var(--space-1) 0 0; padding: var(--space-2);
  background: var(--surface-sunken); border-radius: var(--radius-sm);
  font-size: var(--text-xs); overflow-x: auto; white-space: pre-wrap; word-break: break-word;
}
.plan-card .acts { display: flex; gap: var(--space-1); margin-top: var(--space-2); }
.finding { border-left: 2px solid var(--line-strong); padding-left: var(--space-2);
  margin-top: var(--space-2); font-size: var(--text-xs); }
.finding .head { display: flex; gap: var(--space-2); align-items: baseline; }
.finding code { color: var(--ink-strong); }
.finding .detail { color: var(--ink-muted); margin-top: 2px; }

/* ── Drawer ── */
.drawer {
  position: fixed; right: 0; top: 0; bottom: 0; width: 520px; z-index: 40;
  background: var(--surface-overlay); border-left: 1px solid var(--line-strong);
  box-shadow: var(--shadow-overlay); display: flex; flex-direction: column;
}
.drawer-head { display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-3); border-bottom: 1px solid var(--line); }
.drawer-body { overflow: auto; padding: var(--space-3); }

/* ── Palette ── */
.palette {
  position: fixed; top: 14vh; left: 50%; transform: translateX(-50%);
  width: min(620px, 92vw); z-index: 50;
  background: var(--surface-overlay); border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-overlay); overflow: hidden;
}
.palette input { width: 100%; border: none; border-radius: 0;
  padding: var(--space-3) var(--space-4); font-size: var(--text-lg); background: transparent; }
.palette-list { list-style: none; margin: 0; padding: 0; max-height: 46vh; overflow-y: auto;
  border-top: 1px solid var(--line); }
.palette-list li { padding: var(--space-2) var(--space-4); cursor: pointer;
  display: flex; gap: var(--space-3); align-items: baseline; }
.palette-list li[aria-selected="true"] { background: var(--accent-quiet); color: var(--accent); }
.palette-list .hint { margin-left: auto; color: var(--ink-faint); font-size: var(--text-xs); }

/* ── Toast: a status line, not an alert. It never blocks anything. ── */
.toast {
  position: fixed; bottom: var(--space-4); left: 50%; transform: translateX(-50%);
  background: var(--surface-overlay); border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-overlay); border-radius: var(--radius);
  padding: var(--space-2) var(--space-4); z-index: 60; max-width: 70vw;
}

/* ── Editor ── */
.sql-editor { width: 100%; min-height: 180px; resize: vertical;
  font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.5; }
.kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-1) var(--space-4); }
.kv dt { color: var(--ink-muted); }
.kv dd { margin: 0; font-family: var(--font-mono); }
.card { background: var(--surface-raised); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--space-3); margin-bottom: var(--space-3); }
.card h3 { margin: 0 0 var(--space-2); font-size: var(--text-md); color: var(--ink-strong); }

/* ═══════════════════════════════════════════════════════════════
   RESPONSIVE — the four-column shell, on a screen that has no room for it
   ═══════════════════════════════════════════════════════════════

   The desktop shell is rail · sidebar · room · plan panel. On a laptop that is
   four columns of about 1200px; on a phone it is four columns of nothing.

   ── The rule this section is written under ────────────────────────
   Collapse a TRACK, never hide a grid CHILD. `hidden` removes an element from
   the grid's flow and every child after it shifts one column left — which is
   how the plan panel once ate the whole window while the room vanished. Every
   breakpoint below sets `grid-template-columns` and nothing else, so the
   children stay exactly where the grid put them.

   ── And why the plan panel is the first thing to go ───────────────
   It is the one column that is empty most of the time: it holds changes
   somebody has staged and not yet applied, which on a phone is usually none.
   The sidebar goes second because every screen that needs it can also be
   reached from the screen itself. The rail is last, because it is the only way
   to get anywhere. */

/* A laptop. The plan panel becomes an overlay that the count still opens. */
@media (max-width: 1180px) {
  .shell { grid-template-columns: var(--rail-w) var(--side-w) 1fr 0; }
  .shell[data-side="none"] { grid-template-columns: var(--rail-w) 0 1fr 0; }
  .plan-panel {
    position: fixed; top: 0; right: 0; bottom: 0;
    width: min(var(--plan-w), 92vw);
    border-left: 1px solid var(--line);
    background: var(--surface-overlay);
    transform: translateX(100%);
    transition: transform 120ms ease-out;
    z-index: 5;
  }
  /* Opened by a state attribute, not by `hidden`: the panel must stay in the
     grid's flow, and an off-canvas element that is still in the tree is also
     still reachable by a screen reader, which is the point. */
  .shell[data-plan="open"] .plan-panel { transform: translateX(0); }
}

/* A tablet, or a narrow window. The sidebar's list moves into the screens that
   need it — every one of them offers its own picker — so the track goes to
   zero rather than the content going missing. */
@media (max-width: 860px) {
  .shell,
  .shell[data-side="none"] { grid-template-columns: var(--rail-w) 0 1fr 0; }
  .side { overflow: hidden; border-right: none; }
  .top { padding-left: var(--space-2); padding-right: var(--space-2); }
  /* The top bar's buttons lose their words and keep their titles, which is
     also what makes `check:a11y`'s accessible-name rule bite here: without the
     `title` these become three unnamed squares. */
  .top-right button { font-size: 0; }
  .top-right button::after { font-size: var(--text-sm); }
  #btn-developer::after { content: "Dev"; }
  #btn-density::after   { content: "◧"; }
  #btn-theme::after     { content: "◐"; }
  #btn-palette::after   { content: "⌘K"; }
}

/* A phone. The rail goes horizontal along the bottom, where a thumb is —
   still one grid, still the same four children, one of them re-flowed. */
@media (max-width: 560px) {
  .shell {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr var(--rail-w);
  }
  .shell,
  .shell[data-side="none"] { grid-template-columns: 1fr; }
  .rail {
    grid-row: 2; grid-column: 1;
    flex-direction: row; justify-content: space-around;
    border-right: none; border-top: 1px solid var(--line);
    padding-top: 0;
    /* More rooms than fit is the ordinary case in developer mode, so it
       scrolls sideways rather than wrapping into a second row that would eat
       the screen. */
    overflow-x: auto;
  }
  .side { grid-row: 1; grid-column: 1; overflow: hidden; height: 0; }
  .main { grid-row: 1; grid-column: 1; }
  .room { padding: var(--space-3); }
  /* A table wider than the phone scrolls INSIDE its own container. The page
     itself must never scroll sideways: a horizontal page scroll on a phone
     hides the primary action and there is no scrollbar to tell you it is
     there. */
  .grid-wrap, .s-scroll { max-width: 100%; overflow-x: auto; }
  .s-fields { grid-template-columns: 1fr; }
}

/* ── Developer mode ──────────────────────────────────────────────
   The rail is built from ROOMS and filtered in JS, so nothing here hides a
   room. This is only the affordance that says which mode you are in — a
   toggle whose state is invisible is a toggle people press twice. */
:root[data-developer="true"] #btn-developer {
  background: var(--accent-quiet);
  border-color: var(--accent);
  color: var(--accent);
}

/* ── Two classes that were used and never declared ────────────────
   `ghost` (a quiet button beside a primary one) and `explain-out` (where a
   cost's EXPLAIN lands in the plan panel) were written in `app.js` and defined
   in no stylesheet, so both rendered as the platform's defaults — a "quiet"
   button that was not quiet, and an EXPLAIN with no separation from the card
   above it. Found by the rule below them in `check-web.ts`, which now reads
   every class every script writes and fails on one no stylesheet declares. */
.ghost {
  background: transparent;
  border: 1px solid var(--line-strong);
  color: var(--ink-muted);
}
.ghost:hover { background: var(--surface-hover); color: var(--ink); }
.explain-out {
  margin-top: var(--space-2);
  padding: var(--space-2);
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}

/* ── The demo banner — §22 W4 ─────────────────────────────────────────
   Above the shell rather than over it. A visitor has to be told that this is a
   real product and that the roaster in it does not exist, and a banner that
   covers the thing it is describing is the pattern that trained everybody to
   dismiss banners unread.

   `--accent-quiet` rather than a warning colour: this is not a caution. It is
   the page introducing itself. */
.demo-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--accent-quiet);
  border-bottom: 1px solid var(--line);
}
.demo-banner-title {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-strong);
}
.demo-banner-body {
  flex: 1 1 20rem;
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}
.demo-banner-action {
  flex: 0 0 auto;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
}
.demo-banner-action:hover { background: var(--accent-hover); }

/* ── First run — §22 W5 ──────────────────────────────────────────────
   A `<label for>` rather than an `aria-label`: this form asks for a production
   database password, and a visible label is what makes the field clickable, the
   question readable when the placeholder is gone, and the answer checkable by
   `check:a11y` as a real association rather than a string on an attribute. */
.field-label {
  display: block;
  margin-top: var(--space-3);
  margin-bottom: var(--space-1);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-strong);
}
.field {
  display: block;
  width: 100%;
  max-width: 34rem;
  padding: var(--space-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  color: var(--ink);
  font-size: var(--text-sm);
}
.field:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.s-plan .hint {
  max-width: 34rem;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
.s-plan .primary { margin-top: var(--space-3); }

/* ── The product's own name and its legal links — D16, §22 W7 ────────
   Both come from `flowbase.setting` and neither is in the markup, so a rename is a
   row rather than a deploy. The footer is `hidden` until an operator has set
   something: an empty Terms link is worse than no link. */
.brand {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-muted);
  letter-spacing: 0.02em;
}
.legal {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
  padding: var(--space-2) var(--space-4);
  border-top: 1px solid var(--line);
  background: var(--surface-base);
  font-size: var(--text-xs);
}
.legal a { color: var(--ink-muted); text-decoration: none; }
.legal a:hover { color: var(--accent); text-decoration: underline; }

/* The company, beside the legal links. The product's name is a setting (D16);
   who makes it is not, so this is the one string in the footer that is a
   constant. */
.legal-by { color: var(--ink-faint); }
