/* ==========================================================================
   PocketCorp Coder — product components
   Everything here is specific to building apps: the home composer, the build
   chat, the data grid, and the device preview. The shared chrome (sidebar,
   cards, forms, modals) lives in app.css.
   ========================================================================== */

/* ---------- Full-height views (Build, Preview, Data) ----------
   Those views own the viewport: the page itself never scrolls, the panel
   inside them does. Everything else scrolls normally. */

/* The body becomes the flex column so the mobile top bar takes its share and
   .app gets exactly the rest — otherwise a 100dvh .app plus a ~57px topbar
   overflows and pushes the chat composer off the bottom of the screen. */
body.view-fixed {
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

body.view-fixed .app { flex: 1; height: auto; min-height: 0; min-width: 0; }

/* The transcript renders whatever the agent emits. Every known shape is fixed
   at the source above; this clip guarantees an unforeseen one still cannot
   push the page sideways. `clip` (not `hidden`) leaves the panel's own
   internal scrolling — the tool bodies, the data grid — working. */
.chat, .chat-scroll { overflow-x: clip; }

body.view-fixed .content {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding-bottom: 0;
}

/* The Build / Data / Preview pages fill the viewport and scroll internally.
   `min-width: 0` at every level is load-bearing: a flex item defaults to
   `min-width: auto` (its min-content width), so without it one long agent
   string widens the page instead of wrapping inside the panel. */
.page--fill {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  flex: 1;
}

/* Vertical space is scarce in these views — the header gives some back. */
body.view-fixed .page-head { margin-bottom: 20px; }
body.view-fixed .page-sub { display: none; }

/* ---------- Home composer ---------- */

.hero {
  display: flex;
  flex-direction: column;
  gap: 26px;
  padding: 40px 0 12px;
  border-bottom: 1px solid var(--pc-border-muted);
  margin-bottom: 44px;
}

.hero-title {
  font-family: var(--pc-font-display);
  font-size: clamp(1.6rem, 4.4vw, 2.6rem);
  font-weight: 500;
  letter-spacing: var(--pc-track-tight);
  line-height: 1.25;
  margin: 0;
  max-width: 18ch;
}

.hero-sub {
  font-size: 0.74rem;
  line-height: 1.9;
  opacity: var(--pc-dim-2);
  max-width: 54ch;
  margin: -14px 0 0;
}

.composer {
  border: var(--pc-border-w) solid var(--pc-border);
  transition: border-color 0.3s var(--pc-ease);
  background: var(--pc-bg-subtle);
}

.composer:focus-within { border-color: var(--pc-border-strong); }

.composer-input {
  width: 100%;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: var(--pc-font-body);
  font-size: 0.82rem;
  line-height: 1.8;
  padding: 18px 20px 4px;
  resize: none;
  outline: none;
  min-height: 88px;
  max-height: 40vh;
  overflow-y: auto;
}

.composer-input::placeholder { color: inherit; opacity: 0.35; }

.composer-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 14px 12px 20px;
}

.composer-hint {
  font-size: 0.58rem;
  letter-spacing: var(--pc-track-tight);
  text-transform: uppercase;
  opacity: var(--pc-dim-3);
}

.composer-seeds {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.seed {
  font-family: var(--pc-font-body);
  font-size: 0.65rem;
  padding: 7px 13px;
  border: 1px solid var(--pc-border);
  background: transparent;
  color: inherit;
  cursor: pointer;
  opacity: var(--pc-dim-1);
  transition: all 0.25s var(--pc-ease);
  text-align: left;
}

.seed:hover { opacity: 1; border-color: var(--pc-border-hover); background: var(--pc-bg-hover); }

/* ---------- Theme picker (home page) ---------- */

.theme-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: -10px;
}

.theme-row-label {
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  font-weight: 500;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  opacity: var(--pc-dim-3);
  margin-right: 4px;
}

