/* UI Lab — app chrome. Editorial: Newsreader display over a warm pastel ground.
   The chrome runs entirely on tokens.css custom properties, which is what makes
   the composer's "theme UI Lab with this look" toggle a one-line style write. */

* { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  /* The shell is allowed to be wide because nothing inside it stretches —
     extra width buys more masonry columns, never fatter cards. Capped at six
     columns' worth, past which a page stops being scannable. */
  --shell-max: 2320px;
  --card-w: 352px;
  --card-gap: 20px;
}

/* The root element carries the background too, so the area outside <body>
   (overscroll, short pages) is never the browser's default white. */
html { scroll-padding-top: 92px; background: var(--background); }

body {
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

.skip-link {
  position: absolute; left: -9999px; top: 8px; z-index: 99;
  background: var(--primary); color: var(--primary-foreground);
  padding: 8px 14px; border-radius: 8px; font-size: var(--text-sm);
}
.skip-link:focus-visible { left: 8px; }

/* ── Topbar ─────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: 40;
  background: var(--background);
  border-bottom: 1px solid var(--border);
}
.topbar-inner {
  max-width: var(--shell-max); margin: 0 auto; padding: 14px 24px;
  display: flex; align-items: center; gap: 20px;
}
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; }
.brand-mark {
  width: 24px; height: 24px; border-radius: 7px;
  background-image: var(--gradient-horizon);
  border: 1px solid rgba(0, 0, 0, 0.06);
}
.brand-name { font-family: var(--font-display); font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.brand-name em { font-style: italic; font-weight: 500; color: var(--muted-foreground); }

.topnav { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; margin-left: 8px; }
@media (max-width: 760px) {
  .topbar-inner { flex-wrap: wrap; row-gap: 6px; }
  .topnav {
    order: 10; flex: 1 0 100%; flex-wrap: nowrap; margin-left: 0;
    overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none;
  }
  .topnav::-webkit-scrollbar { display: none; }
  .topnav a { flex: none; }
}
.topnav a {
  text-decoration: none; font-size: var(--text-sm); font-weight: 500;
  color: var(--muted-foreground); padding: 6px 10px; border-radius: 999px;
}
.topnav a:hover { color: var(--foreground); background: var(--muted); }
.topnav a[aria-current="page"] { color: var(--foreground); background: var(--muted); }
.topbar-spacer { flex: 1; }

.icon-btn {
  cursor: pointer; border: 1px solid var(--input); background: var(--card);
  color: var(--foreground); border-radius: 8px; padding: 6px 11px;
  font-size: var(--text-sm); font-weight: 500; font-family: inherit;
}
.icon-btn:hover { background: var(--muted); }
.icon-btn:disabled { opacity: 0.45; cursor: default; }
.icon-btn:disabled:hover { background: var(--card); }

/* ── Page layout ────────────────────────────────────────── */
.page { max-width: var(--shell-max); margin: 0 auto; padding: 36px 24px 80px; }

/* The shelf centers its column cluster, so the headline shifts with it —
   otherwise the h1 floats off to the left of the first card. masonry.js keeps
   --cluster-offset in sync; it's 0 when stacked. */
.page-head { margin-bottom: 28px; max-width: 720px; margin-left: var(--cluster-offset, 0); }
.eyebrow {
  display: flex; align-items: center; gap: 10px;
  font-size: 12px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted-foreground); margin-bottom: 10px;
}
.eyebrow::before { content: ""; width: 26px; height: 3px; border-radius: 2px; background-image: var(--gradient-horizon); }
.page-head h1 {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(30px, 4.5vw, 44px); line-height: 1.08; letter-spacing: -0.015em;
  margin-bottom: 12px;
}
.page-head .lede { color: var(--muted-foreground); font-size: var(--text-lg); line-height: 1.55; }

/* Builder pages: controls rail + preview column */
.builder { display: grid; grid-template-columns: 360px minmax(0, 1fr); gap: 28px; align-items: start; }
@media (max-width: 900px) { .builder { grid-template-columns: 1fr; } }

.rail { display: flex; flex-direction: column; gap: 16px; }
.stage { position: sticky; top: 92px; display: flex; flex-direction: column; gap: 16px; }
@media (max-width: 900px) { .stage { position: static; } }

/* ── Masonry shelf ──────────────────────────────────────────
   Applied by js/core/masonry.js once two columns fit. Cards sit on fixed
   --card-w tracks (so they never stretch), on an 8px row lattice with dense
   packing (so short cards fall up into the gaps tall ones leave). The rail /
   stage wrappers go transparent, which flattens the existing two-column
   markup into one card list without touching any page's HTML. */
