/* ==========================================================================
   Chat Assembler — Komunidad, light professional.

   Tokens from the live properties, not invented. Both sites ship a light and a
   dark set; this uses the light one:
     --ink #17262b   --muted #6b7a84   --line #e7eef0   --bot-bg #eef7f6
     --brand #1d969e --brand-dark #1d968e
   The dark set (--bg #05121c, --surface #0d2231) is kept for the masthead only,
   so the header reads as a different surface from the work area.

   Accent is #1d969e, not the #2dd4bf used on their dark pages: mint on white
   fails contrast for text and small controls.

   No icon font, no emoji, no decorative glyphs. State is carried by weight,
   rule, colour and a 2px accent bar. Every affordance is a word.
   ========================================================================== */

html {
  /* Stops iOS Safari inflating type when the phone is turned to landscape. */
  -webkit-text-size-adjust: 100%;
}
body { margin: 0; background: #f4f7f8; }
.asm {
  /* A phone must never scroll sideways. The shell clips (see overflow below)
     rather than growing past the screen and dragging the page with it. */
  max-width: 100%;

  /* light working surfaces */
  --bg: #f4f7f8;
  --surface: #ffffff;
  --surface-2: #fafcfc;
  --surface-3: #eef4f5;
  --sunk: #eef2f4;

  /* dark masthead only */
  --head: #0b1e2c;
  --head-ink: #e8f2ef;
  --head-ink-2: #93a8b1;
  --head-line: #1d3442;

  /* ink */
  --ink: #17262b;
  --ink-2: #41545c;
  --ink-3: #6b7a84;
  --ink-4: #93a3ab;

  /* rules */
  --line: #e2eaec;
  --line-2: #edf2f3;
  --line-3: #cfdade;

  /* brand */
  --accent: #1d969e;
  --accent-2: #17787f;
  --accent-ink: #135c62;
  --accent-soft: #eaf6f7;
  --accent-line: #a9d9dd;

  /* semantic */
  --warn: #8a5a06;
  --warn-soft: #fdf5e6;
  --warn-line: #ecd9ac;
  --err: #b4322f;
  --err-soft: #fdefee;
  --err-line: #f0c9c6;
  --ok: #1c7a52;
  --ok-soft: #eaf6f0;
  --ok-line: #b3ddc8;

  /* One typeface throughout. Poppins is self-hosted (css/fonts.css) — no
     request to fonts.googleapis.com, so the type does not depend on a third
     party being reachable.

     --f-mono is a role, not a typeface: the eyebrows, counters and coordinates
     that used a monospace face now use Poppins with tabular figures, which
     keeps digits column-aligned without a second family on the page. */
  --f-sans: Poppins, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --f-mono: Poppins, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --r: 7px;
  --r-lg: 10px;
  --r-pill: 26px;

  --shadow: 0 1px 2px rgba(23, 38, 43, .05), 0 1px 3px rgba(23, 38, 43, .05);
  --shadow-lg: 0 2px 4px rgba(23, 38, 43, .06), 0 12px 28px rgba(23, 38, 43, .08);

  font-family: var(--f-sans);
  font-size: 13.5px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

/* Arrival. The landing page covers itself in this page's background colour
   before navigating, so what the eye sees across the two documents is one
   continuous move: the water rises, the surface holds, the app resolves onto
   it. Unconditional rather than only-when-handed-off — it costs a third of a
   second on a direct visit and needs no state to be passed between pages. */
.asm { animation: asm-arrive .34s cubic-bezier(.2, .7, .3, 1) both; }

@keyframes asm-arrive {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

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

.asm *, .asm *::before, .asm *::after { box-sizing: border-box; }
.asm ::selection { background: var(--accent-soft); color: var(--accent-ink); }
.asm :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.mono { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }

.eyebrow {
  font-family: var(--f-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* ==========================================================================
   Masthead — deliberately a different surface from everything below it
   ========================================================================== */

.bar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 22px;
  height: 56px;
  background: var(--head);
  flex-shrink: 0;
  position: relative;
  z-index: 3;
}
.bar::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent) 22%, transparent 22%);
}

.bar .logo { height: 20px; width: auto; display: block; }

/* The mark is the way back to the landing page. Reset the .bar a rules below
   so it reads as a logo, not as another nav word. */
.bar .home { display: block; padding: 0; border-bottom: 0; opacity: 1; }
.bar .home:hover { border-bottom-color: transparent; opacity: .78; }

.bar .div { width: 1px; height: 17px; background: var(--head-line); }

.bar .eyebrow { color: var(--head-ink-2); }

.bar .sp { margin-left: auto; display: flex; align-items: center; gap: 20px; }

.bar .meta {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: .05em;
  color: var(--head-ink-2);
  font-variant-numeric: tabular-nums;
}
.bar .meta b { color: var(--head-ink); font-weight: 500; }

.bar a {
  font-size: 12px;
  font-weight: 500;
  color: var(--head-ink-2);
  text-decoration: none;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
}
.bar a:hover { color: #fff; border-bottom-color: var(--accent); }

/* ==========================================================================
   Body / split
   ========================================================================== */

.body { flex: 1; display: flex; min-height: 0; background: var(--bg); }

.asm { --chat-w: 50%; }

.chatrail {
  width: var(--chat-w);
  min-width: 340px;
  max-width: calc(100% - 380px);
  flex-shrink: 0;
  background: var(--surface);
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--line);
}

.chathead {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 18px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  flex-shrink: 0;
}
.chathead__hint {
  font-size: 11.5px;
  font-weight: 300;
  color: var(--ink-4);
  margin-left: auto;
  text-align: right;
}

/* -- resizer ------------------------------------------------------------- */

.resizer {
  width: 11px;
  flex: 0 0 11px;
  cursor: col-resize;
  background: var(--bg);
  border: 0;
  padding: 0;
  position: relative;
  transition: background .12s ease;
}
.resizer::before {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 3px;
  height: 30px;
  border-radius: 2px;
  background: var(--line-3);
  transition: background .12s ease, height .12s ease;
}
.resizer:hover::before,
.resizer:focus-visible::before { background: var(--accent); height: 48px; }
.resizer[data-dragging="true"]::before { background: var(--accent); height: 80px; }

.asm[data-resizing="true"] { cursor: col-resize; user-select: none; }
/* The GL canvas and the SVG map both capture pointer moves; muting them keeps
   the drag with the splitter instead of panning the map. */
.asm[data-resizing="true"] .mapsvg,
.asm[data-resizing="true"] .mapgl { pointer-events: none; }

.work {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  background: var(--bg);
  border-left: 1px solid var(--line);
  /* The panel's width is set by the splitter, not the viewport, so its
     internal breakpoints have to key off the panel — a media query would fire
     at the wrong moment every time the split is dragged. */
  container-type: inline-size;
  container-name: work;
}

/* ==========================================================================
   Workflow rail — chevrons, left to right, inside the right panel only

   Arrow shape comes from clip-path, so there are no borders to clip: state is
   carried by fill alone. Each chevron overlaps its neighbour by the notch
   width, which is what makes the row read as one continuous flow rather than
   five buttons that happen to sit together.
   ========================================================================== */

.rail {
  --notch: 13px;
  display: flex;
  padding: 9px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }

.st {
  flex: 1 1 0;
  min-width: 0;
  text-align: left;
  border: 0;
  background: var(--surface-3);
  /* Both notches eat into the box, so the text has to be inset past them or
     it runs under the arrow point. */
  padding: 7px calc(var(--notch) + 4px) 7px calc(var(--notch) + 12px);
  /* Overlap by the notch less 2px, so a 2px diagonal of the rail's own
     background shows between chevrons. Without it, five same-coloured
     chevrons read as one flat bar. */
  margin-left: calc(var(--notch) * -1 + 2px);
  cursor: pointer;
  position: relative;
  font: inherit;
  color: var(--ink-3);
  display: flex;
  align-items: center;
  gap: 8px;
  transition: background .12s, color .12s;
  clip-path: polygon(
    0 0, calc(100% - var(--notch)) 0, 100% 50%,
    calc(100% - var(--notch)) 100%, 0 100%, var(--notch) 50%
  );
}
/* First chevron is flat-backed, last is flat-fronted — the row has a start
   and an end, not a stream of arrows pointing off both edges. */
.st:first-child {
  margin-left: 0;
  padding-left: 13px;
  clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% 50%, calc(100% - var(--notch)) 100%, 0 100%);
}
.st:last-child {
  padding-right: 12px;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, var(--notch) 50%);
}
/* Later chevrons paint over earlier ones, so the active one must come forward
   or its left notch is buried under its predecessor. */
.st { z-index: 1; }
.st.on { z-index: 3; }
.st:hover { z-index: 2; }

.st:not(.locked):hover { background: var(--line-2); color: var(--ink); }