.theme-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 7px;
  border: 1px solid var(--pc-border);
  background: transparent;
  color: inherit;
  font-family: var(--pc-font-display);
  font-size: 0.58rem;
  font-weight: 500;
  letter-spacing: var(--pc-track-tight);
  text-transform: uppercase;
  cursor: pointer;
  opacity: var(--pc-dim-1);
  transition: all 0.25s var(--pc-ease);
}

.theme-chip:hover { opacity: 1; border-color: var(--pc-border-hover); }

.theme-chip.is-active {
  opacity: 1;
  border-color: var(--pc-ink);
  border-width: var(--pc-border-w);
  background: var(--pc-bg-subtle);
}

/* A miniature of the theme itself: its surface, its ink as the frame, its
   accent as the mark inside — so the choice is seen, not imagined. */
.theme-swatch {
  width: 20px;
  height: 20px;
  border: 1px solid;
  display: grid;
  place-items: center;
  flex: none;
}

.theme-swatch > span {
  width: 9px;
  height: 9px;
  display: block;
}

/* ---------- Theme preview ----------
   A drawn phone whose screen runs a miniature of the app the scaffolder
   actually produces: splash, top bar, off-canvas sidebar, FAB, avatar list.
   Everything inside is scoped to --tp-* variables set inline on .ph-screen, so
   a previewed theme can never leak into the dashboard's own tokens. */

.phone { --ph-w: 244px; --ph-h: 468px; display: flex; justify-content: center; }
.phone--compact { --ph-w: 200px; --ph-h: 384px; }

/* The device body is the dashboard's ink, not the theme's — it reads as a
   phone holding the app rather than as part of the design. */
.ph-frame {
  position: relative;
  width: var(--ph-w);
  height: var(--ph-h);
  /* Extra top padding is the bezel the speaker slot sits in — putting it
     there rather than over the screen means it contrasts with the device
     body and stays visible whatever colour the previewed app is. */
  padding: 19px 8px 9px;
  border-radius: 30px;
  background: var(--pc-ink);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
  flex: none;
  display: flex;
}

.ph-notch {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  width: 54px;
  height: 4px;
  border-radius: 2px;
  background: var(--pc-surface);
  opacity: 0.4;
  z-index: 6;
}

.ph-screen {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 21px;
  overflow: hidden;
  background: var(--tp-surface);
  color: var(--tp-ink);
  font-family: var(--tp-body);
  display: flex;
  flex-direction: column;
  /* The screen paints the previewed theme's own colours; the dashboard's dark
     mode must not invert anything inside it. */
  color-scheme: only light;
}

/* ---- splash: name over the surface, bar fills, whole thing lifts away ---- */

.ph-splash {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: var(--tp-surface);
  animation: ph-splash-lift 0.5s var(--pc-ease) 0.9s both;
}

.ph-splash-name {
  font-family: var(--tp-display);
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  animation: ph-splash-in 0.4s var(--pc-ease) both;
}

.ph-splash-bar {
  width: 84px;
  height: 2px;
  background: color-mix(in srgb, var(--tp-ink) 15%, transparent);
  overflow: hidden;
}

.ph-splash-bar i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--tp-accent);
  transform-origin: left;
  animation: ph-bar 0.85s var(--pc-ease) 0.1s both;
}

@keyframes ph-splash-lift {
  to { transform: translateY(-101%); }
}

@keyframes ph-splash-in {
  from { opacity: 0; transform: translateY(6px); }
}

@keyframes ph-bar {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* ---- top bar ---- */

.ph-topbar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 13px;
  border-bottom: var(--tp-line) solid var(--tp-ink);
  background: var(--tp-surface);
  z-index: 3;
}

.ph-burger {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  flex: none;
}

.ph-burger i {
  display: block;
  height: 2px;
  width: 100%;
  border-radius: 2px;
  background: var(--tp-ink);
}

.ph-topbar-title {
  flex: 1;
  font-family: var(--tp-display);
  font-size: 0.72rem;
  font-weight: 700;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- avatars ---- */

.ph-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  flex: none;
  display: grid;
  place-items: center;
  font-family: var(--tp-display);
  font-size: 0.55rem;
  font-weight: 700;
  /* --tp-who is set per row, so each person keeps their own colour. */
  background: var(--tp-who, var(--tp-accent));
  color: var(--tp-surface);
  border: var(--tp-line) solid var(--tp-ink);
}