.masonry.is-masonry {
  display: grid;
  justify-content: center;
  align-items: start;
  column-gap: var(--card-gap);
  row-gap: 0;                       /* the gutter lives in each card's row span */
  grid-auto-rows: 8px;
  grid-auto-flow: row dense;
}
.masonry.is-masonry .rail,
.masonry.is-masonry .stage,
.masonry.is-masonry .ctl-cards { display: contents; }
/* Stacked fallback: the wrappers still behave like the columns they were. */
.ctl-cards { display: flex; flex-direction: column; gap: 16px; }
.masonry.is-masonry .m-item { align-self: start; }
/* Nothing may push a track wider than its share — a long line in the generated
   CSS <pre> is the pre's problem to scroll, not the page's. Applies stacked
   too, where it kills a long-standing horizontal scroll on phones. */
.masonry, .masonry .rail, .masonry .stage, .masonry .ctl-cards, .masonry .m-item { min-width: 0; }
/* The thing you're looking at leads. Everything else falls in around it —
   `order` moves placement, not DOM order, so tab order is untouched. */
.masonry.is-masonry .preview-surface,
.masonry.is-masonry #mockup-frame { order: -1; }
/* Sticky can't survive display: contents, and doesn't need to — on a shelf
   the preview is already in view. */
.masonry.is-masonry > .stage { position: static; }

.panel {
  background: var(--card); border: 1px solid var(--border);
  border-radius: 12px; padding: 18px;
}
.panel > h2, .panel > h3 {
  font-size: var(--text-sm); font-weight: 600; margin-bottom: 12px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.panel .hint { font-size: var(--text-xs); color: var(--muted-foreground); line-height: 1.5; margin-top: 10px; }

.preview-surface {
  border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
  background:
    linear-gradient(45deg, var(--muted) 25%, transparent 25%, transparent 75%, var(--muted) 75%),
    linear-gradient(45deg, var(--muted) 25%, transparent 25%, transparent 75%, var(--muted) 75%);
  background-size: 20px 20px; background-position: 0 0, 10px 10px;
  background-color: var(--background);
}

.code-panel { background: var(--card); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.code-panel-head {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  border-bottom: 1px solid var(--border); font-size: var(--text-sm); font-weight: 600;
}
.code-panel pre {
  margin: 0; padding: 14px 16px; overflow-x: auto;
  font-family: var(--font-mono); font-size: 12px; line-height: 1.6;
  max-height: 340px; color: var(--muted-foreground);
}

/* ── Copy buttons (gradient-tool lineage: idle → copied ✓, dirty dot) ── */
.copy-btn {
  position: relative; cursor: pointer; font-family: inherit;
  border: 1px solid var(--input); background: var(--card); color: var(--foreground);
  border-radius: 8px; padding: 7px 13px; font-size: var(--text-sm); font-weight: 500;
}
.copy-btn:hover { background: var(--muted); }
.copy-btn.primary { background: var(--primary); color: var(--primary-foreground); border-color: var(--primary); }
.copy-btn.primary:hover { filter: brightness(1.15); }
.copy-btn.copied { border-color: var(--status-success-fg); color: var(--status-success-fg); background: var(--status-success); }
.copy-btn.primary.copied { background: var(--status-success); color: var(--status-success-fg); filter: none; }
.copy-btn.dirty::after {
  content: ""; position: absolute; top: -3px; right: -3px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--ring); border: 2px solid var(--background);
}

.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }

/* Armed (two-step) destructive buttons */
.reset-btn {
  cursor: pointer; font-family: inherit; font-size: var(--text-xs); font-weight: 600;
  border: 1px solid var(--input); background: transparent; color: var(--muted-foreground);
  border-radius: 999px; padding: 3px 10px;
}
.reset-btn:hover { color: var(--status-error-fg); border-color: var(--status-error-fg); }
.reset-btn.armed, .reset-btn.armed:hover {
  background: var(--status-error); color: var(--status-error-fg); border-color: var(--status-error-fg);
}
.danger-zone { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; justify-content: space-between; margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--border); }
.danger-zone p { flex: 1 1 170px; font-size: var(--text-xs); color: var(--muted-foreground); line-height: 1.45; }

/* ── Toast ──────────────────────────────────────────────── */
.toast {
  position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%) translateY(8px);
  background: var(--primary); color: var(--primary-foreground);
  padding: 9px 16px; border-radius: 999px; font-size: var(--text-sm); font-weight: 500;
  opacity: 0; pointer-events: none; z-index: 60;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: no-preference) {
  .toast { transition: opacity var(--duration-fast) var(--ease-standard), transform var(--duration-fast) var(--ease-standard); }
}

/* ── Focus ──────────────────────────────────────────────── */
:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

/* Fuzzy-search hit highlighting — shows WHY a result matched, which is what
   makes a fuzzy list feel deliberate instead of random. */
mark {
  background: var(--pastel-butter);
  color: inherit;
  border-radius: 3px;
  padding: 0 1px;
}

/* ── Utility ────────────────────────────────────────────── */
.muted { color: var(--muted-foreground); }
.mono { font-family: var(--font-mono); }
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px;
  background: var(--muted); color: var(--muted-foreground);
}
.pill.on { background: var(--pastel-mint); color: var(--pastel-mint-fg); }