.st .num {
  font-family: var(--f-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .1em;
  color: var(--ink-4);
  flex-shrink: 0;
}
.st .lab {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: -.005em;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The hint is prose — it belongs in the panel heading and the title attribute,
   not repeated five times across a narrow rail. */
.st .hint { display: none; }

.st.done { background: var(--ok-soft); }
.st.done .num,
.st.done .lab { color: var(--ok); }

.st.on { background: var(--accent); }
.st.on .num { color: rgba(255, 255, 255, .72); }
.st.on .lab { color: #fff; font-weight: 600; }

/* Locked: reachable by click (it routes you to the blocking step) but plainly
   not yet yours. The rule is stated in the title attribute. */
.st.locked { background: var(--surface-2); }
.st.locked .num { color: var(--line-3); }
.st.locked .lab { color: var(--ink-4); font-weight: 400; }

/* ==========================================================================
   Gate — the advance control at the foot of every step but the last
   ========================================================================== */

.gate {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  /* .stage is a flex column, so auto pins the gate to the foot of the panel on
     short steps. Sticky keeps it in view on long ones — in a gated workflow
     the thing that says why you cannot advance should never be scrolled off. */
  margin-top: auto;
  position: sticky;
  bottom: 0;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-left: 2px solid var(--ink-4);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: 0 -6px 14px -8px rgba(23, 38, 43, .18);
}
.gate[data-ready="true"] { border-left-color: var(--ok); background: var(--ok-soft); border-color: var(--ok-line); }

.gatemsg { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.gatemsg .gt { font-size: 12px; font-weight: 300; color: var(--ink-2); }
.gate[data-ready="true"] .eyebrow { color: var(--ok); }

.cont {
  margin-left: auto;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 9px 17px;
  border: 0;
  border-radius: var(--r);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s;
}
.cont:hover:not(:disabled) { background: var(--accent-2); }
.cont:disabled { background: var(--surface-3); color: var(--ink-4); cursor: not-allowed; }

/* ==========================================================================
   Transcript
   ========================================================================== */

.log {
  flex: 1;
  overflow-y: auto;
  padding: 16px 18px 8px;
  display: flex;
  flex-direction: column;
  gap: 13px;
}
.log::-webkit-scrollbar { width: 10px; }
.log::-webkit-scrollbar-thumb { background: var(--line-3); border-radius: 5px; border: 3px solid var(--surface); }
.log::-webkit-scrollbar-track { background: transparent; }

.msg { max-width: 100%; line-height: 1.62; font-size: 13.5px; }

.msg.u {
  align-self: flex-end;
  max-width: 86%;
  background: var(--head);
  color: var(--head-ink);
  padding: 9px 13px;
  border-radius: var(--r) var(--r) 2px var(--r);
}

.msg.a {
  align-self: stretch;
  border-left: 2px solid var(--accent-line);
  padding-left: 14px;
  color: var(--ink-2);
}
.msg.a strong { color: var(--ink); font-weight: 600; }

.msg.sys {
  align-self: stretch;
  font-size: 12px;
  color: var(--warn);
  background: var(--warn-soft);
  border: 1px solid var(--warn-line);
  border-radius: var(--r);
  padding: 9px 12px;
}

.msg p { margin: 0 0 .6em; }
.msg p:last-child { margin-bottom: 0; }

.delta { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 5px; }

.dchip {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: .03em;
  padding: 3px 8px;
  border-radius: 3px;
  background: var(--accent-soft);
  color: var(--accent-ink);
  border: 1px solid var(--accent-line);
  white-space: nowrap;
}
.dchip.sg { background: var(--ok-soft); color: var(--ok); border-color: var(--ok-line); }
.dchip.rk { background: var(--warn-soft); color: var(--warn); border-color: var(--warn-line); }
.dchip.rm { background: var(--err-soft); color: var(--err); border-color: var(--err-line); }
.dchip.no { background: var(--sunk); color: var(--ink-4); border-color: var(--line-3); text-decoration: line-through; }

.uv {
  margin-top: 10px;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--warn);
  background: var(--warn-soft);
  border: 1px solid var(--warn-line);
  border-radius: var(--r);
  padding: 8px 11px;
}
.uv b {
  display: block;
  font-family: var(--f-mono);
  font-size: 9.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  font-weight: 500;
  margin-bottom: 3px;
}

.typing { display: inline-flex; gap: 5px; align-items: center; height: 1.5em; }
.typing i { width: 4px; height: 4px; border-radius: 50%; background: var(--accent); animation: apulse 1.05s ease-in-out infinite; }
.typing i:nth-child(2) { animation-delay: .14s; }
.typing i:nth-child(3) { animation-delay: .28s; }
@keyframes apulse {
  0%, 60%, 100% { opacity: .25; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) { .typing i { animation: none; opacity: .55; } }

/* -- turn meter ---------------------------------------------------------- */

.turnmeter {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 18px;
  border-top: 1px solid var(--line-2);
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-4);
  background: var(--surface-2);
}
.turnmeter b { color: var(--ink-2); font-weight: 500; }
.turnmeter .pips { display: flex; gap: 3px; margin-left: auto; }
.turnmeter .pip { width: 11px; height: 3px; background: var(--line-3); border-radius: 1px; }
.turnmeter .pip[data-spent="true"] { background: var(--accent); }
.turnmeter[data-state="warning"] { background: var(--warn-soft); color: var(--warn); }
.turnmeter[data-state="warning"] b { color: var(--warn); }
.turnmeter[data-state="warning"] .pip[data-spent="true"] { background: var(--warn); }
.turnmeter[data-state="exhausted"] { background: var(--err-soft); color: var(--err); }
.turnmeter[data-state="exhausted"] b { color: var(--err); }
.turnmeter[data-state="exhausted"] .pip[data-spent="true"] { background: var(--err); }

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

.compose {
  border-top: 1px solid var(--line);
  padding: 11px 18px 14px;
  background: var(--surface);
}

.sugg { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }

.seed {
  font: inherit;
  font-size: 11.5px;
  border: 1px solid var(--line-3);
  background: var(--surface);
  color: var(--ink-3);
  padding: 6px 12px;
  border-radius: var(--r-pill);
  cursor: pointer;
  text-align: left;
  line-height: 1.35;
  transition: border-color .12s, color .12s, background .12s;
}
.seed:hover { border-color: var(--accent); color: var(--accent-ink); background: var(--accent-soft); }

.compose textarea {
  width: 100%;
  border: 1px solid var(--line-3);
  border-radius: var(--r);
  padding: 9px 11px;
  font: inherit;
  font-size: 12.5px;
  resize: none;
  outline: none;
  background: var(--surface);
  color: var(--ink);
  transition: border-color .14s, box-shadow .14s;
}
.compose textarea::placeholder { color: var(--ink-4); }
.compose textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.compose textarea:disabled { background: var(--sunk); color: var(--ink-4); cursor: not-allowed; }

.send {
  margin-top: 8px;
  width: 100%;
  background: var(--accent);
  color: #fff;
  border: 0;
  padding: 9px;
  border-radius: var(--r);
  font: inherit;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: .06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .12s;
}
.send:hover:not(:disabled) { background: var(--accent-2); }
.send:disabled { background: var(--line-3); color: #fff; cursor: default; }

/* ==========================================================================
   Work panel
   ========================================================================== */

.stage { flex: 1; overflow-y: auto; padding: 18px 20px 26px; display: flex; flex-direction: column; }

/* The stage scrolls; nothing inside it is ever compressed to make the content
   fit. Without this, a step whose content is taller than the panel is a column
   flex container with a height deficit, and every child has the default
   `flex-shrink: 1` — so the deficit gets taken out of the children instead of
   producing a scrollbar.

   Most children survive that anyway, because `min-height: auto` floors a flex
   item at its content height. The exception is the one that matters: **that
   floor is 0 for a scroll container**, and any child with a non-visible
   `overflow` is one. So a single stage child with `overflow-x: auto` silently
   volunteers to absorb the entire deficit — which is how the segmented control
   on step 2 ended up 8px tall with 45px of content inside it, its label sliced
   in half and its "Recommended" note nowhere. */
.stage > * { flex-shrink: 0; }

.stage::-webkit-scrollbar { width: 10px; }
.stage::-webkit-scrollbar-thumb { background: var(--line-3); border-radius: 5px; border: 3px solid var(--bg); }

.h2 {
  margin: 0 0 4px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -.032em;
  line-height: 1.15;
  color: var(--ink);
}
.sub {
  color: var(--ink-3);
  font-size: 12.5px;
  font-weight: 300;
  margin: 0 0 16px;
  max-width: 78ch;
  line-height: 1.55;
}

.sec { margin-bottom: 18px; }
.sech {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 10px;
}
.sech h3 {
  margin: 0;
  font-family: var(--f-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.sech .n {
  margin-left: auto;
  font-family: var(--f-mono);
  font-size: 10.5px;
  color: var(--ink-4);
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
  font: inherit;
  font-size: 11.5px;
  padding: 5px 11px;
  border-radius: 5px;
  border: 1px solid var(--line-3);
  background: var(--surface);
  cursor: pointer;
  color: var(--ink-2);
  transition: border-color .12s, color .12s, background .12s;
}
.chip:hover { border-color: var(--ink-4); color: var(--ink); }
.chip.on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 500;
}
.chip.on .mono { opacity: .85; }

select.ind, input.txt {
  font: inherit;
  font-size: 12.5px;
  padding: 7px 10px;
  border: 1px solid var(--line-3);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink);
  min-width: 240px;
}
select.ind:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* -- map ----------------------------------------------------------------- */

/* Map left, the sites it produced right. minmax(0,…) on the first track stops
   the GL canvas from forcing the grid wider than the panel.

   The two columns are always the same height, and the map decides what that
   height is. Its aspect-ratio gives it a natural height at any width, and
   `stretch` matches the site column to it.

   For that to hold, the site column must not be able to grow the row — five
   sites and fifty have to produce the same box. So its content sits in an
   absolutely-positioned layer: the column itself has no intrinsic height, it
   only ever takes the height the map set. A fixed pixel height on the row
   would also equalise them, but it letterboxes the map at wide splits and
   crops it at narrow ones. */
.mapcols {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(238px, 1fr);
  gap: 12px;
  align-items: stretch;
}

.sitecol {
  position: relative;
  min-height: 150px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}
/* The layer that actually holds the header and the list. inset:0 pins it to
   whatever height the grid handed the column. */
.sitecol > .inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.sitecolh {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line-2);
  background: var(--surface-2);
}
.sitecolh .n { margin-left: auto; font-size: 11px; color: var(--ink-2); }

/* Takes the height the header leaves and scrolls inside it, so twenty sites
   never stretch the column past the map. */
.sitescroll { flex: 1; min-height: 0; overflow-y: auto; padding: 8px; }
.sitescroll::-webkit-scrollbar { width: 8px; }
.sitescroll::-webkit-scrollbar-thumb { background: var(--line-3); border-radius: 4px; border: 2px solid var(--surface); }

/* Below this both columns are too narrow to be useful — stack them. Once
   stacked there is no row to share, so the site column gets its own height and
   its content leaves the absolute layer. */
@container work (max-width: 660px) {
  .mapcols { grid-template-columns: 1fr; }
  .sitecol { height: 290px; }
}

/* Control on the left, its explanation on the right, on one line. A flex row
   let the aside sit flush against the select and then wrap underneath it; an
   explicit two-track grid keeps the gutter whatever the text does. */
.row {
  display: grid;
  grid-template-columns: minmax(200px, 300px) minmax(0, 1fr);
  gap: 8px 20px;
  align-items: center;
}
.aside {
  font-size: 11.5px;
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-3);
  padding-left: 20px;
  border-left: 1px solid var(--line);
}
@container work (max-width: 560px) {
  .row { grid-template-columns: 1fr; }
  .aside { padding-left: 0; border-left: 0; }
}

/* ==========================================================================
   Option grid — multi-select cells that fill the row
   ========================================================================== */

.optgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
  gap: 7px;
}

/* --- the four risk families, four across ------------------------------------
   Only this grid. `.optgrid` is shared by the drivers, frameworks and add-on
   card lists, whose counts differ and which auto-fit correctly as they are.

   Measured against the CONTAINER, not the window. The builder's stage is a
   narrow panel beside the conversation — 668px of grid at a 1440px window,
   548px at 1200 — so a viewport media query would be guessing. `.famgrid` is
   the thing being measured, and it tracks the panel however the layout around it
   changes.

   Four, then two, and never three: there are exactly four cards, and a
   three-column stage leaves the fourth alone on a row of its own. That is the
   whole reason this is not `auto-fit`, which steps 4 -> 3 -> 2 and cannot be told
   to skip one. */
.famgrid { container-type: inline-size; }

.optgrid.optgrid--fam { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@container (min-width: 600px) {
  .optgrid.optgrid--fam { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* ~161px a card at 668px of grid, and the tick already costs 27px of every
     line — so the padding comes down and the blurb tightens rather than the card
     turning into a column of two-word lines.
     Selectors match the shape of the base rules (`.opt .ot .d`, not
     `.optgrid--fam .opt .d`): those are declared several hundred lines below
     this block, and at equal specificity the later one wins. A container query
     adds no specificity of its own. */
  .optgrid--fam .opt { padding: 8px 9px; gap: 7px; }
  .optgrid--fam .opt .ot .d { font-size: 11px; line-height: 1.45; }
  /* Letter-spacing is what makes the scope line wrap badly in a narrow card;
     the size is already 9.5px and does not need to shrink. */
  .optgrid--fam .opt .ot .scope { letter-spacing: .05em; }
}

/* Below this a two-column track is under ~145px, which is narrower than the
   words in it. One column, which is what the shared rule does anyway. */
@container (max-width: 320px) {
  .optgrid.optgrid--fam { grid-template-columns: minmax(0, 1fr); }
}

.opt {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 9px 11px;
  border: 1px solid var(--line-3);
  border-radius: var(--r);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  min-height: 44px;   /* comfortable tap target on a phone */
  transition: border-color .12s, background .12s, box-shadow .12s;
}
.opt:hover { border-color: var(--ink-4); }
.opt.on {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: inset 2px 0 0 var(--accent);
}

.opt .tick {
  width: 15px; height: 15px;
  flex-shrink: 0;
  margin-top: 1px;
  border: 1px solid var(--line-3);
  border-radius: 3px;
  background: var(--surface);
  position: relative;
}
.opt.on .tick { background: var(--accent); border-color: var(--accent); }
.opt.on .tick::after {
  content: "";
  position: absolute;
  left: 4px; top: 1px;
  width: 4px; height: 8px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(40deg);
}

.opt .ot { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.opt .ot .t { font-size: 12.5px; font-weight: 500; color: var(--ink); line-height: 1.3; }
/* The formal wording behind the plain question — present but subordinate, so
   nobody has to hover a chip to find out what they actually selected. */
.opt .ot .d {
  font-size: 10.5px;
  font-weight: 300;
  color: var(--ink-4);
  line-height: 1.35;
}
.opt.on .ot .d { color: var(--accent-ink); opacity: .8; }

.mapwrap {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow);
}
/* The bar, the hit list and the footnote are fixed; the map itself absorbs
   whatever height is left. */
.mapbar, .hits, .mapfoot { flex-shrink: 0; }
.mapbar {
  display: flex;
  gap: 9px;
  align-items: center;
  padding: 7px 10px;
  border-bottom: 1px solid var(--line-2);
  background: var(--surface-2);
}
/* aspect-ratio, not a pixel height: the map is then correctly proportioned at
   every split position, and its computed height is what sets the row.
   2:1 is the plate-carree raster's true ratio, so it fills its box exactly —
   no letterboxing, and the click-to-coordinate maths needs no correction. GL
   is happy at any ratio; 16:10 just reads better than a 2:1 strip. */
.mapsvg {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 1;
  background: #e9eff1;
  cursor: crosshair;
  touch-action: none;
}
.mapgl {
  width: 100%;
  aspect-ratio: 16 / 10;
  background: var(--sunk);
}
/* A floor on the height has to go on the wrapper, never on the element that
   carries aspect-ratio: there, min-height back-propagates into a min-WIDTH
   (190px tall at 2:1 demands 380px wide) and pushes the whole page into
   horizontal overflow on a phone. */
.mapwrap { min-height: 210px; }

.mapfoot {
  font-size: 10.5px;
  font-weight: 300;
  color: var(--ink-4);
  padding: 6px 10px;
  border-top: 1px solid var(--line-2);
  line-height: 1.45;
}

.mapbar input {
  flex: 1;
  min-width: 0;
  margin-left: auto;
  border: 1px solid var(--line-3);
  border-radius: var(--r);
  padding: 6px 10px;
  font: inherit;
  font-size: 11.5px;
  outline: none;
  background: var(--surface);
  color: var(--ink);
}
.mapbar input::placeholder { color: var(--ink-4); }
.mapbar input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* A list, not a row of pills: the results are addresses now, and an address is
   two lines of text of unpredictable length. Capped in height and scrolled, so
   eight hits never push the map off the screen. */
.hits {
  display: flex;
  flex-direction: column;
  padding: 4px;
  gap: 1px;
  max-height: 208px;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--accent-soft);
  border-bottom: 1px solid var(--line-2);
}
.hits:empty { display: none; }

.hit {
  font: inherit;
  display: grid;
  /* The kind column takes what it needs and the name column absorbs the rest,
     so a long street name truncates instead of squeezing "Address" onto two. */
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 10px;
  width: 100%;
  text-align: left;
  border: 1px solid transparent;
  background: var(--surface);
  border-radius: var(--r);
  padding: 6px 10px;
  cursor: pointer;
  color: var(--ink);
}
.hit:hover, .hit:focus-visible {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  outline: none;
}

.hit__n {
  font-size: 11.5px;
  font-weight: 500;
  /* One line each. A result that wraps makes the list jump as you type. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hit__s {
  grid-column: 1;
  font-size: 10.5px;
  font-weight: 300;
  color: var(--ink-4);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hit__k {
  grid-row: 1 / -1;
  grid-column: 2;
  font-family: var(--f-mono);
  font-size: 9px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-4);
  white-space: nowrap;
}
.hit:hover .hit__s, .hit:hover .hit__k,
.hit:focus-visible .hit__s, .hit:focus-visible .hit__k { color: rgba(255, 255, 255, .78); }

.hitnote {
  padding: 6px 10px;
  font-size: 11.5px;
  font-weight: 300;
  color: var(--ink-4);
}

/* Mapbox chrome, aligned to the light theme */
.mapgl .mapboxgl-ctrl-group { border: 1px solid var(--line-3); box-shadow: none; }
.mapgl .mapboxgl-ctrl-attrib { background: rgba(255, 255, 255, .82); font-size: 10px; }
.mapgl .mapboxgl-popup-content {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line-3);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  font-size: 12px;
  padding: 9px 11px;
}
.mapgl .mapboxgl-popup-tip { border-top-color: var(--surface); }

/* Site pin — a marker, not an icon font or emoji. */
.pin {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid #fff;
  box-shadow: 0 0 0 3px rgba(29, 150, 158, .22), 0 1px 3px rgba(23, 38, 43, .3);
  cursor: pointer;
}
.pin[data-active="true"] { background: var(--warn); box-shadow: 0 0 0 4px rgba(138, 90, 6, .22); }

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

.sitelist { display: flex; flex-direction: column; gap: 5px; }

/* Two rows in a narrow column: identity on top, coordinates and actions
   beneath. A single flex row would crush the name field. */
.site {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 7px;
  row-gap: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 6px 8px;
  background: var(--surface);
}
.site:hover { border-color: var(--line-3); }
.site.on { border-color: var(--accent); background: var(--accent-soft); }

.site .idx {
  font-family: var(--f-mono);
  font-size: 9.5px;
  letter-spacing: .06em;
  color: var(--ink-4);
  grid-row: 1;
}
.site input.nm { grid-column: 2 / span 2; grid-row: 1; }
.site .co { grid-column: 2; grid-row: 2; }
.site .acts { grid-column: 3; grid-row: 2; display: flex; gap: 9px; }

.site input.nm {
  border: 1px solid transparent;
  border-radius: 5px;
  padding: 3px 6px;
  font: inherit;
  font-weight: 500;
  font-size: 12.5px;
  width: 100%;
  min-width: 0;
  background: transparent;
  color: var(--ink);
}
.site input.nm:hover { border-color: var(--line); background: var(--surface-2); }
.site input.nm:focus {
  border-color: var(--accent);
  background: var(--surface);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.site .co {
  font-family: var(--f-mono);
  font-size: 10px;
  color: var(--ink-4);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-left: 6px;
}
.site .act {
  background: none;
  border: 0;
  border-bottom: 1px solid transparent;
  color: var(--ink-3);
  cursor: pointer;
  font: inherit;
  font-size: 9.5px;
  letter-spacing: .07em;
  text-transform: uppercase;
  padding: 1px 0;
  white-space: nowrap;
}
.site .act:hover { color: var(--accent-ink); border-bottom-color: var(--accent); }
.site .act.del:hover { color: var(--err); border-bottom-color: var(--err); }

/* -- fork cards ---------------------------------------------------------- */

.fork { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 11px; }

.fk {
  border: 1px solid var(--line-3);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  display: flex;
  flex-direction: column;
  gap: 7px;
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: border-color .14s, box-shadow .14s;
}
.fk::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: transparent; }
.fk:hover { border-color: var(--ink-4); box-shadow: var(--shadow-lg); }
.fk.lead { border-color: var(--accent-line); }
.fk.lead::before { background: var(--accent); }
.fk.lead:hover { border-color: var(--accent); }

.fk .kicker { font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-4); }
.fk.lead .kicker { color: var(--accent); }
.fk .hd { font-size: 15px; font-weight: 600; letter-spacing: -.025em; line-height: 1.2; color: var(--ink); }
.fk .by { font-size: 12px; font-weight: 300; color: var(--ink-3); line-height: 1.6; }
.fk .go {
  font-family: var(--f-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-top: auto;
  padding-top: 6px;
}

/* -- templates + picks --------------------------------------------------- */

.tgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 9px; }

.tpl {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 11px 13px;
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 5px;
  transition: border-color .14s, box-shadow .14s;
}
.tpl:hover { border-color: var(--line-3); box-shadow: var(--shadow); }
.tpl.on { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }
.tpl .n { font-weight: 500; font-size: 12.5px; color: var(--ink); padding-right: 78px; }
.tpl .b { font-size: 11.5px; font-weight: 300; color: var(--ink-3); line-height: 1.55; }
.tpl .f { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-4); margin-top: auto; padding-top: 4px; }
.tpl .f b { color: var(--ink-2); font-weight: 500; }