.ph-avatar--me { background: var(--tp-accent); }

/* ---- list ---- */

.ph-body {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  padding: 10px 11px;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.ph-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 9px;
  background: var(--tp-paper);
  border: var(--tp-line) solid var(--tp-ink);
  border-radius: var(--tp-radius);
  /* A hard offset shadow, no blur — the sticker look. Themes that don't want
     it set --tp-lift to 0, which renders nothing. */
  box-shadow: var(--tp-lift) var(--tp-lift) 0 var(--tp-ink);
  flex: none;
}

.ph-row-text { min-width: 0; }
.ph-row-name { font-family: var(--tp-display); font-size: 0.6rem; font-weight: 600; }

.ph-row-note {
  font-size: 0.53rem;
  opacity: 0.6;
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Each row lifts into place; the delay is set inline so the list assembles. */
.ph-in { animation: ph-row-in 0.42s var(--pc-ease) both; }

@keyframes ph-row-in {
  from { opacity: 0; transform: translateY(11px); }
}

/* ---- floating action button ---- */

.ph-fab {
  position: absolute;
  right: 13px;
  bottom: 13px;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--tp-accent);
  color: var(--tp-surface);
  border: var(--tp-line) solid var(--tp-ink);
  display: grid;
  place-items: center;
  font-family: var(--tp-display);
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1;
  z-index: 4;
  box-shadow: var(--tp-lift) var(--tp-lift) 0 var(--tp-ink);
}

.ph-fab-in { animation: ph-fab-in 0.42s var(--pc-ease) both; }

@keyframes ph-fab-in {
  from { opacity: 0; transform: scale(0.4); }
}

/* ---- off-canvas sidebar ---- */

.ph-side {
  position: absolute;
  inset: 0 auto 0 0;
  width: 64%;
  z-index: 8;
  padding: 13px 0;
  background: var(--tp-surface);
  border-right: var(--tp-line) solid var(--tp-ink);
  transform: translateX(-100%);
  transition: transform 0.3s var(--pc-ease);
}

.ph-screen.is-open .ph-side { transform: translateX(0); }

.ph-side-head {
  font-family: var(--tp-display);
  font-size: 0.68rem;
  font-weight: 700;
  padding: 0 14px 11px;
  border-bottom: var(--tp-line) solid var(--tp-ink);
  margin-bottom: 8px;
}

.ph-side-link {
  padding: 8px 14px;
  font-size: 0.58rem;
  opacity: 0.65;
  border-left: 2px solid transparent;
}

.ph-side-link.is-active {
  opacity: 1;
  border-left-color: var(--tp-accent);
  background: color-mix(in srgb, var(--tp-accent) 10%, transparent);
}