.badge {
  position: absolute;
  top: 13px; right: 14px;
  font-family: var(--f-mono);
  font-size: 9px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-ink);
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  padding: 2px 7px;
  border-radius: 3px;
}
.tpl.on .badge { background: #fff; }

.pick {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  margin-bottom: 5px;
  cursor: pointer;
  text-align: left;
  width: 100%;
  font: inherit;
  color: inherit;
  transition: border-color .14s, background .14s;
}
.pick:hover { border-color: var(--line-3); }
.pick.on { border-color: var(--accent); background: var(--accent-soft); }
.pick.rust.on { border-color: var(--warn-line); background: var(--warn-soft); }

.pick .box {
  width: 15px; height: 15px;
  border-radius: 3px;
  border: 1px solid var(--line-3);
  background: var(--surface);
  flex-shrink: 0;
  margin-top: 3px;
  position: relative;
}
.pick.on .box { background: var(--accent); border-color: var(--accent); }
.pick.on .box::after {
  content: "";
  position: absolute;
  left: 4px; top: 1px;
  width: 4px; height: 8px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(40deg);
}
.pick.rust.on .box { background: var(--warn); border-color: var(--warn); }

.pick .t { font-weight: 500; font-size: 12.5px; color: var(--ink); display: block; }
.pick .d { font-size: 11.5px; font-weight: 300; color: var(--ink-3); line-height: 1.5; margin-top: 2px; display: block; }
.pick .r { margin-left: auto; text-align: right; font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-4); white-space: nowrap; padding-left: 10px; }

.modbar {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 11.5px;
  color: var(--ink-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 7px 11px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.modbar b { color: var(--ink); font-weight: 500; }

.linkbtn {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--accent-line);
  color: var(--accent-ink);
  cursor: pointer;
  font: inherit;
  font-size: 11.5px;
  padding: 1px 0;
}
.linkbtn:hover { border-bottom-color: var(--accent); }
/* Spent: the claim banner's "start a new setup" disables itself after the
   click, so a second press cannot wipe the sheet someone just started. */
.linkbtn:disabled {
  color: var(--ink-4);
  border-bottom-color: transparent;
  cursor: default;
}

/* -- stats --------------------------------------------------------------- */

.stat {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  margin-bottom: 16px;
  box-shadow: var(--shadow);
}
.stat > div { background: var(--surface); padding: 11px 13px; }
.stat .v {
  font-size: 21px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -.035em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.stat .l { font-size: 10.5px; font-weight: 300; color: var(--ink-4); margin-top: 4px; line-height: 1.4; }
.stat .v.sg { color: var(--accent); }
.stat .v.am { color: var(--warn); }
.stat .v.rk { color: var(--ok); }

.tlist { display: flex; flex-wrap: wrap; gap: 5px; }
.tpill {
  font-size: 11.5px;
  padding: 4px 11px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--line-3);
  color: var(--ink-3);
}
.tpill.fed { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-ink); }
.tpill.rsk { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }

.note {
  padding: 10px 13px;
  color: var(--ink-3);
  font-size: 12px;
  font-weight: 300;
  line-height: 1.6;
  border: 1px solid var(--line);
  border-left: 2px solid var(--ink-4);
  border-radius: var(--r);
  background: var(--surface);
}
.note b { color: var(--ink); font-weight: 500; }

/* The same note, raised: a rule that has just been enforced, rather than a rule
   being mentioned. Amber and not red — nothing has gone wrong. */
.note--warn {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: var(--warn-line);
  border-left-color: var(--warn);
}
.note--warn b { color: var(--warn); }

/* -- theme cards --------------------------------------------------------- */

.thg { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 9px; }

.thc {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  padding: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color .14s, box-shadow .14s;
}
.thc:hover { border-color: var(--line-3); box-shadow: var(--shadow); }
.thc.on { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.thc .hd { padding: 10px 12px 8px; display: flex; flex-direction: column; gap: 4px; border-bottom: 1px solid var(--line-2); }
.thc.on .hd { background: var(--accent-soft); }
.thc .nm { font-weight: 600; font-size: 13.5px; color: var(--ink); display: flex; align-items: center; gap: 9px; letter-spacing: -.02em; }
.thc .who { font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase; color: var(--accent); }
.thc .by { padding: 9px 12px 11px; font-size: 11.5px; font-weight: 300; color: var(--ink-3); line-height: 1.6; }

.empty { color: var(--ink-4); font-size: 11.5px; font-weight: 300; padding: 12px 4px; line-height: 1.5; }

.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;
}