.ph-scrim {
  position: absolute;
  inset: 0;
  z-index: 7;
  background: rgba(0, 0, 0, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s var(--pc-ease);
}

.ph-screen.is-open .ph-scrim { opacity: 1; pointer-events: auto; }

/* Soft confetti behind the content, matching the generated app's body. */
.ph-dots {
  background:
    radial-gradient(circle at 14% 12%, color-mix(in srgb, var(--tp-c2) 22%, transparent) 0 9px, transparent 10px),
    radial-gradient(circle at 86% 26%, color-mix(in srgb, var(--tp-c4) 20%, transparent) 0 7px, transparent 8px),
    radial-gradient(circle at 74% 76%, color-mix(in srgb, var(--tp-c3) 20%, transparent) 0 11px, transparent 12px),
    var(--tp-surface);
}

@media (prefers-reduced-motion: reduce) {
  .ph-side, .ph-scrim { transition: none; }
}

/* The picker: chips stacked in a column, the live preview beside them. A
   single wrapping row of chips left a tall void next to the preview; stacking
   makes the two columns roughly equal height and reads like a menu. */
.theme-pick {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}

.theme-pick .theme-row {
  flex-direction: column;
  align-items: stretch;
  gap: 5px;
  margin-top: 0;
}

.theme-pick .theme-chip { justify-content: flex-start; }

.theme-pick-preview {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 9px;
}

.theme-pick-caption {
  font-family: var(--pc-font-display);
  font-size: 0.52rem;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  opacity: var(--pc-dim-3);
}

@media (max-width: 760px) {
  /* Too narrow for two columns: chips go back to a wrapping row above the
     preview, which keeps the hero from becoming a tall scroll. */
  .theme-pick { grid-template-columns: 1fr; gap: 16px; }
  .theme-pick .theme-row { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
  .theme-pick .theme-chip { justify-content: center; }
  .theme-pick-preview { align-items: center; }
}

/* ---------- Create wizard ---------- */

.preset-grid--2 { grid-template-columns: repeat(2, 1fr); }

/* The DNS choices carry a sentence, not a logo, so they read left-aligned. */
.preset--wide {
  align-items: flex-start;
  text-align: left;
  gap: 6px;
  padding: 16px 16px 15px;
  cursor: pointer;
}

.preset--wide small {
  font-family: var(--pc-font-body);
  font-size: 0.6rem;
  line-height: 1.7;
  letter-spacing: 0;
  text-transform: none;
  opacity: var(--pc-dim-2);
}

.domain-preview {
  font-size: 0.68rem;
  padding: 11px 14px;
  border: 1px dashed var(--pc-border);
  opacity: var(--pc-dim-2);
  word-break: break-all;
}

/* ---------- App cards ---------- */

.app-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  text-decoration: none;
  color: inherit;
}

.app-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.app-card-name {
  font-family: var(--pc-font-display);
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: var(--pc-track-tight);
  margin: 0;
}

.app-card-domain {
  font-size: 0.62rem;
  opacity: var(--pc-dim-3);
  word-break: break-all;
  margin: 4px 0 0;
}

.app-card-desc {
  font-size: 0.7rem;
  line-height: 1.8;
  opacity: var(--pc-dim-2);
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.app-card-foot {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 0.58rem;
  letter-spacing: var(--pc-track-tight);
  text-transform: uppercase;
  opacity: var(--pc-dim-3);
  margin-top: auto;
  padding-top: 4px;
}

/* Status is line-work, not color — one live dot is the only exception. */
.dot {
  width: 6px;
  height: 6px;
  border: 1px solid currentColor;
  border-radius: 50%;
  flex: none;
}

.dot--live { background: var(--pc-ok); border-color: var(--pc-ok); animation: dot-pulse 1.6s infinite; }
.dot--on { background: currentColor; }

@keyframes dot-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

@media (prefers-reduced-motion: reduce) {
  .dot--live { animation: none; }
}

/* ---------- App sidebar header ---------- */

/* Sits inside .sidebar-nav, which has no horizontal padding of its own. */
.side-app {
  padding: 0 24px 18px;
  border-bottom: 1px solid var(--pc-border-muted);
  margin-bottom: 14px;
}

.side-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  opacity: var(--pc-dim-3);
  text-decoration: none;
  color: inherit;
  margin-bottom: 14px;
  transition: opacity 0.25s;
}

.side-back:hover { opacity: 1; }

.side-app-name {
  font-family: var(--pc-font-display);
  font-size: 0.86rem;
  font-weight: 500;
  letter-spacing: var(--pc-track-tight);
  margin: 0;
  word-break: break-word;
}

.side-app-meta {
  font-size: 0.58rem;
  opacity: var(--pc-dim-3);
  margin: 6px 0 0;
  display: flex;
  align-items: center;
  gap: 7px;
}

/* ---------- Build chat ---------- */

.chat {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  flex: 1;
  gap: 0;
}

.chat-scroll {
  flex: 1;
  min-height: 0;
  min-width: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 4px 4px 24px;
  display: flex;
  flex-direction: column;
  gap: 22px;
  scrollbar-width: thin;
}

.msg { display: flex; flex-direction: column; gap: 7px; max-width: 760px; min-width: 0; }

.msg-who {
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  font-weight: 500;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  opacity: var(--pc-dim-3);
}

.msg-body {
  font-size: 0.76rem;
  line-height: 1.9;
  min-width: 0;
  /* `anywhere`, not `break-word`: only this value lowers the element's
     min-content width, and that floor is what max-width cannot clamp. A single
     long path or URL from the agent would otherwise widen the whole page. */
  overflow-wrap: anywhere;
}

/* Code keeps its line structure — it scrolls in place instead of breaking. */
.msg-body pre,
.msg-body code {
  overflow-x: auto;
  overflow-wrap: normal;
  max-width: 100%;
}

.msg-body > :first-child { margin-top: 0; }
.msg-body > :last-child { margin-bottom: 0; }

.msg--user {
  align-self: flex-end;
  align-items: flex-end;
  max-width: min(620px, 88%);
}

.msg--user .msg-body {
  border: var(--pc-border-w) solid var(--pc-border);
  background: var(--pc-bg-subtle);
  padding: 12px 16px;
  white-space: pre-wrap;
  text-align: left;
}

.msg--error .msg-body {
  border-left: var(--pc-border-w) solid var(--pc-danger);
  padding-left: 14px;
  color: var(--pc-danger);
  white-space: pre-wrap;
}

/* A tool call and its result collapse into one line until you open it. */
.tool {
  border: 1px solid var(--pc-border-muted);
  max-width: 760px;
  min-width: 0;
  background: var(--pc-bg-subtle);
}

.tool-head {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-width: 0;
  padding: 9px 13px;
  background: transparent;
  border: 0;
  color: inherit;
  font-family: var(--pc-font-body);
  font-size: 0.65rem;
  cursor: pointer;
  text-align: left;
}

.tool-head:hover { background: var(--pc-bg-hover); }

.tool-name {
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  font-weight: 500;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  flex: none;
}

.tool-arg {
  opacity: var(--pc-dim-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
}

.tool-caret { flex: none; opacity: var(--pc-dim-3); transition: transform 0.25s var(--pc-ease); }
.tool.is-open .tool-caret { transform: rotate(90deg); }

.tool-body {
  border-top: 1px solid var(--pc-border-muted);
  padding: 12px 13px;
  font-size: 0.66rem;
  line-height: 1.8;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  overflow-x: auto;
  max-height: 380px;
  overflow-y: auto;
  opacity: var(--pc-dim-1);
}

.tool--error { border-color: var(--pc-danger); }
.tool--error .tool-name { color: var(--pc-danger); }

/* ---------- Chat attachments ---------- */

/* Sent with a message. */
.msg-files {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.att {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--pc-border);
  transition: border-color 0.25s var(--pc-ease);
}

.att:hover { border-color: var(--pc-border-hover); }

.att--image { padding: 0; overflow: hidden; line-height: 0; }

.att--image img {
  display: block;
  max-width: 220px;
  max-height: 180px;
  width: auto;
  height: auto;
  object-fit: cover;
}

.att--file {
  padding: 9px 13px;
  font-size: 0.66rem;
  background: var(--pc-bg-subtle);
  max-width: 260px;
}

.att--file span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Staged in the composer, not yet sent. */
.tray {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0 20px 4px;
}

.tray[hidden] { display: none; }

.tray-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px 5px 8px;
  border: 1px solid var(--pc-border);
  background: var(--pc-surface);
  font-size: 0.63rem;
  max-width: 220px;
}

.tray-item.is-error { border-color: var(--pc-danger); color: var(--pc-danger); }

.tray-item img {
  width: 26px;
  height: 26px;
  object-fit: cover;
  display: block;
  flex: none;
}

.tray-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: var(--pc-dim-1);
}