/* ==========================================================================
   Segmented control

   One object, not a row of loose buttons: mutually exclusive choices read as a
   single control. Used for the tracking mode, the climate-risk switch and the
   pillar tabs — same interaction, same widget, three places.
   ========================================================================== */

/* No `overflow-x: auto` here, and that is deliberate rather than an omission.
   CSS has no way to scroll one axis and overflow the other: setting overflow-x
   forces overflow-y to match, so this box became a scroll container in both
   directions. Two consequences, both bugs — it clipped its own labels instead of
   growing for them, and as a scroll container it lost its automatic minimum
   height, which let the stage's flex layout crush it (see `.stage > *`).

   Nothing is lost. The labels wrap inside their own segment now, so two or three
   choices fit any width down to a phone without a horizontal scrollbar that was
   also hidden — `scrollbar-width: none` on a scroller people were expected to
   scroll. */
.seg {
  display: flex;
  gap: 3px;
  padding: 3px;
  margin-bottom: 16px;
  background: var(--surface-3);
  border: 1px solid var(--line);
  border-radius: 9px;
}

.sgb {
  /* Basis 0 so the segments share the row equally regardless of label length —
     a segmented control whose halves are different widths reads as two buttons
     that happen to touch. */
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  align-items: flex-start;
  padding: 7px 13px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--ink-3);
  font: inherit;
  cursor: pointer;
  text-align: left;
  /* Wraps rather than nowrap: with basis 0 a long label had nowhere to go, so
     it ran past its own segment and under the next one. */
  white-space: normal;
  transition: background .12s, color .12s, box-shadow .12s;
}
.sgb:hover { color: var(--ink); }
.sgb.on {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow), inset 0 -2px 0 var(--accent);
}

.sgb .sgt { font-size: 12.5px; font-weight: 500; }
.sgb.on .sgt { font-weight: 600; }
.sgb .sgn { font-size: 10px; font-weight: 300; color: var(--ink-4); letter-spacing: .01em; }
.sgb.on .sgn { color: var(--accent-ink); }

.chips--pad { padding-top: 2px; }

/* Scope line on a risk data set — where the data exists at all. */
.opt .ot .scope {
  margin-top: 4px;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.opt.on .ot .scope { color: var(--accent-ink); }

/* A scope line that is a sentence rather than a label. "PH ONLY" reads fine in
   letter-spaced caps; "RESERVES THE TAB. NO DATA UNTIL A SOURCE IS WIRED." is
   three lines of shouting, and it is the one line on that card someone has to
   actually read before ticking it. */
.opt .ot .scope--say {
  letter-spacing: 0;
  text-transform: none;
  font-size: 11px;
  font-weight: 400;
  line-height: 1.4;
}

/* ==========================================================================
   Configuration summary — step 5
   ========================================================================== */

.cfglist {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow);
}

.cfg {
  display: grid;
  grid-template-columns: minmax(120px, 168px) minmax(0, 1fr) auto;
  gap: 12px;
  align-items: baseline;
  padding: 8px 13px;
  border-bottom: 1px solid var(--line-2);
}
.cfg:last-child { border-bottom: 0; }
.cfg:nth-child(even) { background: var(--surface-2); }

.cfl {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.cfv { font-size: 12.5px; color: var(--ink); line-height: 1.45; }
/* An unset line is stated as unset rather than left blank — a blank row reads
   as "nothing to do here". */
.cfg[data-set="false"] .cfv { color: var(--ink-4); font-style: italic; }

.cfe {
  border: 0;
  border-bottom: 1px solid transparent;
  background: none;
  color: var(--ink-4);
  font: inherit;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 0;
}
.cfe:hover { color: var(--accent-ink); border-bottom-color: var(--accent); }

/* -- current look -------------------------------------------------------- */

.lookrow {
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
  gap: 16px;
  align-items: stretch;
  padding: 13px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.lookmini {
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--sunk);
}
.lookmini.empty2 {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 108px;
  font-size: 11px;
  color: var(--ink-4);
  border-style: dashed;
}
.lookmeta { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }
.lookname { font-size: 16px; font-weight: 600; letter-spacing: -.02em; color: var(--ink); }
.lookby { font-size: 11.5px; font-weight: 300; color: var(--ink-3); line-height: 1.55; }
.cont.slim { margin: 6px 0 0; padding: 8px 15px; font-size: 11px; }

@container work (max-width: 620px) {
  .lookrow { grid-template-columns: 1fr; }
  .cfg { grid-template-columns: 1fr auto; }
  .cfl { grid-column: 1 / -1; }
}

/* ==========================================================================
   Launch panel — the last thing on step 5
   ========================================================================== */

.launch {
  margin-top: auto;
  padding: 18px 20px 20px;
  border: 1px solid var(--ok-line);
  border-radius: var(--r-lg);
  background: var(--ok-soft);
  box-shadow: var(--shadow);
}

.lhead { display: flex; flex-direction: column; gap: 3px; margin-bottom: 15px; }
.lhead .eyebrow { color: var(--ok); }
.lh {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -.028em;
  color: var(--ink);
}
.lby {
  margin: 2px 0 0;
  font-size: 12.5px;
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 68ch;
}

.lgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}
.lfield { display: flex; flex-direction: column; gap: 4px; }
.llab {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.lin {
  font: inherit;
  font-size: 13.5px;
  padding: 10px 12px;
  border: 1px solid var(--line-3);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink);
  outline: none;
  width: 100%;
}
.lin::placeholder { color: var(--ink-4); }
.lin:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.lhint { font-size: 10.5px; font-weight: 300; color: var(--ink-4); }

.lnote { font-size: 12px; line-height: 1.5; color: var(--ink-2); margin-top: 12px; }
.lnote:empty { display: none; }
.lnote[data-state="err"] { color: var(--err); font-weight: 500; }
.lnote[data-state="ok"] { color: var(--ok); font-weight: 500; }

.launch .cont { margin-top: 14px; width: 100%; min-height: 46px; }

/* The built state. Its primary action is a navigation, so it is an <a> wearing
   the .cont dress — flex to center the label the way a button would, and the
   underline stripped. Sized and placed exactly like "Build my platform" was,
   so a returning owner's muscle memory still lands on the way forward. */
.launch--ready a.cont {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  text-decoration: none;
}
.launch--ready .lby { margin-top: 6px; }

.lswitch {
  margin: 12px 0 0;
  font-size: 11.5px;
  font-weight: 300;
  color: var(--ink-3);
}

@container work (max-width: 560px) {
  .launch { padding: 14px; }
  .lgrid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Modal — the template gallery
   ========================================================================== */

.modal { position: fixed; inset: 0; z-index: 60; display: flex; }
.modal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(11, 30, 44, .5);
  backdrop-filter: blur(2px);
}
.modal__panel {
  position: relative;
  margin: auto;
  width: min(1040px, calc(100vw - 32px));
  max-height: min(760px, calc(100dvh - 32px));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  /* A sheet, not a dialog box: the corner radius is the single strongest cue
     that separates a modern OS surface from a 2012 modal. */
  border-radius: 20px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.modal__head {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 20px 22px 16px;
  /* No rule and no tinted bar. The header is part of the sheet rather than a
     strip bolted to the top of it; the list below provides the only division
     the eye needs. */
}
.modal__title {
  margin: 3px 0 0;
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -.03em;
  color: var(--ink);
}
.modal__x {
  margin-left: auto;
  flex: 0 0 auto;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  color: var(--ink-2);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  padding: 7px 15px;
  cursor: pointer;
  transition: background .15s ease;
}
.modal__x:hover { background: var(--line); color: var(--ink); }

.modal__body {
  flex: 1;
  min-height: 0;
  display: grid;
  /* 300, not 258: at 258 the row's second line — "Top bar with a section
     outline" — had ~145px to sit in and was ellipsised on every template whose
     nav has a name longer than two words. */
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: 0;
}

.tmlist {
  overflow-y: auto;
  padding: 4px 10px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Untinted. A grey sidebar against a white panel is two materials for one
     surface; the selected row is what should carry the colour. */
  background: transparent;
}
.tmlist::-webkit-scrollbar { width: 8px; }
.tmlist::-webkit-scrollbar-thumb { background: var(--line-3); border-radius: 4px; border: 2px solid var(--surface-2); }

.tmi {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  border: 0;
  border-radius: 13px;
  background: transparent;
  cursor: pointer;
  min-height: 56px;
  transition: background .14s ease;
}
.tmi:hover { background: var(--surface-3); }
/* Selection is a filled row, not a border and an inset bar. One shape changing
   fill reads as "this one"; three simultaneous cues read as decoration. */
.tmi.on { background: var(--accent-soft); }
.tmi.on .tmn { color: var(--accent-ink); }
.tmlist:focus-visible { outline: 2px solid color-mix(in srgb, var(--accent) 55%, transparent); outline-offset: -6px; border-radius: 16px; }

/* Thumbnail: the full-size wireframe scaled down, so the row and the preview
   are literally the same drawing. A separate simplified thumbnail would be a
   second thing to keep in step. */
.tmthumb {
  position: relative;
  width: 74px;
  height: 47px;
  flex-shrink: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface);
}
.tmthumb__in {
  position: absolute;
  top: 0;
  left: 0;
  width: 264px;
  height: 168px;
  transform: scale(0.28);
  transform-origin: top left;
  pointer-events: none;
}
.tmthumb .mk { height: 100%; min-height: 0; border: 0; border-radius: 0; }
.tmi.on .tmthumb { border-color: var(--accent); }

.tmt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tmn { font-size: 14px; font-weight: 500; letter-spacing: -.01em; color: var(--ink); display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.tmcur {
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: var(--surface);
  border: 0;
  border-radius: var(--r-pill);
  padding: 2px 7px;
}
/* Planned, not available. Stated on the row, on the preview and on the commit
   button — three places, because a disabled button on its own reads as a bug. */
.tmsoon {
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--warn);
  background: var(--warn-soft);
  border: 0;
  border-radius: var(--r-pill);
  padding: 2px 7px;
}
.tmi.soon .tmn { color: var(--ink-2); }
.tmtag.soon { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); }

/* .mk.mk--soon, not .mk--soon: the base .mk rule sets display:flex and is
   declared later in the file, so a single class would lose the tie-break and
   the label would sit left-aligned instead of centred. */
.mk.mk--soon {
  display: grid;
  place-items: center;
  border-style: dashed;
  background:
    repeating-linear-gradient(45deg, transparent 0 7px, rgba(23, 38, 43, .035) 7px 14px),
    var(--mk-bg);
}
.mk-soon {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-4);
}
/* The thumbnail is drawn at 264px and scaled to 0.28, so its type has to be
   sized for the pre-scale canvas or it comes out unreadable. */
.mk--thumb .mk-soon { font-size: 30px; letter-spacing: .12em; }

/* Wraps rather than ellipsises. "Top bar with a section ou…" tells the reader
   less than two short lines do, and the row has the height to spare. */
.tmw {
  font-size: 11px;
  font-weight: 300;
  line-height: 1.35;
  color: var(--ink-4);
  white-space: normal;
  overflow-wrap: break-word;
}

.tmview { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; }
/* The list is what makes the dialog tall, so the preview takes the slack
   instead of leaving a void under the description. */
/* No hatching behind the wireframe. The diagonal texture was doing the work of
   saying "this is a mock" that the abstract blocks already do, and it fought
   with the dark templates. A plain recessed surface instead. */
.tmstage {
  flex: 1;
  min-height: 250px;
  display: grid;
  padding: 22px;
  background: var(--surface-3);
  border-bottom: 1px solid var(--line);
}
.tmfacts { padding: 18px 22px 20px; display: flex; flex-direction: column; gap: 6px; }
.tmh { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -.032em; color: var(--ink); }
.tmb { margin: 0; font-size: 13.5px; font-weight: 300; line-height: 1.62; color: var(--ink-2); max-width: 60ch; }
.tmmeta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* Filled, not outlined, and sentence case. A row of hollow uppercase capsules
   is the single most dated thing a UI can wear. */
.tmtag {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
  background: var(--surface-3);
  border: 0;
  border-radius: var(--r-pill);
  padding: 4px 11px;
}

.modal__foot {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 22px 18px;
  border-top: 1px solid var(--line);
  flex-wrap: wrap;
}
.modal__hint { font-size: 12px; font-weight: 300; line-height: 1.5; color: var(--ink-4); flex: 1; min-width: 180px; }

/* The sheet's own primary action. Sentence case and a capsule, unlike the
   builder's uppercase Continue buttons — scoped to the modal rather than
   changed globally, because every primary button on the page is not what was
   being asked about here. */
.modal__foot .cont {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -.01em;
  text-transform: none;
  padding: 10px 20px;
  border-radius: var(--r-pill);
}

/* ==========================================================================
   Layout wireframes

   Built from the template's own layout/mode/accent, so a preview cannot drift
   away from what it claims to show. Deliberately abstract — it communicates the
   shape of the app, and abstract blocks cannot promise a feature that is not
   there the way a fake screenshot would.
   ========================================================================== */

/* height:100% so the wireframe fills the stage; min-height keeps it legible
   when the stage is short (the mini preview overrides both). */
.mk {
  height: 100%;
  min-height: 210px;
  --mk-bg: #f1f4f6;
  --mk-surface: #ffffff;
  --mk-line: #e6ecee;
  --mk-ink: #c2cfd4;
  --mk-ink-2: #e2eaec;

  display: flex;
  gap: 6px;
  padding: 7px;
  border-radius: 14px;
  background: var(--mk-bg);
  border: 1px solid var(--mk-line);
  overflow: hidden;
}
/* The two skinned templates. The wireframe has to show the material or Frost
   and Aurora read as duplicates of Studio and Console — same blocks, same
   places. Translucency at this scale would just look muddy, so the preview
   states it the way the real thing looks: a gradient wash, panels lighter than
   the ground, no drawn borders. */
.mk[data-skin="glass"] {
  --mk-bg: transparent;
  --mk-surface: rgba(255, 255, 255, .76);
  --mk-line: rgba(255, 255, 255, .85);
  --mk-ink-2: rgba(19, 45, 55, .13);
  --mk-ink: rgba(19, 45, 55, .22);
  /* Stronger than the real app's wash. At preview size the gradient is a
     150px band; at the tint the app uses it disappeared and Frost read as
     Studio with rounder corners. */
  background-color: #e8eef3;
  background-image:
    radial-gradient(11rem 8rem at 2% -6%, color-mix(in srgb, var(--mk-accent) 58%, transparent), transparent 66%),
    radial-gradient(10rem 7rem at 106% 0%, rgba(122, 150, 255, .58), transparent 66%),
    radial-gradient(11rem 8rem at 58% 116%, rgba(45, 212, 191, .48), transparent 64%);
}

.mk[data-skin="aurora"] {
  --mk-bg: transparent;
  --mk-surface: rgba(255, 255, 255, .075);
  --mk-line: rgba(255, 255, 255, .10);
  --mk-ink-2: rgba(255, 255, 255, .13);
  --mk-ink: rgba(255, 255, 255, .22);
  background-color: #06080d;
  background-image:
    radial-gradient(15rem 10rem at 2% -12%, color-mix(in srgb, var(--mk-accent) 42%, transparent), transparent 60%),
    radial-gradient(13rem 9rem at 102% 2%, rgba(148, 106, 255, .38), transparent 62%),
    radial-gradient(14rem 10rem at 72% 114%, rgba(0, 194, 168, .26), transparent 60%);
}

/* Deeper corners are half of what makes these two look different. */
.mk[data-skin="glass"] .mk-side,
.mk[data-skin="glass"] .mk-top,
.mk[data-skin="glass"] .mk-tile,
.mk[data-skin="glass"] .mk-map,
.mk[data-skin="aurora"] .mk-side,
.mk[data-skin="aurora"] .mk-top,
.mk[data-skin="aurora"] .mk-tile,
.mk[data-skin="aurora"] .mk-map { border-radius: 13px; }
.mk[data-skin="glass"] .mk-row,
.mk[data-skin="aurora"] .mk-row { border-radius: 9px; }

.mk[data-mode="dark"] {
  --mk-bg: #0c1a22;
  --mk-surface: #172a35;
  --mk-line: #1f3a48;
  --mk-ink: #3c5a6b;
  --mk-ink-2: #24404f;
}

/* The mini preview on the summary card: same wireframe, quarter scale. */
.mk--mini { height: 112px; min-height: 0; padding: 4px; gap: 3px; border: 0; border-radius: 0; }

.mk > * { min-width: 0; }
.mk-col { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; }
.mk-main { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; }
.mk-body { display: flex; flex-direction: column; gap: 5px; flex: 1; min-height: 0; }

/* sidebar / icon rail */
.mk-side {
  width: 25%;
  max-width: 78px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 8px 7px;
  border-radius: 10px;
  background: var(--mk-surface);
  border: 1px solid var(--mk-line);
}
.mk-nl { height: 6px; border-radius: 3px; background: var(--mk-ink-2); }
.mk-nl:first-child { background: var(--mk-accent); width: 62%; }

.mk-rail {
  width: 26px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 5px;
  border-radius: 10px;
  background: var(--mk-surface);
  border: 1px solid var(--mk-line);
}
.mk-ri { height: 14px; border-radius: 6px; background: var(--mk-ink-2); }
.mk-ri:first-child { background: var(--mk-accent); }