.tray-x {
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  opacity: var(--pc-dim-3);
  font-size: 0.7rem;
  line-height: 1;
  padding: 4px;
  flex: none;
}

.tray-x:hover { opacity: 1; color: var(--pc-danger); }

/* Drag-and-drop target: the whole chat, so a dropped file lands wherever the
   user aims. The outline is drawn on a pseudo-element to avoid reflow. */
.chat.is-dropping { position: relative; }

.chat.is-dropping::after {
  content: 'Drop to attach';
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  pointer-events: none;
  border: var(--pc-border-w) dashed var(--pc-border-strong);
  background: color-mix(in srgb, var(--pc-surface) 88%, transparent);
  font-family: var(--pc-font-display);
  font-size: 0.6rem;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
}

/* Live token stream — replaced by the settled message when the block closes. */
.chat-live { max-width: 760px; min-width: 0; }
.chat-live:empty { display: none; }

.chat-thinking {
  font-size: 0.7rem;
  line-height: 1.9;
  opacity: var(--pc-dim-3);
  font-style: italic;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.chat-status {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  opacity: var(--pc-dim-2);
  padding: 2px 0 4px;
}

.chat-status[hidden] { display: none; }

.spinner {
  width: 9px;
  height: 9px;
  border: 1.5px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
  flex: none;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 3s; }
}