/* top bar */
.mk-top {
  height: 24px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 0 9px;
  border-radius: 10px;
  background: var(--mk-surface);
  border: 1px solid var(--mk-line);
}
.mk-pill { height: 6px; width: 30px; border-radius: 3px; background: var(--mk-ink-2); }
.mk-pill:first-child { background: var(--mk-accent); width: 40px; }
.mk-top--tabs { gap: 9px; }
.mk-tab { height: 6px; width: 34px; border-radius: 3px; background: var(--mk-ink-2); }
.mk-tab:first-child { background: var(--mk-accent); }

/* content blocks */
.mk-tiles { display: flex; gap: 5px; flex-shrink: 0; }
.mk-tile {
  flex: 1;
  min-height: 42px;
  border-radius: 11px;
  background: var(--mk-surface);
  border: 1px solid var(--mk-line);
}
/* One accent mark per tile rather than a coloured cap on all of them: a stripe
   across every card is a 2015 dashboard, a single tinted chip inside one is a
   card with something in it. */
.mk-tile:first-child {
  background: color-mix(in srgb, var(--mk-accent) 12%, var(--mk-surface));
  border-color: color-mix(in srgb, var(--mk-accent) 22%, transparent);
}
.mk-grid { flex: 1; display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 1fr; gap: 5px; }
.mk-grid .mk-tile { min-height: 0; }

.mk-rows { flex: 1; display: flex; flex-direction: column; gap: 4px; min-height: 0; }
.mk-row {
  height: 16px;
  flex-shrink: 0;
  border-radius: 8px;
  background: var(--mk-surface);
  border: 1px solid var(--mk-line);
}

/* map-first */
.mk-map {
  flex: 1.5;
  border-radius: 11px;
  border: 1px solid var(--mk-line);
  background:
    radial-gradient(circle at 34% 42%, var(--mk-accent) 0 4.5px, transparent 4.5px),
    radial-gradient(circle at 58% 63%, var(--mk-accent) 0 4.5px, transparent 4.5px),
    radial-gradient(circle at 72% 34%, var(--mk-accent) 0 4.5px, transparent 4.5px),
    radial-gradient(circle at 46% 74%, var(--mk-ink) 0 3px, transparent 3px),
    repeating-linear-gradient(0deg, var(--mk-ink-2) 0 1px, transparent 1px 18px),
    repeating-linear-gradient(90deg, var(--mk-ink-2) 0 1px, transparent 1px 18px),
    var(--mk-surface);
}
.mk-list { flex: 1; display: flex; flex-direction: column; gap: 4px; }

/* document with an outline */
.mk-doc { flex: 1; display: flex; gap: 5px; min-height: 0; }
.mk-outline { width: 30%; max-width: 92px; display: flex; flex-direction: column; gap: 5px; padding-top: 3px; }
.mk-ol { height: 5px; border-radius: 3px; background: var(--mk-ink-2); }
.mk-ol:first-child { background: var(--mk-accent); width: 70%; }
.mk-page {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 9px;
  border-radius: 5px;
  background: var(--mk-surface);
  border: 1px solid var(--mk-line);
}
.mk-line { height: 4px; border-radius: 2px; background: var(--mk-ink-2); }
.mk-line:first-child { background: var(--mk-accent); width: 46%; height: 6px; }
.mk-line:nth-child(5) { width: 72%; }
.mk-line:last-child { width: 58%; }

/* phone */
.mk--bottom { justify-content: center; }
.mk-phone {
  width: 132px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 5px;
  border-radius: 12px;
  background: var(--mk-surface);
  border: 1px solid var(--mk-line);
}
.mk-phone > .mk-top { height: 16px; border: 0; background: var(--mk-bg); }
.mk-phone > .mk-body { gap: 5px; }
.mk-card {
  flex: 1;
  border-radius: 5px;
  background: var(--mk-bg);
  border: 1px solid var(--mk-line);
  border-left: 2px solid var(--mk-accent);
}
.mk-bottom {
  height: 20px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-around;
  border-radius: 5px;
  background: var(--mk-bg);
  border: 1px solid var(--mk-line);
}
.mk-bi { width: 12px; height: 7px; border-radius: 3px; background: var(--mk-ink-2); }
.mk-bi:first-child { background: var(--mk-accent); }

/* ==========================================================================
   Pane tabs — phone and tablet only

   On a narrow screen the split view is a losing proposition: two 160px columns
   are worse than one usable one. Below the breakpoint only one panel is
   mounted and this bar switches between them, which is also why the switch
   lives in the DOM on every screen — it costs one hidden element and saves a
   second template.
   ========================================================================== */

.panetabs { display: none; }

.ptab {
  flex: 1 1 0;
  min-height: 48px;
  border: 0;
  background: var(--surface);
  color: var(--ink-3);
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .02em;
  cursor: pointer;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}
.ptab[aria-selected="true"] {
  color: var(--accent-ink);
  background: var(--accent-soft);
  box-shadow: inset 0 2px 0 var(--accent);
}

/* Something changed in the panel you are not looking at. Cleared when you
   open it — otherwise a turn that quietly rewrites the setup is invisible. */
.ptab .dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  transition: opacity .16s;
}
.asm[data-work-dirty="true"] .ptab[data-pane="work"] .dot { opacity: 1; }

/* ==========================================================================
   Phone and tablet
   ========================================================================== */

@media (max-width: 900px) {
  .asm {
    /* dvh, not vh: on mobile Safari and Chrome vh is the *largest* viewport, so
       100vh puts the composer behind the browser's own toolbar. */
    height: 100dvh;
    font-size: 14px;
  }

  .bar { height: 52px; padding: 0 12px; gap: 10px; }
  .bar .logo { height: 17px; }
  /* The library counters and the section eyebrow are the first things to go —
     neither is why anyone opened the page on a phone. */
  .bar .eyebrow, .bar .div, .bar .meta { display: none; }
  .bar .sp { gap: 14px; }

  .body { min-height: 0; }
  .resizer { display: none; }

  /* One pane at a time. display:none rather than visibility so the hidden
     pane's scroll position and any GL canvas survive the switch. */
  .chatrail {
    width: 100% !important;
    min-width: 0;
    max-width: none;
    border-right: 0;
  }
  .work { border-left: 0; }
  .asm[data-pane="chat"] .work,
  .asm[data-pane="work"] .chatrail { display: none; }

  .panetabs {
    display: flex;
    flex-shrink: 0;
    border-top: 1px solid var(--line);
    /* Clears the iPhone home bar. Zero on everything else. */
    padding-bottom: env(safe-area-inset-bottom, 0);
    background: var(--surface);
  }

  .chathead { padding: 8px 14px; }
  .chathead__hint { display: none; }
  .log { padding: 13px 14px 6px; gap: 12px; }
  .msg.u { max-width: 92%; }
  .turnmeter { padding: 6px 14px; }
  .turnmeter .pip { width: 8px; }
  .compose { padding: 9px 14px 11px; }
  /* 16px is the threshold below which iOS Safari zooms the page on focus. */
  .compose textarea { font-size: 16px; padding: 10px; }
  .send { min-height: 46px; padding: 12px; }
  .seed { font-size: 12px; padding: 8px 13px; }

  .rail { padding: 7px 10px; gap: 0; scroll-snap-type: x proximity; }
  .st { min-width: 138px; flex: 0 0 auto; scroll-snap-align: start; min-height: 40px; }

  .stage { padding: 14px 12px 18px; }
  .h2 { font-size: 18px; }
  /* min-width:auto on a flex item is what lets a wide child stretch the
     column past the viewport; the panes must be free to shrink. */
  .work, .chatrail { min-width: 0; }
  .sub { font-size: 12px; margin-bottom: 13px; }

  /* Touch targets. A 28px-high pill is a coin toss with a thumb. */
  .chip { min-height: 38px; padding: 8px 13px; font-size: 12.5px; }
  .pick { padding: 11px 12px; }
  .act { min-height: 30px; }
  .site .acts { gap: 14px; }
  /* Taller rows for a thumb, and a shorter list: on a phone the map is what
     the user is aiming at, so the results must not bury it. */
  .hit { min-height: 44px; padding: 7px 10px; }
  .hits { max-height: 168px; }

  .gate { padding: 10px 12px; gap: 10px; }
  .gate .cont {
    min-height: 46px;
    width: 100%;
    margin-left: 0;
    /* nowrap here would make this label the page's minimum width. */
    white-space: normal;
  }
  .gatemsg { width: 100%; }

  /* A tablet still has room for two or three cells; only a phone does not.
     auto-fit with a 240px floor resolves to 1 column at 390px and 3 at 820
     without a second breakpoint. */
  .stat { grid-template-columns: repeat(auto-fit, minmax(46%, 1fr)); }
  .optgrid { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

  /* The gallery stacks: preview on top, the six templates listed under it.
     A 300px list column beside a preview leaves neither enough room.

     Vertical, not the horizontal strip this was. The strip fitted two cards on a
     390px screen, so the question the sheet is asking — which of these six? —
     had five of its answers off the side with nothing to say they were there.
     A list scrolls in the direction a phone already scrolls. */
  .modal__panel { width: 100%; max-height: 100dvh; border-radius: 0; }
  .modal__body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .tmview { order: 1; overflow: visible; }
  .tmlist {
    order: 2;
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: auto;
    border-top: 1px solid var(--line);
    padding: 8px 10px calc(10px + env(safe-area-inset-bottom));
  }
  .tmi { width: auto; min-height: 60px; }
  /* On a phone the preview must not eat the screen: fixed height, so the
     description and the list both stay in view. */
  .tmstage { flex: 0 0 auto; padding: 14px; min-height: 0; }
  .mk { height: 180px; min-height: 0; }
  .tmthumb .mk { height: 100%; }
  .tmfacts { padding: 14px 18px 16px; }
  .tmh { font-size: 20px; }
  /* "Choose the shape of your app" broke with "app" alone on line two. */
  .modal__title { font-size: 18px; }
  .modal__head { padding: 16px 18px 12px; }
  .modal__foot { padding: 12px 18px calc(14px + env(safe-area-inset-bottom)); }
  .modal__foot .cont { flex: 1; min-height: 46px; }
  .seg { margin-bottom: 13px; }
  .sgb { padding: 8px 12px; min-height: 44px; }
}

/* Phones proper — the two-column stat grid and the wide select stop paying. */
@media (max-width: 560px) {
  .stat { grid-template-columns: 1fr 1fr; }
  .fork, .thg, .optgrid { grid-template-columns: 1fr; }
  select.ind, input.txt { min-width: 0; width: 100%; font-size: 16px; }
  .mapbar { flex-wrap: wrap; }
  .mapbar .eyebrow { width: 100%; }
  .mapbar input { margin-left: 0; font-size: 16px; }
  .tgrid { grid-template-columns: 1fr; }
  .modbar { font-size: 11px; }
}

/* A pointer that cannot hover should not reserve hover styling, and a coarse
   pointer needs the rail to be swipeable rather than precise. */
@media (hover: none) {
  .st:not(.locked):hover { background: var(--surface-3); }
  .st.done:not(.locked):hover { background: var(--ok-soft); }
  .rail { -webkit-overflow-scrolling: touch; }
}

/* Landscape phone: vertical space is the scarce resource. */
@media (max-width: 900px) and (max-height: 480px) {
  .bar { height: 44px; }
  .chathead, .turnmeter { display: none; }
  .mapsvg, .mapgl { min-height: 0; max-height: 46dvh; }
  .sitecol { height: 220px; }
}

/* ==========================================================================
   Step 3 — what is left of the CRA panel

   The scores, the component bars and the band scale moved to the platform with
   the data they described; this page no longer draws a number. What stays is
   the warming pathway, which is configuration — it scales the climate component
   and so changes the figures the platform is built with — and the pill a
   not-yet-wired domain wears.
   ========================================================================== */

.craseg { margin-bottom: 14px; }
.navnote + .craseg { margin-top: 16px; }
.craseg .eyebrow { display: block; margin-bottom: 5px; }

.crapill {
  flex: 0 0 auto;
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--sunk);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* --- financial exposure: the figures, not the result ---------------------- */

/* One collapsible row per site. A disclosure, not a link: it opens a form
   rather than going anywhere, and the state on the right is the thing a reader
   scans for — which of my sites still needs figures. */
.crafins { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-2); }
.crafins .navpick__h { margin-bottom: 4px; }

.crafin {
  margin-top: 8px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  overflow: hidden;
}

.crafin__toggle {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 13px;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
  text-align: left;
  cursor: pointer;
}
.crafin__toggle:hover { background: var(--surface-2); }
.crafin__site {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crafin__state {
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .02em;
}
/* Group headings inside the asset form — Values, Interruption, Chronic,
   Building — served with the fields, same as the platform panel's. */
.crafin__group {
  margin: 14px 0 6px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.crafin__body .crafin__group:first-child { margin-top: 2px; }

.crafin__state[data-state="empty"] { background: var(--sunk); color: var(--ink-4); }
.crafin__state[data-state="part"]  { background: #fdf5e6; color: #8a5a06; }
.crafin__state[data-state="ready"] { background: var(--accent-soft); color: var(--accent-ink); }

.crafin__body { padding: 0 13px 13px; border-top: 1px solid var(--line-2); }
.crafin__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
  margin-bottom: 10px;
}

@media (max-width: 760px) {
  .crafin__grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   The Risk Navigator — step 3

   Two levels of tabs (domain, then mode) over one set of pickers. Both tab
   rows reuse `.seg` / `.sgb`, because they are the same interaction as the
   tracking-mode switch and the pillar tabs — a third bespoke tab style would
   make the page look assembled from parts.

   The pickers below them are chips rather than a third row of segments: a
   segmented control means "one of these", and sites are "any number of
   these". Same rounded vocabulary, different affordance.
   ========================================================================== */

.navlede {
  margin: 0 0 12px;
  font-size: 12px;
  font-weight: 300;
  line-height: 1.55;
  color: var(--ink-3);
}

.navbody { margin-top: 14px; }

.navmode__b {
  margin: 10px 0 14px;
  font-size: 12px;
  font-weight: 300;
  line-height: 1.55;
  color: var(--ink-3);
}

.navsrc {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: .02em;
  color: var(--ink-4);
}
p.navsrc { margin: 10px 0 0; }

/* --- a domain with no source yet ------------------------------------------
   Deliberately quiet. It is a placeholder, and dressing a placeholder up as a
   feature is how a customer ends up believing they bought one. */
.navplan {
  margin-top: 14px;
  padding: 16px;
  border: 1px dashed var(--line);
  border-radius: var(--r-lg);
  background: var(--sunk);
}
.navplan__h { display: flex; align-items: center; gap: 12px; }
.navplan__h h4 {
  flex: 1 1 auto;
  margin: 0;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink-2);
}
.navplan__b {
  margin: 8px 0 12px;
  font-size: 12px;
  font-weight: 300;
  line-height: 1.55;
  color: var(--ink-3);
}

.navpick { margin-bottom: 12px; }
.navpick__h {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 6px;
}
.navpick__h .eyebrow { flex: 1 1 auto; }

.navcap {
  flex: 0 0 auto;
  font-size: 10.5px;
  font-weight: 400;
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}

.navchips { display: flex; flex-wrap: wrap; gap: 6px; }

.navchip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 6px 11px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font: inherit;
  font-size: 12px;
  font-weight: 400;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.navchip:hover:not(:disabled) { border-color: var(--accent); color: var(--ink); }
.navchip.on {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-weight: 500;
}
.navchip:disabled { cursor: not-allowed; opacity: .55; }
/* An out-of-coverage site is shown, not hidden: someone who placed a pin in
   Cambodia should see why it is absent from the comparison. */
.navchip.off { background: var(--sunk); color: var(--ink-4); }
.navchip__t { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.navchip__x {
  font-size: 9.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-4);
}

.navnote {
  margin: 8px 0 0;
  font-size: 11px;
  font-weight: 300;
  line-height: 1.5;
  color: var(--ink-4);
}

@media (max-width: 760px) {
  .navchip__t { max-width: 130px; }
}

/* What this view becomes once the platform exists. The builder shows no data,
   so the one thing it owes the reader is a plain sentence about where the data
   will be. */
.navout {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-top: 16px;
  padding: 10px 13px;
  border: 1px solid var(--accent);
  border-left-width: 3px;
  border-radius: var(--r);
  background: var(--accent-soft);
}
.navout__k {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
.navout__v { font-size: 12px; font-weight: 400; color: var(--ink-2); line-height: 1.5; }

@media (max-width: 760px) {
  .navout { flex-direction: column; gap: 4px; }
}

/* -- what it will cost ----------------------------------------------------
   Step 5's price block. Reuses the configuration summary's rows so the money
   reads as one more line of the setup rather than as an advertisement bolted to
   the end of it — the only differences are two columns instead of three, and a
   total that is allowed to look like one.
   ------------------------------------------------------------------------- */

/* The order of events, above any number. Bordered like a quiet notice rather
   than coloured like a warning: it is good news. */
.pricetrial {
  margin: 0 0 10px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--r);
  background: var(--surface-2);
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-2);
}

.pricelede {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-3);
}

.cfgmoney {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
}
/* Sentence case, not the summary's uppercase micro-label: these are plan names
   and tier names, and setting a product name in tracked-out 10px capitals makes
   it read as a field label. */
.cfgmoney .cfl {
  font-size: 12.5px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
}
.cfgmoney .cfv { font-variant-numeric: tabular-nums; white-space: nowrap; }

.cfgmoney--total { background: var(--surface-2) !important; }
.cfgmoney--total .cfl { font-weight: 500; color: var(--ink); }
.cfgmoney--total .cfv { font-size: 15px; font-weight: 500; }

.pricenote {
  margin: 8px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-4);
}