.chat-foot {
  flex: none;
  min-width: 0;
  padding: 14px 0 18px;
  background: var(--pc-surface);
  border-top: 1px solid var(--pc-border-muted);
}

/* ---------- Data tab ---------- */

.data-layout {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 230px minmax(0, 1fr);
  gap: 28px;
}

/* With no tables there is nothing to pick, so the panel takes the full width. */
.data-layout.is-empty { grid-template-columns: 1fr; }

.table-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow-y: auto;
  min-height: 0;
  padding-bottom: 24px;
}

.table-link {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 12px;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: var(--pc-font-body);
  font-size: 0.7rem;
  cursor: pointer;
  text-align: left;
  border-left: 2px solid transparent;
  transition: all 0.2s var(--pc-ease);
}

.table-link:hover { background: var(--pc-bg-hover); }

.table-link.is-active {
  border-left-color: var(--pc-ink);
  background: var(--pc-bg-hover);
}

.table-link small { opacity: var(--pc-dim-3); font-size: 0.58rem; flex: none; }

.table-link--sql { margin-top: 12px; opacity: var(--pc-dim-2); }
.table-link--sql:hover { opacity: 1; }

.data-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  gap: 14px;
  padding-bottom: 24px;
}

.data-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  flex: none;
}

.data-bar .grow { flex: 1; }

.table-wrap {
  flex: 1;
  min-height: 0;
  overflow: auto;
  border: 1px solid var(--pc-border-muted);
}

.dtable {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.68rem;
}

.dtable th, .dtable td {
  border-bottom: 1px solid var(--pc-border-muted);
  border-right: 1px solid var(--pc-border-muted);
  padding: 0;
  text-align: left;
  vertical-align: top;
}

.dtable th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--pc-surface);
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  font-weight: 500;
  letter-spacing: var(--pc-track-tight);
  text-transform: uppercase;
  padding: 10px 12px;
  white-space: nowrap;
  border-bottom-width: var(--pc-border-w);
}

.dtable th .pk { opacity: var(--pc-dim-3); margin-left: 5px; }

.dtable td.actions { padding: 0 4px; white-space: nowrap; text-align: right; }

.cell {
  width: 100%;
  min-width: 90px;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: var(--pc-font-body);
  font-size: 0.68rem;
  padding: 9px 12px;
  outline: none;
  resize: none;
  line-height: 1.6;
}

.cell:focus { background: var(--pc-bg-hover); box-shadow: inset 0 0 0 1.5px var(--pc-border-strong); }
.cell.is-dirty { background: var(--pc-bg-hover); box-shadow: inset 2px 0 0 var(--pc-ink); }
.cell.is-null::placeholder { opacity: 0.3; font-style: italic; }

.row-btn {
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  opacity: var(--pc-dim-3);
  padding: 6px 8px;
  font-size: 0.7rem;
  line-height: 1;
}

.row-btn:hover { opacity: 1; }
.row-btn--danger:hover { color: var(--pc-danger); }

.pager {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 0.6rem;
  letter-spacing: var(--pc-track-tight);
  text-transform: uppercase;
  opacity: var(--pc-dim-2);
  flex: none;
}

.pager .grow { flex: 1; }

.sql-row { display: flex; gap: 10px; align-items: stretch; flex: none; }
.sql-row .input { font-size: 0.68rem; }

/* ---------- Preview tab ---------- */

.preview-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  flex: none;
  padding-bottom: 16px;
}

.preview-bar .grow { flex: 1; }

.seg {
  display: inline-flex;
  border: 1px solid var(--pc-border);
}

.seg button {
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  padding: 9px 16px;
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  opacity: var(--pc-dim-2);
  transition: all 0.25s var(--pc-ease);
}

.seg button + button { border-left: 1px solid var(--pc-border); }
.seg button:hover { opacity: 1; }
.seg button.is-active { background: var(--pc-ink); color: var(--pc-surface); opacity: 1; }

.preview-stage {
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding-bottom: 24px;
  background:
    repeating-linear-gradient(45deg,
      var(--pc-bg-subtle) 0 8px, transparent 8px 16px);
}

.device {
  background: var(--pc-surface);
  border: var(--pc-border-w) solid var(--pc-border);
  width: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.device--mobile {
  width: 390px;
  max-width: 100%;
  align-self: center;
  height: min(844px, 100%);
}

.preview-frame {
  flex: 1;
  width: 100%;
  border: 0;
  background: var(--pc-surface);
  min-height: 0;
}

.preview-log {
  font-size: 0.62rem;
  line-height: 1.7;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 190px;
  overflow: auto;
  border: 1px solid var(--pc-border-muted);
  padding: 12px 14px;
  opacity: var(--pc-dim-2);
  margin: 0;
}

/* ---------- Overview bits ---------- */

.kv {
  display: grid;
  grid-template-columns: minmax(110px, auto) minmax(0, 1fr);
  gap: 10px 20px;
  font-size: 0.7rem;
  align-items: baseline;
}

.kv dt {
  font-family: var(--pc-font-display);
  font-size: 0.55rem;
  font-weight: 500;
  letter-spacing: var(--pc-track);
  text-transform: uppercase;
  opacity: var(--pc-dim-3);
}

.kv dd { margin: 0; word-break: break-word; }

.file-list {
  display: flex;
  flex-direction: column;
  max-height: 340px;
  overflow-y: auto;
  font-size: 0.66rem;
}

.file-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 6px 0;
  border-bottom: 1px solid var(--pc-border-muted);
}

.file-row:last-child { border-bottom: 0; }
.file-row span:last-child { opacity: var(--pc-dim-3); flex: none; }

/* ---------- Responsive ---------- */

@media (max-width: 980px) {
  /* The table picker becomes a scrolling tab strip above the grid. `auto` for
     its row keeps it at content height; the grid takes whatever is left. */
  .data-layout {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr);
    gap: 14px;
  }

  .table-list {
    flex-direction: row;
    align-items: center;
    overflow-x: auto;
    overflow-y: hidden;
    padding-bottom: 6px;
    flex: none;
  }

  .table-link {
    border-left: 0;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    flex: none;
  }

  .table-link.is-active { border-left-color: transparent; border-bottom-color: var(--pc-ink); }
  .table-link--sql { margin-top: 0; margin-left: 8px; }
}

@media (max-width: 860px) {
  .hero { padding-top: 16px; margin-bottom: 32px; }
  .composer-input { min-height: 76px; font-size: 0.78rem; }
  .composer-bar { flex-wrap: wrap; gap: 10px; }
  .composer-hint { display: none; }
  .msg--user { max-width: 92%; }
  .device--mobile { width: 100%; height: 100%; }
  .preview-stage { background: none; padding-bottom: 16px; }
  body.view-fixed .content { padding-bottom: 0; }
  .chat-foot { padding-bottom: 14px; }
}
