/* The app shell every mockup page is built from: the evaluator's page
   wrapper, the Book (rail + document), the phone Contents sheet, and Table
   mode.

   Extracted verbatim from look.html (#661), which keeps its own inline copy
   so the approved look page can never be broken by a change made here. If
   you change a rule in both places, say so; they are allowed to diverge,
   because look.html is a frozen record and this file is the living one. */

/* -- The evaluator's page (wrapper, not the product) -------------------- */
.page { max-width: 1560px; margin: 0 auto; padding: var(--sp-6) var(--sp-5) var(--sp-7); }
.masthead { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-5); flex-wrap: wrap; }
.masthead h1 { font-size: var(--step-3); }
.masthead .label { margin-bottom: var(--sp-2); display: block; }
.intro { max-width: 72ch; font-family: var(--serif); font-size: var(--step-1); line-height: 1.6; margin-top: var(--sp-4); }
.themebar { display: flex; gap: var(--sp-2); align-items: center; }
.themebar .btn[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); }
.contents-strip { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); margin-top: var(--sp-4); font-size: var(--step--1); }
.screen { margin-top: var(--sp-7); padding-top: var(--sp-5); border-top: 1px solid var(--rule-strong); }
.screen__head { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
/* A section that opens straight into a sub-heading (the "Found, settled, and
   open" sections) otherwise stacks h2, h3 and body with no air between them. */
.screen__head + h3 { margin-top: var(--sp-5); }
.screen > h3 + .prose { margin-top: var(--sp-2); }
.screen__num { font: 600 var(--step--1)/1 var(--sans); color: var(--accent); letter-spacing: .08em; text-transform: uppercase; }
.screen__cap { color: var(--ink-soft); max-width: 84ch; margin: var(--sp-2) 0 var(--sp-5); }
@media (min-width: 1640px) { .frames--pair { grid-template-columns: 390px minmax(0, 1fr); align-items: start; } }
.frame__box { position: relative; overflow: hidden !important; } /* the app inside scrolls, so bars can stay put */
.layer { position: absolute; inset: 0; transition: opacity .22s ease, transform .22s ease; }
.layer[hidden] { display: none; }
.layer--out { opacity: 0; transform: scale(.985); pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .layer { transition: none; } }

/* -- App shell ---------------------------------------------------------- */
.app { height: 100%; display: flex; flex-direction: column; container-type: inline-size; container-name: app; background: var(--paper); color: var(--ink); }
.app .appbar { position: static; flex: none; }
.appbar__title { font: 600 var(--step-0)/1.2 var(--serif); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.appbar__sub { font-size: var(--step--1); color: var(--ink-faint); }
.crumb { display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--ink-faint); font-size: var(--step--1); min-width: 0; }
.crumb b { color: var(--ink); font-weight: 600; }

/* -- Book: rail + document ---------------------------------------------- */
.book { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr); }
.book--rail { grid-template-columns: 236px minmax(0, 1fr); }
.rail { overflow-y: auto; border-right: 1px solid var(--rule); background: var(--paper-sunk); padding: var(--sp-5) var(--sp-3) var(--sp-5) var(--sp-4); }
.rail__title { font: 600 var(--step-1)/1.25 var(--serif); }
.rail__meta { font-size: var(--step--1); color: var(--ink-faint); margin: 2px 0 var(--sp-4); }
.rail .label { display: block; margin: 0 .6rem var(--sp-2); }
.rail__group { margin-top: var(--sp-5); }
.rail__back { margin-top: var(--sp-6); }
.toc { list-style: none; margin: 0; padding: 0; }
.toc button, .toc a {
  display: flex; width: 100%; align-items: center; justify-content: space-between; gap: var(--sp-2);
  text-align: left; background: none; border: 0; border-left: 2px solid transparent;
  padding: .42rem .6rem; font: 500 var(--step-0)/1.3 var(--sans); color: var(--ink-soft);
  cursor: pointer; border-radius: 0 var(--r-1) var(--r-1) 0; text-decoration: none;
}
.toc button:hover, .toc a:hover { color: var(--ink); background: var(--paper-raised); }
.toc [aria-current="page"] { color: var(--accent-ink); border-left-color: var(--accent); font-weight: 600; background: var(--paper-raised); }
.toc__count { font: 500 var(--step--1)/1 var(--mono); color: var(--ink-faint); }
.toc--sub { margin: 2px 0 var(--sp-2) .7rem; border-left: 1px solid var(--rule-strong); }
.toc--sub button { font-size: var(--step--1); padding: .32rem .6rem; border-left: 0; color: var(--ink-faint); }
.toc--sub [aria-current="location"] { color: var(--accent-ink); font-weight: 600; background: none; }
.book__main { overflow-y: auto; min-height: 0; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { .book__main { scroll-behavior: auto; } }
.doc { padding: var(--sp-6) var(--sp-7) var(--sp-7); max-width: 1240px; }
@container app (max-width: 640px) { .doc { padding: var(--sp-4) var(--sp-4) var(--sp-7); } }
.doc > .label { display: block; margin-bottom: var(--sp-2); }
.doc h1 { margin-bottom: var(--sp-2); }
.doc__lead { font: var(--step-1)/1.5 var(--serif); color: var(--ink-soft); max-width: 64ch; margin-bottom: var(--sp-2); }
.doc__meta { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; color: var(--ink-soft); font-size: var(--step--1); }
.doc__grid { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--sp-6) var(--sp-7); align-items: start; margin-top: var(--sp-5); }
.doc__grid--wide { grid-template-columns: minmax(0, 1fr) 400px; }
@container app (max-width: 860px) { .doc__grid, .doc__grid--wide { grid-template-columns: minmax(0, 1fr); } }
.aside { display: grid; gap: var(--sp-5); }
.aside .label { display: block; margin-bottom: var(--sp-2); }
.sec { padding-top: var(--sp-5); margin-top: var(--sp-5); border-top: 1px solid var(--rule); scroll-margin-top: var(--sp-4); }
.sec--first { border-top: 0; margin-top: 0; padding-top: var(--sp-3); }
.sec > h2 { font-size: var(--step-2); margin-bottom: var(--sp-3); }
.sec > h3 { font-size: var(--step-1); margin-bottom: var(--sp-2); }
.sec__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-3); }
.sec__head h2 { font-size: var(--step-2); }
.kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--sp-1) var(--sp-4); margin: 0; }
.kv dt { color: var(--ink-faint); } .kv dd { margin: 0; }
.stat-row { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.stat-row b { display: block; font: 600 var(--step-3)/1.1 var(--serif); }
.stat-row span { font-size: var(--step--1); color: var(--ink-faint); }

/* -- Lists -------------------------------------------------------------- */
.list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-3); overflow: hidden; }
.list > li { background: var(--paper-raised); padding: var(--sp-3) var(--sp-4); display: flex; align-items: center; gap: var(--sp-3); }
.list__main { min-width: 0; flex: 1; }
.list__title { font-weight: 600; }
.list__sub { font-size: var(--step--1); color: var(--ink-faint); }
.list__end { margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--step--1); color: var(--ink-soft); white-space: nowrap; }
.roster__char { font: 600 var(--step-0)/1.2 var(--serif); }
.who__disc--gm { background: var(--ink); color: var(--paper); }
.who__disc--off { background: var(--paper-sunk); color: var(--ink-faint); border: 1px dashed var(--rule-strong); }

.rsvp { display: flex; gap: var(--sp-2); }
.rsvp .btn { flex: 1; min-height: 44px; }
.rsvp .btn[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); box-shadow: inset 0 0 0 1px var(--accent); }

.hero { display: grid; gap: var(--sp-2); }
.hero__when { font: 600 var(--step-3)/1.15 var(--serif); }
.hero__alt { color: var(--ink-soft); font-size: var(--step-1); }
.hero__title { font: italic var(--step-1)/1.4 var(--serif); color: var(--ink-faint); }

.campgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: var(--sp-4); }
@container app (max-width: 640px) { .campgrid { grid-template-columns: minmax(0, 1fr); } }
.camp { display: grid; gap: var(--sp-3); align-content: start; }
.camp__name { font-size: var(--step-2); }
.camp__meta { font-size: var(--step--1); color: var(--ink-faint); }
.camp__week { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-1) var(--sp-3); font-size: var(--step-0); margin: 0; }
.camp__week dt { color: var(--ink-faint); } .camp__week dd { margin: 0; }
.camp__last { font: var(--step-0)/1.55 var(--serif); color: var(--ink-soft); border-left: 3px solid var(--rule-strong); padding-left: var(--sp-3); margin: 0; }
.camp__last b { font-weight: 600; color: var(--ink); font-style: normal; }

.slist { list-style: none; margin: 0; padding: 0; }
.slist > li { display: grid; grid-template-columns: 3.4rem minmax(0, 1fr) auto; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--rule); align-items: baseline; }
.slist > li:first-child { border-top: 0; }
.slist__n { font: 500 var(--step--1)/1.6 var(--mono); color: var(--ink-faint); }
.slist__title { font: 600 var(--step-1)/1.3 var(--serif); }
.slist__title button { all: unset; cursor: pointer; color: var(--accent); text-decoration: underline; text-underline-offset: 3px; font: inherit; }
.slist__title button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.slist__line { font: var(--step-0)/1.5 var(--serif); color: var(--ink-soft); }
.slist__when { font-size: var(--step--1); color: var(--ink-faint); white-space: nowrap; }
.slist--x .slist__title { color: var(--ink-faint); text-decoration: line-through; font-weight: 400; }
/* Every row is padded at the sides, so the highlighted one keeps its number
   and date inside the tint, lines up with the rows around it, and stays within
   the column like the cards above it. It used to reach into the gutter with a
   padding that .slist > li silently overrode, leaving its content against its
   edges (lane 2c's review). */
.slist > li.slist--up { background: var(--accent-soft); border-radius: var(--r-2); border-top-color: transparent; }
.slist > li.slist--up + li { border-top-color: transparent; }

.quote { font: italic var(--step-1)/1.5 var(--serif); border-left: 3px solid var(--rule-strong); padding-left: var(--sp-4); margin: 0 0 var(--sp-4); max-width: 60ch; }
.quote cite { display: block; font: 500 var(--step--1)/1.3 var(--sans); color: var(--ink-faint); font-style: normal; margin-top: var(--sp-1); }

/* Event log (the disclosure around the kit's .events rows) */
.log > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-raised); }
.log > summary::-webkit-details-marker { display: none; }
.log > summary:hover { border-color: var(--rule-strong); }
.log[open] > summary { border-radius: var(--r-3) var(--r-3) 0 0; }
.log__chev { display: inline-block; width: 1.1rem; text-align: center; color: var(--ink-faint); transition: transform .18s; }
.log[open] .log__chev { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .log__chev { transition: none; } }
.log__sum { font-weight: 600; }
.log__sub { font-size: var(--step--1); color: var(--ink-faint); }
.log__body { border: 1px solid var(--rule); border-top: 0; border-radius: 0 0 var(--r-3) var(--r-3); padding: var(--sp-3) var(--sp-3) var(--sp-4); background: var(--paper-sunk); }
.log__filters { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-3); }
.chip[aria-pressed="true"]:not(.qbw *) { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); } /* never recolour the shared wiki chips */
.chip--btn { cursor: pointer; }
.events__row[hidden] { display: none; }
.ev-kind { display: inline-block; margin-left: var(--sp-2); font: 600 var(--step--1)/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--ink-faint); }
.ev-kind--reveal { color: var(--accent); } .ev-kind--decision { color: var(--warn); }

/* -- Prep: document with tools in the margin ---------------------------- */
.prep { display: grid; grid-template-columns: minmax(0, 1fr) 272px; gap: var(--sp-6) var(--sp-7); align-items: start; margin-top: var(--sp-5); }
.margin { position: sticky; top: 0; display: grid; gap: var(--sp-2); }
.margin .label { display: block; margin-bottom: var(--sp-1); }
.tool { justify-content: flex-start; text-align: left; width: 100%; min-height: 44px; }
.tool small { display: block; font-weight: 400; color: var(--ink-faint); font-size: var(--step--1); }
.tool[aria-expanded="true"] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-ink); }
.drawer { border: 1px solid var(--rule-strong); border-radius: var(--r-3); padding: var(--sp-3); background: var(--paper-raised); box-shadow: var(--shadow); display: grid; gap: var(--sp-2); }
.drawer[hidden] { display: none; }
.drawer .label { margin: 0; }
.want { font: var(--step-1)/1.6 var(--serif); background: var(--paper-sunk); border: 1px solid var(--rule); border-radius: var(--r-3); padding: var(--sp-4) var(--sp-5); max-width: 64ch; margin: 0; }
.beats { padding-left: 1.5rem; margin: 0; font: var(--step-1)/1.55 var(--serif); max-width: 64ch; }
.beats li { margin-bottom: var(--sp-2); padding-left: .25rem; }
.ins { border: 1px solid var(--rule); border-left: 3px solid var(--accent); border-radius: var(--r-2); background: var(--paper-raised); padding: var(--sp-3) var(--sp-4); margin: 0 0 var(--sp-3); max-width: 72ch; }
.ins__head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); flex-wrap: wrap; }
.ins__head .label { color: var(--accent); }
.ins__src { font-size: var(--step--1); color: var(--ink-faint); margin-left: auto; }
.ins__out { font: var(--step-1)/1.55 var(--serif); }
.ins__actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); flex-wrap: wrap; }
.ins--new { animation: settle .6s ease; }
@keyframes settle { from { background: var(--accent-soft); } }
@media (prefers-reduced-motion: reduce) { .ins--new { animation: none; } }
.statline { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); font: var(--step--1)/1.6 var(--mono); color: var(--ink-soft); margin-top: var(--sp-1); }
.pack { display: inline-flex; align-items: center; gap: .35rem; font-size: var(--step--1); color: var(--ink-faint); }
.pack::before { content: ""; width: .5rem; height: .5rem; border-radius: 2px; background: var(--rule-strong); }
.pack--campaign::before { background: var(--warn); }
.pack--instance::before { background: var(--accent); }

/* -- Phone: Contents sheet ---------------------------------------------- */
.sheet { position: absolute; inset: 0; z-index: 20; display: grid; align-items: end; }
.sheet[hidden] { display: none; }
.sheet__scrim { position: absolute; inset: 0; width: 100%; border: 0; background: rgba(20, 22, 26, .45); cursor: pointer; }
.sheet__panel { position: relative; background: var(--paper-raised); border-radius: var(--r-4) var(--r-4) 0 0; padding: var(--sp-3) var(--sp-4) var(--sp-5); max-height: 82%; overflow: auto; box-shadow: 0 -8px 30px rgba(0, 0, 0, .28); }
.sheet__grip { width: 2.5rem; height: 4px; border-radius: 4px; background: var(--rule-strong); margin: 0 auto var(--sp-3); }
.sheet .toc button { min-height: 44px; font-size: var(--step-1); }
.sheet .toc--sub button { min-height: 40px; font-size: var(--step-0); }
.livebar { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); background: var(--live-soft); border-bottom: 1px solid var(--live); color: var(--ink); flex: none; }
.livebar .btn--primary { margin-left: auto; white-space: nowrap; flex: none; }

/* -- Table mode --------------------------------------------------------- */
.tm { height: 100%; display: flex; flex-direction: column; background: var(--table-bg); color: var(--table-ink); }
.tm__bar { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) var(--sp-5); border-bottom: 1px solid var(--table-rule); background: var(--table-raised); flex: none; }
.tm__body { flex: 1; min-height: 0; overflow: auto; padding: var(--sp-5); }
.tm__grid { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: var(--sp-5); align-items: start; }
.tm .btn { min-height: 44px; }
.tm .btn--stop { border-color: var(--live); color: var(--live); }
.tm .field { background: var(--table-bg); border-color: var(--table-rule); color: var(--table-ink); min-height: 44px; font-size: var(--step-1); }
.tm .field::placeholder { color: var(--table-soft); }
.tm .who__disc { background: #2b3340; color: var(--table-ink); }
.tm .ev-kind, .tm .faint, .tm .list__end { color: var(--table-soft); }
.rec { display: inline-flex; align-items: center; gap: var(--sp-2); font: 600 var(--step-0)/1 var(--sans); color: var(--live); white-space: nowrap; }
.clock { font: 600 var(--step-2)/1 var(--mono); font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.speakers { display: flex; gap: var(--sp-2); align-items: center; }
.spk { width: 2.25rem; height: 2.25rem; border-radius: 999px; display: grid; place-items: center; background: var(--table-raised); border: 1px solid var(--table-rule); color: var(--table-soft); font: 600 var(--step--1)/1 var(--sans); }
.spk--talking { border-color: var(--accent); color: var(--table-ink); box-shadow: 0 0 0 3px rgba(111, 188, 174, .28); }
.spk--absent { opacity: .38; border-style: dashed; }
.tm__meta { display: grid; line-height: 1.25; min-width: 0; }
.tm__meta b { font-family: var(--serif); font-weight: 600; white-space: nowrap; }
.tm__meta span { font-size: var(--step--1); color: var(--table-soft); white-space: nowrap; }
.spot { background: var(--table-raised); border: 1px solid var(--table-rule); border-radius: var(--r-4); padding: var(--sp-6); display: grid; gap: var(--sp-3); }
.spot__title { font: 600 var(--step-4)/1.15 var(--serif); }
.spot__line { font: var(--step-2)/1.4 var(--serif); max-width: 40ch; }
.spot__actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-2); }
.tag { font: 600 var(--step--1)/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--table-soft); }
.tag--on { color: var(--accent); }
.shelf { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: var(--sp-3); margin-top: var(--sp-3); }
.tc { background: var(--table-raised); border: 1px solid var(--table-rule); border-radius: var(--r-3); padding: var(--sp-4); display: grid; gap: var(--sp-2); text-align: left; color: var(--table-ink); cursor: pointer; min-height: 132px; font: inherit; align-content: start; }
.tc:hover { border-color: var(--table-soft); }
.tc--on { border-color: var(--accent); }
.tc--spot { outline: 2px solid var(--accent); outline-offset: 2px; }
.tc__title { font: 600 var(--step-1)/1.2 var(--serif); }
.tc__line { font-size: var(--step--1); color: var(--table-soft); line-height: 1.45; }
.tc__foot { display: flex; gap: var(--sp-2); align-items: center; margin-top: auto; padding-top: var(--sp-1); }
.tm h2 { font-size: var(--step-2); }
.tm .sec { border-top-color: var(--table-rule); }
.lookup { display: grid; gap: var(--sp-3); }
.lookup__group { display: grid; gap: var(--sp-2); }
.lookup__group .label { margin-top: var(--sp-1); }
.lk { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-3); align-items: center; padding: var(--sp-3); background: var(--table-raised); border: 1px solid var(--table-rule); border-radius: var(--r-2); }
.lk__title { font: 600 var(--step-0)/1.25 var(--serif); }
.lk__meta { font-size: var(--step--1); color: var(--table-soft); line-height: 1.4; }
.lk__meta em { font-style: normal; color: var(--table-ink); }
.lk--empty { color: var(--table-soft); font-size: var(--step--1); padding: var(--sp-2) 0; }
.note { width: 100%; min-height: 96px; background: var(--table-bg); color: var(--table-ink); border: 1px solid var(--table-rule); border-radius: var(--r-2); padding: var(--sp-3); font: var(--step-0)/1.5 var(--sans); resize: vertical; }
.note::placeholder { color: var(--table-soft); }
.tm .lk .btn--sm { min-height: 40px; }
.here { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.here li { display: flex; align-items: center; gap: var(--sp-2); }

/* Book-side lookup (prep page and wiki page use the same result rows on paper) */
.lookup--paper .lk { background: var(--paper-raised); border-color: var(--rule); }
.lookup--paper .lk__meta { color: var(--ink-faint); }
.lookup--paper .lk__meta em { color: var(--ink); }
.lookup--paper .lk--empty { color: var(--ink-faint); }

/* Phone table face */
.tmp .tm__bar { padding: var(--sp-3) var(--sp-4); gap: var(--sp-3); }
.tmp .tm__body { padding: var(--sp-4); display: grid; gap: var(--sp-5); align-content: start; }
.pc { background: var(--table-raised); border: 1px solid var(--accent); border-radius: var(--r-4); padding: var(--sp-5); display: grid; gap: var(--sp-2); }
.pc__title { font: 600 var(--step-3)/1.15 var(--serif); }
.pc__line { font: var(--step-1)/1.45 var(--serif); }
.tmp .btn { min-height: 48px; }
.tmp .btn--sm { min-height: 40px; }

/* -- The wiki: chapters of the book (Screens 6–11) ------------------------
   Layout glue only. Everything inside a wiki page is a shared component
   (shared/wiki.js + the kit's qbw- styles); this places them on the page. */
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.toc__tag { display: inline-block; margin-left: .4rem; padding: .14rem .38rem; vertical-align: .1em; border: 1px dashed var(--gm); border-radius: 999px; font: 700 .625rem/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--gm); }
.leafbar { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-4); flex-wrap: wrap; margin: calc(-1 * var(--sp-2)) 0 var(--sp-4); }
.leafbar__back { padding-left: 0; }
.leafbar__end { display: flex; align-items: center; gap: var(--sp-2) var(--sp-4); flex-wrap: wrap; margin-left: auto; }
.viewas { display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.pv-note { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-3); margin: 0 0 var(--sp-5); padding: var(--sp-3) var(--sp-4); border: 1px solid var(--accent); border-radius: var(--r-3); background: var(--accent-soft); color: var(--accent-ink); font-size: var(--step--1); }
.leaf { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--sp-6) var(--sp-7); align-items: start; }
.leaf--wide { grid-template-columns: minmax(0, 1fr) 400px; }
@container app (max-width: 1180px) { .leaf, .leaf--wide { grid-template-columns: minmax(0, 1fr); } }
.leaf__main, .leaf__side { min-width: 0; }
.leaf__side { display: grid; gap: var(--sp-5); align-content: start; }
.leaf__side .sec { margin-top: 0; }
.leaf__side .sec > h2, .leaf__side .sec__head h2 { font-size: var(--step-1); }
.leaf__body { margin-top: var(--sp-5); }
.pstack { display: grid; gap: var(--sp-5); margin-top: var(--sp-5); }
.leafdoc .sec > h2 { font-size: var(--step-1); }
.shelfpage { max-width: 56rem; margin-top: var(--sp-4); }
.turn { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-top: var(--sp-6); padding-top: var(--sp-3); border-top: 1px solid var(--rule); }
.turn .btn { display: inline-block; max-width: 42%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.turn__n { font-size: var(--step--1); color: var(--ink-faint); text-align: center; }
@container app (max-width: 640px) { .turn__n { display: none; } .turn .btn { max-width: 48%; } }

/* Front page */
.wsearch { display: grid; gap: var(--sp-2); }
.wsearch .field { min-height: 44px; font-size: var(--step-1); }
.wsearch__try { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--step--1); color: var(--ink-faint); }
.wsearch__out:not(:empty) { margin-top: var(--sp-4); }
.mapthumb-wrap { position: relative; }
.mapthumb .qbw-map__top, .mapthumb .qbw-map__atlases, .mapthumb .qbw-map__filters, .mapthumb .qbw-map__note, .mapthumb .qbw-map__legend { display: none; }
.mapthumb .qbw-map__scroll { overflow: hidden; }
/* At thumbnail size the session badges sit on the party's label; the full map keeps them. */
.mapthumb .qbw-wp { display: none; }
.mapthumb__open { position: absolute; inset: 0; width: 100%; padding: 0; border: 0; border-radius: var(--r-3); background: transparent; cursor: pointer; }
.mapthumb__open:hover { box-shadow: inset 0 0 0 2px var(--accent); }
.mapthumb__cap { margin: var(--sp-2) 0 0; font-size: var(--step--1); color: var(--ink-soft); }
.toc--browse { border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-raised); padding: var(--sp-1) 0; }
.toc--browse button { border-left: 0; border-radius: 0; }
.sugg { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.sugg > li { display: grid; gap: var(--sp-1); padding: var(--sp-3); border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-raised); }
.sugg__top { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); font: 600 var(--step-0)/1.3 var(--serif); }
.sugg__line { margin: 0; font-size: var(--step--1); color: var(--ink-soft); }
.sugg__src { font-size: .75rem; color: var(--ink-faint); }
.sugg__acts { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-1); }
.wf-health .log__sub { font-size: var(--step--1); }

/* Map plate, quests, rules, editor */
.plate { max-width: 980px; margin-top: var(--sp-4); }
.qbw-qlog li.is-open { box-shadow: inset 3px 0 0 var(--accent); } /* you are here, in the quest log */
.rulelist > li.is-open { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
.edstates { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); padding: var(--sp-2) var(--sp-3); border: 1px dashed var(--rule-strong); border-radius: var(--r-3); }
.ednote { max-width: 84ch; margin: 0 0 var(--sp-4); font-size: var(--step--1); color: var(--ink-soft); }
.ednote code { font: .9em var(--mono); background: var(--paper-sunk); border: 1px solid var(--rule); border-radius: 3px; padding: 0 .25em; }

/* Table mode: a wiki page as a card, without leaving the table */
.lk__acts { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2); }
.peek { display: grid; gap: var(--sp-3); padding: var(--sp-4); background: var(--table-raised); border: 1px solid var(--accent); border-radius: var(--r-3); }
.peek[hidden] { display: none; }
.peek__head { display: flex; align-items: center; gap: var(--sp-2); }
.tm .peek .btn { min-height: 40px; }
.peek .qbw-head__title { font-size: var(--step-2); }


/* ── Shell rules that sat just past the extracted range ──────────────────
   look.html keeps these in its page-local block (lines 364-370) because it
   added them for #661, but they belong to the shell: every page that draws
   a Contents entry or the bell needs them. */
.qi { margin-right: .3em; }
.toc button > span:first-child, .toc a > span:first-child { display: inline-flex; align-items: center; gap: .4em; }
.appbar__bell { position: relative; }
.appbar__badge {
  position: absolute; top: -4px; right: -4px; min-width: 1.1em; height: 1.1em; padding: 0 .3em;
  border-radius: 999px; background: var(--live); color: #fff; font: 700 .625rem/1.1em var(--sans); text-align: center;
}

/* ══ Lane 1 (#659): search, the account menu, the bell ═══════════════════
   New; look.html has no equivalent. ───────────────────────────────────── */

/* SH-9 search in the bar (#667) */
.appsearch {
  position: relative; display: flex; align-items: center; flex: 0 1 17rem; min-width: 0;
}
.appsearch__icon { position: absolute; left: .55rem; color: var(--ink-faint); pointer-events: none; margin: 0; }
.appsearch__input {
  width: 100%; min-height: 34px; padding: .32rem .6rem .32rem 2rem;
  background: var(--paper); border: 1px solid var(--rule); border-radius: var(--r-2);
  font: 400 var(--step--1)/1.3 var(--sans); color: var(--ink);
}
.appsearch__input::placeholder { color: var(--ink-faint); }
.appsearch__input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.appsearch__input::-webkit-search-cancel-button { cursor: pointer; }

/* The results, and the two menus, share one popover shape. */
.anchor { position: relative; }
/* A panel must never be taller than there is room for, or its bottom — the
   footer, which is how you reach notification settings — is cut off and
   unreachable (owner's review, 15 September). So it caps its own height and
   is a column: the head and the foot stay put, and the middle scrolls. */
.menu {
  position: absolute; top: calc(100% + .4rem); right: 0; z-index: 40; width: 17rem;
  display: flex; flex-direction: column; max-height: 32rem;
  background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--r-3);
  box-shadow: var(--shadow-lift, 0 10px 30px rgba(0,0,0,.18)); overflow: hidden;
}
.menu[hidden] { display: none; }
.menu__head, .menu__foot, .menu__me, .menu__theme { flex: none; }
.menu__scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.menu--wide { width: 24rem; }
.menu__me { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); border-bottom: 1px solid var(--rule); }
.menu__name { font: 600 var(--step-0)/1.2 var(--sans); }
.menu__pron { font-size: var(--step--1); color: var(--ink-faint); }
.menu__list { list-style: none; margin: 0; padding: var(--sp-2) 0; }
.menu__list--last { border-top: 1px solid var(--rule); }
.menu__list button {
  display: flex; align-items: center; width: 100%; gap: .1rem; text-align: left;
  background: none; border: 0; padding: .5rem var(--sp-4); cursor: pointer;
  font: 500 var(--step-0)/1.3 var(--sans); color: var(--ink);
}
.menu__list button:hover { background: var(--paper-sunk); }
.menu__theme { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--rule); }
.menu__theme .label { display: flex; align-items: center; margin-bottom: var(--sp-2); }
.seg { display: flex; border: 1px solid var(--rule); border-radius: var(--r-2); overflow: hidden; }
.seg__btn {
  flex: 1; background: var(--paper); border: 0; border-right: 1px solid var(--rule);
  padding: .35rem .2rem; cursor: pointer; font: 500 var(--step--1)/1.3 var(--sans); color: var(--ink-soft);
}
.seg__btn:last-child { border-right: 0; }
.seg__btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-ink); font-weight: 600; }
.menu__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--rule); }
.menu__foot { padding: var(--sp-2) var(--sp-3); border-top: 1px solid var(--rule); background: var(--paper-sunk); }
.menu__empty { padding: var(--sp-5) var(--sp-4); color: var(--ink-soft); font-size: var(--step--1); text-align: center; }

/* The identity disc is a button now that it opens a menu (SH-4). */
.appbar__me { background: none; border: 0; padding: 0; cursor: pointer; line-height: 0; border-radius: 999px; }
.appbar__me:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* SH-5 notification rows. Scrolling belongs to .menu__scroll around it. */
.notes { list-style: none; margin: 0; padding: 0; }
.notes__row {
  display: grid; grid-template-columns: .9rem 1.2rem minmax(0, 1fr); gap: var(--sp-2);
  align-items: start; padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--rule);
}
.notes__row:last-child { border-bottom: 0; }
.notes__row:hover { background: var(--paper-sunk); }
.notes__mark { display: flex; justify-content: center; padding-top: .45em; }
.notes__dot { width: .45rem; height: .45rem; border-radius: 999px; background: var(--accent); }
.notes__icon { color: var(--ink-faint); margin: .1em 0 0; }
.notes__what { display: block; font-size: var(--step--1); line-height: 1.45; }
.notes__row--unread .notes__what { font-weight: 600; }
.notes__meta { display: block; margin-top: 2px; font-size: .75rem; color: var(--ink-faint); }

/* The phone bar carries five things now; the wordmark shrinks to a mark. */
.appbar--phone { gap: var(--sp-2); }
.appbar__brand--mark { font-size: var(--step-1); letter-spacing: -.02em; }

/* SH-9 results */
.sr { list-style: none; margin: 0; padding: 0; }
.sr__group { padding: var(--sp-3) 0 var(--sp-2); border-bottom: 1px solid var(--rule); }
.sr__group:last-of-type { border-bottom: 0; }
.sr__group > .label { display: block; padding: 0 var(--sp-4) var(--sp-1); }
.sr__row button {
  display: grid; grid-template-columns: 1.2rem minmax(0, 1fr); gap: var(--sp-2); width: 100%;
  text-align: left; background: none; border: 0; padding: .4rem var(--sp-4); cursor: pointer; color: var(--ink);
}
.sr__row button:hover { background: var(--paper-sunk); }
.sr__icon { color: var(--ink-faint); margin: .15em 0 0; }
.sr__title { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; font: 600 var(--step--1)/1.35 var(--sans); }
.sr__kind { font: 500 .7rem/1 var(--sans); color: var(--ink-faint); text-transform: lowercase; }
.sr__line { display: block; font-size: .78rem; line-height: 1.4; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr__all { margin: 0 var(--sp-3) var(--sp-1); }

/* ── Round two of lane 1 (#659), from the owner's review ─────────────────
   The "You" group at the foot of the phone Contents sheet, and the footer. */

/* The phone sheet is a PAPER panel (.sheet__panel uses --paper-raised), not
   the dark chrome the desktop rail is painted in — so the You group inside it
   takes paper colours. Drawing it on chrome made its own text invisible. */
.you { border-top: 1px solid var(--rule); padding-top: var(--sp-4); margin-top: var(--sp-5); color: var(--ink); }
.you__me { display: flex; align-items: center; gap: var(--sp-3); padding: 0 .6rem var(--sp-3); }
.you__name { font: 600 var(--step-0)/1.2 var(--sans); }
.you__pron { font-size: var(--step--1); color: var(--ink-faint); }
.you__theme { padding: var(--sp-3) .6rem var(--sp-2); }
.you__theme .label { display: flex; align-items: center; margin-bottom: var(--sp-2); }
.you .toc button { color: var(--ink); }
.you .toc button:hover { background: var(--paper-sunk); }

.foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: .1rem .55rem;
  padding: var(--sp-4) var(--sp-7); border-top: 1px solid var(--rule);
  font-size: var(--step--1); color: var(--ink-faint);
}
@container app (max-width: 640px) { .foot { padding: var(--sp-4); } }
.foot a { color: var(--ink-soft); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
.foot a:hover { color: var(--accent-ink); }
.foot__sep { opacity: .5; }
.foot__v { font-variant-numeric: tabular-nums; }
/* Table mode is furniture at a table; a licence link has no business there. */
.tablemode .foot, .tm .foot { display: none; }

/* ══ Lane 2 (#659): the campaign core ════════════════════════════════════
   The live-session bar (SH-6), the campaign banners (SH-8), and the page
   furniture the four campaign screens share. SH-6 had no features placed on
   it at all until 2026-09-16 — the six rows it now carries (IS-304..309)
   were written while drawing this lane.
   ─────────────────────────────────────────────────────────────────────── */

/* ── SH-6 · the live-session bar ──────────────────────────────────────────
   Three states, not one. A session's status and whether the bot is recording
   are independent (IS-306), so the bar must be able to say "we are playing"
   without claiming "we are recording" — and must say so again, differently,
   when the recording it was reporting has gone quiet (IS-001's honesty rule).
   Colour is never the only carrier: each state says its own words. */
.livebar__body { display: grid; gap: .1rem; min-width: 0; }
.livebar__meta { font-size: var(--step--1); color: var(--ink-soft); }
/* The extracted rule above only pushes a --primary button to the right edge;
   the "go there" bar's button is secondary and was left stranded against the
   text. Whatever the bar's one button is, it belongs at the end. */
.livebar > .btn:last-child { margin-left: auto; white-space: nowrap; flex: none; }
/* The clock now sits inside the bar's title, which is bold sans; it keeps the
   tabular figures and the mono face but not the display size. */
.livebar__body b .clock { font-size: inherit; }
.livebar--quiet { background: var(--paper-sunk); border-bottom-color: var(--rule-strong); }
.livebar--stale { background: var(--warn-soft); border-bottom-color: var(--warn); }
/* On a phone the bar is sticky and shares the only row of chrome the screen
   has, so the meta line is dropped rather than wrapped. */
@container app (max-width: 640px) {
  .livebar { position: sticky; top: 0; z-index: 3; padding: var(--sp-2) var(--sp-3); }
  .livebar .livebar__meta { display: none; }
}

/* ── SH-8 · campaign-wide banners ─────────────────────────────────────────
   Up to five can apply at once and the ledger never said how they stack, so
   this decides it: one at a time, worst first, the rest folded behind a line
   that names them. Five stacked banners is a wall between a person and their
   campaign. */
.banners { display: grid; gap: var(--sp-2); padding: var(--sp-4) var(--sp-7) 0; }
.banner {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--rule-strong); border-left-width: 3px;
  border-radius: var(--r-2); background: var(--paper-raised);
}
.banner .qi { flex: none; margin-top: .1rem; }
.banner__body { display: grid; gap: .2rem; min-width: 0; flex: 1; }
.banner__t { font: 600 var(--step-0)/1.35 var(--sans); }
.banner__d { font-size: var(--step--1); color: var(--ink-soft); }
.banner__acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
/* Where there is no room beside the text, the buttons drop beneath it rather
   than squeezing it to a word a line (lane 1b's review). The icon is taken out
   of the flow so that only the buttons can wrap -- never the text away from
   its icon. */
.banner { flex-wrap: wrap; position: relative; }
.banner:has(> .qi) { padding-inline-start: calc(var(--sp-4) + 1.15em + var(--sp-3)); }
.banner > .qi { position: absolute; inset-inline-start: var(--sp-4); top: calc(var(--sp-3) + .1rem); margin: 0; }
.banner__body { flex: 1 1 20rem; }
.banner__acts { margin-inline-start: auto; }
.banner--warn { border-color: var(--warn); background: var(--warn-soft); }
.banner--warn .banner__d { color: var(--ink); }
.banner--live { border-color: var(--live); background: var(--live-soft); }
.banner--gm { border-color: var(--gm); background: var(--gm-soft); }
.banner--quiet { border-left-color: var(--rule-strong); background: var(--paper-sunk); }
/* The fold. It names what is behind it rather than saying "2 more". */
.banner__more {
  justify-self: start; font: var(--step--1) var(--sans); color: var(--ink-soft);
  background: none; border: 0; padding: .2rem 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px; text-align: left;
}
.banner__more:hover { color: var(--accent-ink); }
@container app (max-width: 640px) { .banners { padding: var(--sp-3) var(--sp-4) 0; } }

/* ── Tabs (CAMP-2's Upcoming / Completed / Cancelled) ─────────────────── */
.tabs { display: flex; gap: var(--sp-1); flex-wrap: wrap; border-bottom: 1px solid var(--rule); margin-bottom: var(--sp-4); }
.tabs__btn {
  font: 600 var(--step-0)/1 var(--sans); color: var(--ink-soft);
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: var(--sp-3); margin-bottom: -1px; cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--sp-2);
}
.tabs__btn:hover { color: var(--ink); }
.tabs__btn[aria-selected="true"] { color: var(--accent-ink); border-bottom-color: var(--accent); }
.tabs__n { font-size: var(--step--1); color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.tabs__btn[aria-selected="true"] .tabs__n { color: var(--accent-ink); }

/* ── Forms (CAMP-3's session form, CAMP-9/12's settings) ──────────────── */
.form { display: grid; gap: var(--sp-4); max-width: 46rem; }
.form__row { display: grid; gap: var(--sp-2); min-width: 0; }
.form__lab { font: 600 var(--step--1)/1.3 var(--sans); }
.form__hint { font-size: var(--step--1); color: var(--ink-soft); }
.form__err { font-size: var(--step--1); color: var(--warn); display: flex; align-items: center; gap: var(--sp-2); }
/* align-items: start matters. Each cell is itself a grid of label/field/hint
   with auto rows, so a stretched cell distributes the spare height between
   those rows -- and the moment one side's hint wraps to two lines, the other
   side's field slides down and the pair stops lining up. */
.form__two { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: var(--sp-4); align-items: start; }
.form__acts { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; padding-top: var(--sp-2); }
textarea.field { min-height: 5.5rem; resize: vertical; line-height: 1.5; }

/* A toggle row: label and helper on the left, the switch on the right. */
.tog { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-3) 0; border-top: 1px solid var(--rule); }
.tog:first-of-type { border-top: 0; }
.tog__body { flex: 1; display: grid; gap: .2rem; min-width: 0; }
.tog__sw {
  flex: none; width: 2.6rem; height: 1.5rem; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--rule-strong); background: var(--paper-sunk); position: relative;
}
.tog__sw::after {
  content: ""; position: absolute; top: 50%; left: .18rem; transform: translateY(-50%);
  width: 1.05rem; height: 1.05rem; border-radius: 999px; background: var(--ink-faint);
  transition: left .12s ease, background .12s ease;
}
@media (prefers-reduced-motion: reduce) { .tog__sw::after { transition: none; } }
.tog__sw[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); }
.tog__sw[aria-pressed="true"]::after { left: 1.2rem; background: var(--accent); }

/* D16's transcript switch, in the search panel's foot. */
.sr__tog { display: flex; align-items: flex-start; gap: var(--sp-3); }
.sr__tog__label { font-size: var(--step--1); line-height: 1.4; }

/* A row of buttons where one of them is the current choice. Without this the
   pressed state lives only in aria-pressed, which is to say only for a screen
   reader — the scheduling mode and the vote-notification setting both looked
   like three identical unselected buttons. Same treatment as .rsvp. */
.pick .btn[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* Proposed time slots (vote mode, 2-5 of them). */
.slots { display: grid; gap: var(--sp-2); }
.slot { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.slot__n { font: 600 var(--step--1)/1 var(--mono); color: var(--ink-faint); width: 1.5rem; flex: none; }
.slot__warn { font-size: var(--step--1); color: var(--warn); display: inline-flex; align-items: center; gap: var(--sp-1); }

/* ── CAMP-8 · members and their characters ───────────────────────────── */
.mlist { display: grid; gap: var(--sp-3); }
.mem { border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-raised); padding: var(--sp-3) var(--sp-4); }
.mem__top { display: flex; align-items: flex-start; gap: var(--sp-3); flex-wrap: wrap; }
.mem__who { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; flex: 1; }
.mem__name { font: 600 var(--step-0)/1.3 var(--sans); display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
/* A person's pronouns, never a character's (#653). */
.mem__pron { font-size: var(--step--1); color: var(--ink-faint); font-weight: 400; }
.mem__acts { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.chars { display: grid; gap: var(--sp-2); margin: var(--sp-3) 0 0; padding-left: calc(1.75rem + var(--sp-3)); }
.char { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; font-size: var(--step--1); }
.char__name { font-weight: 600; font-size: var(--step-0); }
.char--off { opacity: .6; }
.char__meta { color: var(--ink-soft); }
.char__acts { margin-left: auto; display: flex; gap: var(--sp-2); }
@container app (max-width: 640px) { .chars { padding-left: 0; } }

/* ── CAMP-1's first-run checklist ────────────────────────────────────── */
.ck { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-3); overflow: hidden; }
.ck__row { background: var(--paper-raised); display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); }
.ck__row--done .ck__what { color: var(--ink-faint); text-decoration: line-through; }
.ck__what { flex: 1; min-width: 0; }

/* ── The Settings frame (CAMP-9..17), drawn in this lane ─────────────── */
.setnav { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-3); overflow: hidden; }
.setnav__row {
  background: var(--paper-raised); border: 0; width: 100%; text-align: left; cursor: pointer;
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); font: inherit; color: var(--ink);
}
.setnav__row:hover { background: var(--paper-sunk); }
/* Without this the nine rows read as a static list rather than nine doors. */
.setnav__row::after { content: "\203A"; color: var(--ink-faint); font-size: var(--step-1); line-height: 1; flex: none; }
.setnav__main { flex: 1; min-width: 0; display: grid; gap: .15rem; }
.setnav__name { font: 600 var(--step-0)/1.3 var(--sans); }
.setnav__sum { font-size: var(--step--1); color: var(--ink-soft); }
/* Every section says who can see it, which is IS-199's whole ask. */
.setnav__who { font-size: var(--step--1); color: var(--ink-faint); white-space: nowrap; display: inline-flex; align-items: center; gap: var(--sp-1); }

/* A modal drawn as a still: the box only, on the ground it sits on. */
.modal {
  max-width: 34rem; background: var(--paper-raised); border: 1px solid var(--rule-strong);
  border-radius: var(--r-3); box-shadow: var(--shadow); padding: var(--sp-5); display: grid; gap: var(--sp-3);
}
.modal h3 { font-size: var(--step-1); margin: 0; }
.modal__acts { display: flex; gap: var(--sp-3); flex-wrap: wrap; justify-content: flex-end; padding-top: var(--sp-2); }
.modal__danger { color: var(--warn); }

/* The shared .clock is display-sized (step-2); in the bar it is one word in a
   sentence, so it takes the sentence size and keeps only the tabular figures. */
.livebar__meta .clock { font-size: var(--step--1); }

/* ── Settings sections (lane 2b, #659) ───────────────────────────────────
   Seven of the nine settings sections, plus the pieces General was missing.
   These are product components, not reviewer furniture, so they live here
   with .setnav and .mem rather than on the lane page. */

/* A destructive button. There is no red in the palette on purpose -- the looks
   carry --warn (amber) and --live (the recording colour), and a third alarm
   colour would dilute both. So danger borrows --warn, the same token
   .modal__danger already uses for the sentence above the button. */
.btn--danger { border-color: var(--warn); color: var(--warn); }
.btn--danger:hover:not(:disabled) { background: var(--warn-soft); }

/* A link that is a button. Used where an action sits inside a sentence and a
   real button would break the line. */
.linkish {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--accent-ink); text-decoration: underline;
  text-underline-offset: 2px;
}
.linkish:hover { text-decoration-thickness: 2px; }

/* A section of a settings page that ends a page rather than continuing it. */
.sec--danger { border-top: 1px solid var(--warn); }
.sec--danger > h2 { color: var(--warn); }

/* ── CAMP-10 · invite links ──────────────────────────────────────────── */
.ilinks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.ilink {
  display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) var(--sp-4); background: var(--paper-raised);
  border: 1px solid var(--rule); border-radius: var(--r-2);
}
/* A dead link is dimmed but never hidden: a GM has to be able to recognise the
   link they pasted into Discord a fortnight ago as the one that stopped. The
   chip carries the reason, so this is not dimming alone (IS-295). */
.ilink--dead { background: var(--paper-sunk); }
.ilink--dead .ilink__label, .ilink--dead .ilink__url { color: var(--ink-faint); }
.ilink__main { flex: 1; min-width: 14rem; display: grid; gap: .25rem; }
.ilink__top { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.ilink__label { font: 600 var(--step-0)/1.3 var(--sans); }
.ilink__meta { font-size: var(--step--1); color: var(--ink-soft); }
.ilink__meta em { font-style: normal; color: var(--ink); }
.ilink__url { min-width: 0; }
.ilink__url code {
  display: block; font: var(--step--1)/1.5 var(--mono); color: var(--ink-soft);
  overflow-wrap: anywhere;
}
.ilink__acts { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; margin-left: auto; }

/* A toggle whose consequence lives on another page gets a way to it. */
.tog__link {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--step--1); color: var(--accent-ink); margin-top: .2rem;
}

/* ── CAMP-13 · retention and the AI panel ────────────────────────────── */
.ret { padding: var(--sp-4) 0; border-top: 1px solid var(--rule); display: grid; gap: var(--sp-2); }
.ret:first-of-type { border-top: 0; padding-top: var(--sp-2); }
.ret__h { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.ret__h b { font: 600 var(--step-0)/1.3 var(--sans); }
.ret__h .faint { font-size: var(--step--1); }

.panel { padding: var(--sp-5); }
/* The panel when what it describes is switched off elsewhere: present, legible
   and plainly not in use (D25). Not disabled -- there is nothing to disable,
   and nothing has been lost. */
.panel--muted { background: var(--paper-sunk); border-style: dashed; }
.aisec { margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid var(--rule); }
.aisec h4 { margin: 0 0 var(--sp-3); font: 600 var(--step-0)/1.3 var(--sans); }
.aisec .spread { margin-bottom: var(--sp-3); }

/* ── CAMP-14 · a set of choices with reasons ─────────────────────────── */
/* Radios rather than a slider or a segmented control: "players suggest, I
   decide" is a different shape from more-or-less permission, and each option
   needs a sentence saying what it means for a player. */
.choices { border: 0; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.choices legend { padding: 0; margin-bottom: var(--sp-3); }
.choice {
  display: flex; gap: var(--sp-3); align-items: flex-start; cursor: pointer;
  padding: var(--sp-3) var(--sp-4); background: var(--paper-raised);
  border: 1px solid var(--rule); border-radius: var(--r-2);
}
.choice:hover { border-color: var(--rule-strong); }
.choice--on { border-color: var(--accent); background: var(--accent-soft); }
.choice input { margin-top: .28rem; flex: none; accent-color: var(--accent); }
.choice__body { display: grid; gap: .2rem; min-width: 0; }
.choice__t { font: 600 var(--step-0)/1.3 var(--sans); }
.choice__d { font-size: var(--step--1); color: var(--ink-soft); }

/* ── CAMP-15 · content packs ─────────────────────────────────────────── */
.pks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.pk {
  display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-4); background: var(--paper-raised);
  border: 1px solid var(--rule); border-radius: var(--r-2);
}
.pk--off { background: var(--paper-sunk); }
.pk__main { flex: 1; min-width: 16rem; display: grid; gap: .3rem; }
.pk__top { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.pk__name { font: 600 var(--step-0)/1.3 var(--sans); }
.pk__top .faint { font-size: var(--step--1); }
.pk__meta, .pk__by { font-size: var(--step--1); color: var(--ink-soft); }
.pk__by { color: var(--ink-faint); }
.pk__detail { font-size: var(--step--1); color: var(--warn); }
.pk__detail--bad { color: var(--live); }
/* The licence is load-bearing: "no licence -- nothing here can be exported" is
   the only warning before an export quietly leaves things out. A sentence, at
   body size, not a badge. */
.pk__lic { font-size: var(--step--1); color: var(--ink-soft); }
.pk__acts { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; margin-left: auto; }

.spin {
  display: inline-block; width: .7rem; height: .7rem; vertical-align: -1px;
  border: 2px solid var(--warn); border-right-color: transparent; border-radius: 50%;
  animation: qb-spin 900ms linear infinite;
}
@keyframes qb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 3s; } }

.filepick { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.filepick .faint { font-size: var(--step--1); }
/* The affirmation is a legal record, not a nicety, so it is boxed off from the
   form fields above it rather than reading as one more field. */
.affirm { margin: var(--sp-4) 0 var(--sp-2); }
.affirm .choice { background: var(--paper-sunk); }

/* ── CAMP-17 · the clone tree ────────────────────────────────────────── */
.tree { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-2); overflow: hidden; }
.tree__row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); background: var(--paper-raised); }
.tree__n { flex: 1; min-width: 0; font-weight: 500; }
.tree__c { font-size: var(--step--1); color: var(--ink-faint); }
/* Three states, and the partial one is a square rather than a lighter tick --
   "some of these" must not depend on noticing a shade (IS-295). */
.tri { flex: none; width: 1.05rem; height: 1.05rem; border: 1px solid var(--rule-strong); border-radius: 4px; position: relative; }
.tri--on { background: var(--accent); border-color: var(--accent); }
.tri--on::after { content: ""; position: absolute; left: 5px; top: 1px; width: 4px; height: 9px; border: solid var(--paper); border-width: 0 2px 2px 0; transform: rotate(45deg); }
.tri--part { border-color: var(--accent); }
.tri--part::after { content: ""; position: absolute; inset: 3px; background: var(--accent); border-radius: 1px; }

.modal--wide { max-width: 34rem; }
/* "Take a copy first?" inside a destructive dialog. Set apart, because it is an
   offer rather than part of the warning, and it is the one moment the offer is
   actually useful. */
.modal__take {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  flex-wrap: wrap; padding: var(--sp-3) var(--sp-4); margin: var(--sp-2) 0;
  background: var(--paper-sunk); border: 1px solid var(--rule); border-radius: var(--r-2);
}
.modal__take > div { display: grid; gap: .15rem; }

/* ── CAMP-9 · the pieces General was missing ─────────────────────────── */
.nudge {
  display: flex; gap: var(--sp-3); align-items: flex-start; flex-wrap: wrap;
  margin-top: var(--sp-2); padding: var(--sp-3) var(--sp-4);
  background: var(--accent-soft); border-radius: var(--r-2);
}
.nudge > div:first-of-type { flex: 1; min-width: 14rem; display: grid; gap: .2rem; }
.nudge .row-wrap { margin-left: auto; }

.conv { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-2); overflow: hidden; }
/* A grid, not a flex row: the type chips differ in width, and on a flex row
   that leaves every title starting at a different place down the list. */
.conv__row { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) auto; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4); background: var(--paper-raised); }
.conv__row > .chip { justify-self: start; }
.conv__n { flex: 1; min-width: 0; }
.conv__more { padding: var(--sp-2) var(--sp-4); background: var(--paper-raised); font-size: var(--step--1); }

.bad { color: var(--live); }

/* A field whose control is not the one currently chosen -- the months box
   beside a "keep them" that is already pressed. It has to read as inert rather
   than as an empty box somebody forgot to fill in. */
.field:disabled, .field[disabled] {
  background: var(--paper-sunk); color: var(--ink-faint);
  border-color: var(--rule); cursor: not-allowed;
}

/* ── The session, start to finish (lane 3, #659) ─────────────────────────
   SESS-1 to SESS-7. Product components, so they live here beside .setnav and
   .mem rather than on the lane page. */

/* ── SESS-1 · the voting grid ────────────────────────────────────────── */
/* A real table, because it is one: slots are columns, people are rows, and a
   screen reader should be able to say "Tuesday, Marcus, no" without being
   told the shape by hand. */
.vg-wrap { overflow-x: auto; }
.vg { border-collapse: separate; border-spacing: 0; width: 100%; min-width: 34rem; }
.vg th, .vg td { border-bottom: 1px solid var(--rule); padding: var(--sp-2) var(--sp-3); }
.vg__corner { width: 12rem; border-bottom-color: var(--rule-strong); }
.vg__slot {
  vertical-align: bottom; text-align: left; display: table-cell;
  border-bottom: 2px solid var(--rule-strong); min-width: 6.5rem;
}
/* The best slot is marked three ways over -- a tick, a tint and a heavier
   rule -- because on a five-column grid the one that matters must survive
   being skimmed, and colour alone is IS-295's failure. */
.vg__slot--best { background: var(--accent-soft); border-bottom-color: var(--accent); }
.vg__star { color: var(--accent); }
.vg__d { display: block; font: 600 var(--step-0)/1.25 var(--sans); }
.vg__t { display: block; font-size: var(--step--1); color: var(--ink-soft); }
.vg__score { display: block; margin-top: .2rem; font: 600 var(--step--1)/1 var(--mono); color: var(--ink-faint); }
.vg__clash { display: block; margin-top: .2rem; font-size: var(--step--1); color: var(--warn); }
.vg__who { text-align: left; font-weight: 500; }
.vg__who .who__disc { margin-right: var(--sp-2); vertical-align: -.35rem; }
.vg__cell { text-align: center; }
.vg__cell--mine { background: var(--paper-sunk); }
.vg__btn {
  width: 100%; min-height: 40px; display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2); cursor: pointer; font: 500 var(--step--1)/1 var(--sans);
  background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--r-2); color: inherit;
}
.vg__btn:hover { border-color: var(--accent); }

/* D29 · the same four times on a phone, turned ninety degrees. */
.vl { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.vl__row {
  display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4);
  background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--r-2);
}
.vl__row--best { border-color: var(--accent); background: var(--accent-soft); }
.vl__when { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.vl__when b { font: 600 var(--step-0)/1.25 var(--sans); }
.vl__when span { font-size: var(--step--1); color: var(--ink-soft); }
.vl__tally { font-size: var(--step--1); color: var(--ink-soft); display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.vl__clash { color: var(--warn); margin-left: var(--sp-2); }
.vl__mine { margin-top: var(--sp-1); }

/* ── SESS-3 · is the summary ready? ──────────────────────────────────── */
/* The one piece of machinery a player does want. An icon, a word and a
   sentence -- never a colour on its own, and never a bare spinner. */
.tstate {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) var(--sp-4); border: 1px solid var(--rule);
  border-left: 3px solid var(--rule-strong); border-radius: 0 var(--r-2) var(--r-2) 0;
  background: var(--paper-raised);
}
.tstate > div { display: grid; gap: .15rem; }
.tstate__i { flex: none; line-height: 1.4; }
.tstate--ready { border-left-color: var(--good); }
.tstate--processing { border-left-color: var(--warn); }
.tstate--failed { border-left-color: var(--live); }
.tstate--gone { border-left-color: var(--rule-strong); background: var(--paper-sunk); }

/* ── SESS-4 · correcting the events ──────────────────────────────────── */
.evlist { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-2); overflow: hidden; }
.evx {
  display: grid; grid-template-columns: 4rem 9rem minmax(0, 1fr) auto;
  gap: var(--sp-3); align-items: baseline;
  padding: var(--sp-3) var(--sp-4); background: var(--paper-raised);
}
.evx__t { font: var(--step--1)/1.6 var(--mono); color: var(--ink-faint); }
.evx__who { font-size: var(--step--1); color: var(--ink-soft); }
.evx__what { min-width: 0; }
/* A struck event keeps its words. The GM is saying "this did not happen", and
   hiding it would make the correction unreviewable. */
.evx--struck .evx__what { color: var(--ink-faint); text-decoration: line-through; }
.evx--struck .evx__tag, .evx--rewritten .evx__tag, .evx--relabelled .evx__tag {
  display: inline-block; margin-left: var(--sp-2); font: 600 var(--step--1)/1 var(--sans);
  letter-spacing: .04em; text-transform: uppercase; color: var(--gm); text-decoration: none;
}
.evx__was { display: block; margin-top: .2rem; font-size: var(--step--1); color: var(--ink-faint); text-decoration: line-through; }
.evx__acts { display: inline-flex; gap: var(--sp-1); flex-wrap: wrap; justify-content: flex-end; }
@container app (max-width: 46rem) {
  .evx { grid-template-columns: 4rem minmax(0, 1fr); }
  .evx__who { grid-column: 2; }
  .evx__what, .evx__acts { grid-column: 1 / -1; }
  .evx__acts { justify-content: flex-start; }
}

/* ── SESS-7 · who can read this note ─────────────────────────────────── */
/* D30. One editor, and a switch that says in words who the reader will be --
   this is the one place where getting the audience wrong cannot be taken
   back, so it never relies on remembering what a badge meant. */
.aud { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.aud__btn {
  display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer;
  min-height: 40px; padding: var(--sp-2) var(--sp-4);
  font: 500 var(--step-0)/1 var(--sans); color: var(--ink-soft);
  background: var(--paper-raised); border: 1px solid var(--rule); border-radius: 999px;
}
.aud__btn:hover { border-color: var(--rule-strong); color: var(--ink); }
.aud__btn[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); font-weight: 600;
}
.note-ta { min-height: 9rem; font: var(--step-0)/1.6 var(--sans); margin-top: var(--sp-2); }
.vg__score abbr { text-decoration: none; border-bottom: 1px dotted var(--rule-strong); cursor: help; }
/* A read-only vote says the word as well as showing the colour. Four of five
   rows reading as a bare coloured dot is exactly IS-295's failure, and the
   roster directly beneath this grid already gets it right. */
.vg__said { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--step--1); color: var(--ink-soft); }

/* ── At the table (lane 4, #659) ─────────────────────────────────────────
   TABLE-1 to TABLE-5. Built on look.html's Table mode classes (.tm, .spot,
   .tc, .pc) so the lane sits inside the settled look. */

.kbd { font: 600 .72rem/1 var(--mono); padding: .15rem .35rem; border: 1px solid var(--table-rule); border-radius: 4px; color: var(--table-soft); margin-left: .25rem; }

/* The cold open, dismissible for this session. */
.coldopen { position: relative; margin-bottom: var(--sp-4); padding: var(--sp-3) var(--sp-5) var(--sp-3) var(--sp-4);
  background: var(--table-raised); border: 1px solid var(--table-rule); border-radius: var(--r-3); display: grid; gap: var(--sp-1); }
.coldopen p { color: var(--table-ink); font: var(--step-0)/1.5 var(--serif); }
.coldopen__x { position: absolute; top: var(--sp-2); right: var(--sp-2); padding: .2rem; min-height: 0; }

/* ── D33 · the scene bar ─────────────────────────────────────────────── */
.sb { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; margin: var(--sp-3) 0; }
.sb__chip { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; min-height: 38px;
  padding: .3rem .8rem; font: 500 var(--step--1)/1 var(--sans); color: var(--table-soft);
  background: var(--table-raised); border: 1px solid var(--table-rule); border-radius: 999px; }
.sb__chip[aria-selected="true"] { color: var(--table-ink); border-color: var(--accent); background: rgba(111, 158, 230, .16); font-weight: 600; }
/* An empty scene is a normal state now (IS-319), and reads as one: dashed,
   not greyed -- it is waiting to be filled, not unavailable. */
.sb__chip--empty { border-style: dashed; }
.sb__n { font: 600 .72rem/1 var(--mono); color: var(--table-soft); }
.sb__map { display: inline-flex; color: var(--accent); }

/* ── The freeform board ──────────────────────────────────────────────── */
/* Absolutely positioned, because the GM's placement is sacred (#235) and a
   reflowing grid is the one thing it must not be (IS-320). A filtered-out card
   is faded in place, never moved -- the point of the still is that switching
   scene back puts every card exactly where it was. */
.fb { position: relative; height: 26rem; border: 1px dashed var(--table-rule); border-radius: var(--r-3);
  background-image: radial-gradient(var(--table-rule) 1px, transparent 1px); background-size: 22px 22px; }
.fb__card { position: absolute; display: flex; flex-direction: column; gap: var(--sp-1); min-height: 7rem; cursor: grab; }
.fb__card--hidden { opacity: .14; filter: grayscale(1); pointer-events: none; }
.fb__grip { position: absolute; top: 6px; left: 50%; transform: translateX(-50%); width: 1.8rem; height: 3px; border-radius: 3px; background: var(--table-rule); }
.fb__n { font: 600 .72rem/1 var(--mono); color: var(--table-soft); border: 1px solid var(--table-rule); border-radius: 4px; padding: .1rem .3rem; }

.shown { display: grid; gap: var(--sp-2); }
.shown__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.shown__list li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0 var(--sp-2); align-items: baseline;
  padding: var(--sp-2) var(--sp-3); background: var(--table-raised); border: 1px solid var(--table-rule); border-radius: var(--r-2); }
.shown__list .faint { grid-column: 1; font-size: var(--step--1); }
.shown__list .linkish { grid-row: 1 / span 2; grid-column: 2; align-self: center; }
.tm .linkish { color: var(--accent); }

/* ── D34 · the GM on a phone ─────────────────────────────────────────── */
.plist { list-style: none; margin: var(--sp-2) 0 0; padding: 0; display: grid; gap: 1px; background: var(--table-rule);
  border: 1px solid var(--table-rule); border-radius: var(--r-2); overflow: hidden; }
.plist__row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); background: var(--table-raised); min-height: 48px; }
.plist__row--on { box-shadow: inset 3px 0 0 var(--accent); }
.plist__n { font: 600 .8rem/1 var(--mono); color: var(--table-soft); width: 1.2rem; }
.plist__t { flex: 1; min-width: 0; font-weight: 500; }
.phone-acts { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.stale { padding: var(--sp-2) var(--sp-4); background: rgba(217, 167, 90, .16); color: var(--table-ink);
  border-bottom: 1px solid var(--warn); font-size: var(--step--1); display: flex; gap: var(--sp-2); align-items: center; }

/* A still of a Table mode surface: the Table palette behind a panel or modal. */
.tmbed { background: var(--table-bg); color: var(--table-ink); }
.tm-modal, .tmbed .sw { background: var(--table-raised); color: var(--table-ink); border-color: var(--table-rule); }
.tm-modal .choice, .tmbed .choice { background: var(--table-bg); border-color: var(--table-rule); color: var(--table-ink); }
.tm-modal .choice--on { border-color: var(--accent); }
.tm-modal .choice__d, .tm-modal .form__hint { color: var(--table-soft); }
.tm-modal .field { background: var(--table-bg); color: var(--table-ink); border-color: var(--table-rule); }

/* ── Scenes, managed (D33) ───────────────────────────────────────────── */
.scn { list-style: none; margin: var(--sp-3) 0; padding: 0; display: grid; gap: var(--sp-2); }
.scn__row { display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-3);
  border: 1px solid var(--rule); border-radius: var(--r-2); background: var(--paper-raised); }
.scn__main { flex: 1; display: grid; gap: var(--sp-2); min-width: 0; }
.scn__meta { font-size: var(--step--1); color: var(--ink-soft); display: inline-flex; gap: var(--sp-1); align-items: center; flex-wrap: wrap; }

/* ── TABLE-3 · the shared screen ─────────────────────────────────────── */
/* Readable from two or three metres, so it is sized like signage, not like an
   app. No controls: a TV on the table is not something anyone taps. */
.ss { aspect-ratio: 16 / 9; background: #0b1220; color: #eef3fb; display: grid; place-items: center;
  border-radius: var(--r-3); overflow: hidden; position: relative; }
.ss__inner { text-align: center; padding: 6%; display: grid; gap: .8em; justify-items: center; }
.ss__brand { font: 600 1rem/1 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: #8db1ea; }
.ss__lead { margin: 0; font-size: 1.1rem; color: #b7c6dc; }
.ss__code { font: 700 clamp(2.4rem, 7vw, 4.2rem)/1 var(--mono); letter-spacing: .12em; color: #fff;
  padding: .3em .6em; border: 2px solid #34507d; border-radius: 14px; }
.ss__small { margin: 0; font-size: .95rem; color: #8193ad; }
.ss__kind { font: 600 .9rem/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: #8db1ea; }
.ss__title { font: 600 clamp(2rem, 5.2vw, 3.4rem)/1.1 var(--serif); }
.ss__line { margin: 0; font: clamp(1.1rem, 2.4vw, 1.6rem)/1.4 var(--serif); color: #cdd8e8; max-width: 30ch; }
.ss--lost .ss__inner { opacity: .72; }
.ss__lostbar { position: absolute; left: 0; right: 0; bottom: 0; padding: .7rem 1rem; font-size: 1rem;
  background: rgba(217, 167, 90, .22); color: #fff; display: flex; gap: .5rem; justify-content: center; align-items: center; }

/* ── TABLE-4 · the full recording panel ──────────────────────────────── */
.recp { display: grid; gap: var(--sp-3); padding: var(--sp-4); background: var(--paper-raised);
  border: 1px solid var(--rule); border-radius: var(--r-3); }
.recp__head { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.recp__who { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.recp__who li { display: flex; align-items: center; gap: var(--sp-3); }
.recp__n { flex: 1; font-weight: 500; }
.recp__quiet .recp__n { color: var(--ink-soft); }

/* ── TABLE-5 · the sweep ─────────────────────────────────────────────── */
.sw { padding: var(--sp-4); border: 1px solid var(--table-rule); border-radius: var(--r-3); display: grid; gap: 0; }
.sw .muted { color: var(--table-soft); }
.sw__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--table-rule);
  border: 1px solid var(--table-rule); border-radius: var(--r-2); overflow: hidden; }
.sw__row { display: flex; gap: var(--sp-3); align-items: center; justify-content: space-between; flex-wrap: wrap;
  padding: var(--sp-3); background: var(--table-bg); }
.sw__main { display: grid; gap: .1rem; min-width: 10rem; }
.sw__main .faint { font-size: var(--step--1); color: var(--table-soft); }
.sw__acts { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.sw__done { display: inline-flex; gap: var(--sp-2); align-items: center; font-size: var(--step--1); }
.sw--phone .sw__row { flex-direction: column; align-items: stretch; }
.sw--phone .sw__acts .btn { flex: 1; }
/* A Table mode still at its natural height, like .shot--page for the book. */
.shot--table .tm { height: auto; }
.shot--table .tm__body { overflow: visible; }
/* A card footer wraps between tags, never inside one: "Handout · On the
   table" broke across two lines in a narrow card. */
.fb__card .tc__foot { flex-wrap: wrap; row-gap: .3rem; }
.fb__card .tag { white-space: nowrap; }
/* The phone sweep: buttons wrap as whole buttons rather than a label
   breaking in two ("Keep in the / wiki"). */
.sw--phone .sw__acts .btn { flex: 1 1 auto; white-space: nowrap; }
/* A single shared-screen still would otherwise fill a whole grid row at 16:9
   and stand 850px tall. A TV is drawn at a TV's proportion, not the page's. */
.ss { max-width: 46rem; }
/* The shared screen sizes its type to its OWN width, not the page's. vw made
   a TV drawn at a third of the page wrap its title and outgrow 16:9, because
   the text was sized for 1700px. cqi scales with the screen it is on -- which
   is also what a real TV of any size needs. */
.ss { container-type: inline-size; }
.ss__code { font-size: clamp(1.6rem, 13cqi, 4.2rem); }
.ss__title { font-size: clamp(1.3rem, 8.5cqi, 3.4rem); }
.ss__line { font-size: clamp(.9rem, 4.2cqi, 1.6rem); }
.ss__lead { font-size: clamp(.8rem, 3.4cqi, 1.1rem); }
/* The lost-contact bar sits over the bottom of the screen; the content keeps
   clear of it rather than being covered. */
.ss--lost .ss__inner { padding-bottom: 3rem; }
/* ── D37 · the board as a canvas wider than the screen ──────────────── */
.cv { position: relative; }
/* The board scrolls within itself, so the bar and spotlight above it stay put. */
.cv__scroll { overflow: hidden; border-radius: var(--r-3); }
.fb--wide { width: 161%; }
/* Cards past the visible edge are counted at that edge, never silently gone
   (IS-326). A word and a count as well as the arrow -- not an arrow alone. */
.cv__edge { position: absolute; right: var(--sp-2); top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); font: 600 var(--step--1)/1 var(--sans); color: var(--table-ink);
  background: var(--table-raised); border: 1px solid var(--accent); border-radius: 999px;
  box-shadow: -18px 0 22px 4px var(--table-bg); }
.cv__edge svg { transform: scaleX(-1); }
.cv__bar { height: 6px; margin-top: var(--sp-2); background: var(--table-rule); border-radius: 6px; }
.cv__thumb { display: block; width: 62%; height: 100%; background: var(--table-soft); border-radius: 6px; }

/* ── Prep (lane 5, #659) ─────────────────────────────────────────────────
   PREP-1 to PREP-3, built on look.html's prep classes (.prep, .margin, .tool,
   .drawer, .want, .beats, .ins), which already live above. */

/* D40 · the sheet saves itself, and says which of four states it is in. */
.save { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--step--1); color: var(--ink-soft); }
.save--warn { color: var(--ink); font-weight: 600; }
.save--warn .qi { color: var(--warn); }

/* D38 · The plan: the generator's five parts, set as part of the document
   rather than as a tool's output box. */
.plan { display: grid; gap: var(--sp-4); max-width: 72ch; }
.plan__strong { font: italic var(--step-1)/1.55 var(--serif); margin: 0; }
.plan__part h3 { font: 600 var(--step--1)/1.2 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--ink-soft); margin: 0 0 var(--sp-2); }
.plan__list { margin: 0; padding-left: 1.4rem; display: grid; gap: var(--sp-2); font: var(--step-0)/1.55 var(--serif); }
.plan__list li { padding-left: .2rem; }
.plan__act, .plan__on { font: var(--step--1) var(--sans); margin-left: var(--sp-2); white-space: nowrap; }
.plan__on { color: var(--ink-faint); }
.plan__meta { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; font-size: var(--step--1); color: var(--ink-soft); }
.plan__stale { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--warn); background: var(--warn-soft); border-radius: var(--r-2); font-size: var(--step--1); }
.plan__empty { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; color: var(--ink-soft); }

/* D39 · what an item is doing across sessions. In words, not a glyph: the
   icon set has no pin, and "carried from Session 11" says more than one would. */
.ins__state { display: inline-flex; align-items: center; gap: var(--sp-1); font: 600 var(--step--1)/1.2 var(--sans); color: var(--accent-ink); }
.ins--carried { background: var(--paper-sunk); }
.ins__actions .btn[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); }

/* D43 · the sheet's Shelf section, by scene. An empty scene is a normal
   state (IS-319) and reads as waiting, not as missing. */
.sg { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); max-width: 72ch; }
.sg__head { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); align-items: baseline; }
.sg__name { font: 600 var(--step-0)/1.3 var(--sans); }
.sg__meta { font-size: var(--step--1); color: var(--ink-soft); display: inline-flex; gap: var(--sp-1); align-items: center; flex-wrap: wrap; }
.sg__empty { padding: var(--sp-3) var(--sp-4); border: 1px dashed var(--rule-strong); border-radius: var(--r-2); color: var(--ink-soft); font-size: var(--step--1); }

/* A margin drawer drawn on its own, at the margin's own width. */
.drawerbed { padding: var(--sp-4); background: var(--paper-sunk); }
.drawerbed .drawer { width: 272px; max-width: 100%; margin: 0 auto; box-shadow: none; }
.drawer__res { display: grid; gap: var(--sp-2); padding: var(--sp-3); border: 1px solid var(--rule); border-radius: var(--r-2); background: var(--paper); }
.drawer__res p { margin: 0; }
.drawer__acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.drawer__foot { font-size: var(--step--1); }
.drawer__rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.drawer__rows li { display: grid; gap: .15rem; }
.drawer__sub { font-size: var(--step--1); color: var(--ink-faint); }

/* The rumour mill's truth, in a word as well as a colour. */
.truth { display: inline-block; font: 600 var(--step--1)/1 var(--sans); padding: .2rem .4rem; border: 1px solid currentColor; border-radius: 4px; }
.truth--true { color: var(--good); } .truth--distorted { color: var(--warn); } .truth--false { color: var(--live); }

/* PREP-3 · history. */
.filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
.hist__where { font-size: var(--step--1); color: var(--ink-soft); }
.hist__acts { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }

/* D42 · a phone: the margin's tools become a button in the header row. */
.prep--phone { display: block; }
.prep--phone .margin { display: none; }

/* D41 · the planning page (proposed). The arcs get a real handle, because
   today's board can only move an arc up (PR-053). */
.grip { flex: none; width: .75rem; height: 1.2rem; cursor: grab; opacity: .7;
  background-image: radial-gradient(var(--ink-faint) 1.4px, transparent 1.6px); background-size: 6px 6px; }
/* The sheet's title with Suggest a title beside it, wrapping below on a phone
   rather than squeezing the button into two lines. */
.titlerow { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 var(--sp-3); }
.titlerow .btn { white-space: nowrap; }
.plan__stale { margin-bottom: var(--sp-4); }

/* A generated roll table (PR-127): a table, not a line of text. */
.tbl { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
.tbl th, .tbl td { text-align: left; padding: .3rem .4rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
.tbl th { font-weight: 600; color: var(--ink-soft); }
.tbl td:first-child { width: 2.2rem; font-family: var(--mono); color: var(--ink-soft); }
/* A split button: the default action, and a chevron for the other one. */
.split { display: inline-flex; }
.split .btn:first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.split__more { border-top-left-radius: 0; border-bottom-left-radius: 0; margin-left: -1px; padding-inline: .5rem; }
/* Per-row links in a narrow drawer: small, so a pair fits on one line. */
.drawer__rows .drawer__acts { gap: 0 var(--sp-3); }
.drawer__rows .linkish { font-size: var(--step--1); }

/* ── Home and you (lane 1b, #659) ─────────────────────────────────────── */
/* HOME-4: archived and binned campaigns, folded at the foot of Home. */
.fold { border-top: 1px solid var(--rule); margin-top: var(--sp-6); padding-top: var(--sp-3); }
.fold > summary { cursor: pointer; list-style: none; display: flex; gap: var(--sp-2); align-items: center;
  font: 600 var(--step-0)/1.4 var(--sans); color: var(--ink-soft); }
.fold > summary::-webkit-details-marker { display: none; }
.fold[open] > summary { margin-bottom: var(--sp-4); }
.camp--dim { opacity: .74; }
/* D48: notification settings as a grid. */
.nbox { container: nbox / inline-size; max-width: 46rem; }
.ngrid { border-collapse: collapse; width: 100%; max-width: 46rem; }
.ngrid th, .ngrid td { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--rule); text-align: left; vertical-align: middle; }
.ngrid thead th { font: 600 var(--step--1)/1.2 var(--sans); color: var(--ink-soft); }
.ngrid tbody th { font: 600 var(--step-0)/1.3 var(--sans); }
.ngrid .sub { display: block; font: 400 var(--step--1)/1.35 var(--sans); color: var(--ink-soft); }
.ngrid .field { min-height: 36px; padding-block: .2rem; }
.always { display: inline-flex; gap: var(--sp-1); align-items: center; font-size: var(--step--1); color: var(--ink-soft); }
/* D49: plan & billing. */
.price { font: 600 var(--step-2)/1 var(--sans); }
.meter { height: 8px; border-radius: 8px; background: var(--paper-sunk); border: 1px solid var(--rule); overflow: hidden; max-width: 30rem; }
.meter > span { display: block; height: 100%; background: var(--accent); }
.choice-grid { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }

/* A disabled button looks it. The kit had no rule, so every "disabled until…"
   still drew an active button (lane 1b's render check). */
.btn:disabled, .btn[disabled] { opacity: .5; cursor: not-allowed; }
/* A fold drawn as the first thing on its page has nothing above to rule off. */
.doc > .fold:first-child { margin-top: 0; border-top: 0; padding-top: 0; }

/* ── The rest of a campaign (lane 2c, #659) ───────────────────────────── */
/* CAMP-7: a rate is a number first; the colour only agrees with it. */
.rate { font-weight: 600; }
.rate--hi { color: var(--good); } .rate--mid { color: var(--warn); } .rate--lo { color: var(--live); }
/* SH-7 / IS-292: the skip link, drawn in its focused state. */
.skip { position: absolute; left: var(--sp-3); top: var(--sp-2); z-index: 5; padding: var(--sp-2) var(--sp-3);
  background: var(--paper-raised); color: var(--accent-ink); border: 2px solid var(--accent); border-radius: var(--r-2); font-weight: 600; }
/* The notification grid on a narrow screen (lane 1b's review): four columns
   squeezed the email choice to two letters. Each kind becomes a row with its
   controls beneath, labelled, and the in-app column -- "Always" on every
   row -- is said once above instead. */
.ngrid__l, .ngrid__note { display: none; }
@container nbox (max-width: 32rem) {
  .ngrid thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ngrid, .ngrid tbody { display: block; }
  .ngrid tr { display: grid; grid-template-columns: 1fr auto; gap: var(--sp-2) var(--sp-4); align-items: center; padding: var(--sp-3) 0; border-bottom: 1px solid var(--rule); }
  .ngrid th, .ngrid td { padding: 0; border: 0; }
  .ngrid tbody th { grid-column: 1 / -1; }
  .ngrid td.ngrid__app { display: none; }
  .ngrid td { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
  .ngrid td .field { flex: 1; min-width: 0; max-width: 14rem; }
  .ngrid__l { display: inline; font-size: var(--step--1); color: var(--ink-soft); white-space: nowrap; }
  .ngrid__note { display: flex; gap: var(--sp-2); align-items: center; margin: 0 0 var(--sp-1); font-size: var(--step--1); color: var(--ink-soft); }
}

/* ── Lane 3's backfill (#696) ────────────────────────────────────────────
   The states and dialogs the first draw left out: the rest of the vote,
   pencilled in, Manage (D52), the recording and transcript, versions (D51),
   and the ledger. */
.sess__desc { margin: var(--sp-2) 0 var(--sp-2); max-width: 62ch; color: var(--ink-soft); font-style: italic; }
.doc > .sess__meta { margin-bottom: var(--sp-4); }
.sess__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: var(--sp-2) 0 0; font-size: var(--step--1); color: var(--ink-soft); }
.sess__meta-sep { flex: 1 1 var(--sp-4); }
/* Manage, and the calendar's two ways in. In the product the menu hangs off
   its button; in a still it sits in the flow under the row, right-aligned,
   where the eye expects it. */
.manage { position: relative; display: inline-flex; }
.menu--manage { position: static; margin: var(--sp-2) 0 0 auto; width: min(19rem, 100%); }
.row-wrap + .menu--manage { margin-left: auto; }
.menu__list .menu__danger { color: var(--warn); }
/* The vote. */
.vg__away { display: block; font-size: var(--step--1); color: var(--ink-faint); font-style: italic; }
.vg__rm { display: block; margin-top: .3rem; }
.vg__slot { vertical-align: top; }
.vg__slot .vg__star { display: inline-flex; vertical-align: -.1em; }
.ck__what .form__hint { display: block; margin: .15rem 0 0; }
.vg__cell--failed { box-shadow: inset 0 -2px 0 var(--warn); }
.vg__fail { display: inline-flex; margin-left: var(--sp-1); color: var(--warn); vertical-align: middle; }
.vg-legend { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); align-items: center; margin: var(--sp-3) 0 0; font-size: var(--step--1); color: var(--ink-soft); }
.vg-legend > span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.vl__fail { display: flex; gap: var(--sp-1); align-items: center; margin: 0; font-size: var(--step--1); font-weight: 600; }
.vl__fail .qi { color: var(--warn); }
.addtime { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); padding: var(--sp-4); max-width: 34rem; border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-sunk); }
.addtime .form__row { margin: 0; }
.slotrow { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: var(--sp-2); align-items: center; }
/* The read-only log: a struck line, for its GM only. */
.events__row--struck .events__what { color: var(--ink-faint); text-decoration: line-through; }
.ev-struck { display: inline-block; margin-left: var(--sp-2); font: 600 var(--step--1)/1 var(--sans); color: var(--gm); text-decoration: none; }
.events__row--struck .ev-struck { text-decoration: none; }
/* A moment is a highlight without a speaker. */
.hl { display: flex; gap: var(--sp-3); align-items: flex-start; }
.hl > :first-child { flex: 1; min-width: 0; }
.hl__acts { display: inline-flex; gap: var(--sp-1); flex: none; }
.moment { margin: 0 0 var(--sp-4); max-width: 60ch; padding-left: var(--sp-4); border-left: 3px dotted var(--rule-strong); font: var(--step-1)/1.5 var(--serif); }
.moment__t { display: block; margin-top: var(--sp-1); font: 500 var(--step--1)/1.3 var(--sans); color: var(--ink-faint); }
/* Loot & XP: itemised, and coin carries its sign as well as its colour. */
.ledger { display: grid; gap: var(--sp-4); }
.ledger__two { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); align-items: start; }
.ledger .ngrid { max-width: none; }
.amt { font-variant-numeric: tabular-nums; }
.amt--plus { color: var(--good); font-weight: 600; }
.amt--minus { color: var(--warn); font-weight: 600; }
/* The transcript: the GM's, and read line by line. */
.tx { display: grid; gap: .1rem; font: var(--step--1)/1.55 var(--mono); }
.tx__line { display: grid; grid-template-columns: 5rem 8.5rem minmax(0, 1fr); gap: var(--sp-3); align-items: baseline; padding: .15rem 0; }
.tx__t { color: var(--ink-faint); }
.tx__who { font-family: var(--sans); font-weight: 600; }
.tx__who .faint { font-weight: 400; }
.tx__said { white-space: pre-wrap; }
.tx__edit { font: var(--step--1)/1.55 var(--mono); }
@container app (max-width: 40rem) {
  .tx__line { grid-template-columns: 4.5rem minmax(0, 1fr); }
  .tx__said { grid-column: 1 / -1; }
}
.field--inline { width: auto; min-height: 32px; padding-block: .1rem; display: inline-block; }
/* Event corrections, beyond strike, reword and relabel. */
.evx--story .evx__tag, .evx--emph .evx__tag, .evx--unemph .evx__tag {
  display: inline-block; margin-left: var(--sp-2); font: 600 var(--step--1)/1 var(--sans);
  letter-spacing: .04em; text-transform: uppercase; color: var(--gm);
}
.evx__star { display: inline-flex; margin-right: var(--sp-1); color: var(--accent); vertical-align: -.15em; }
.evx__wasnote { display: inline-block; margin-left: var(--sp-2); font-size: var(--step--1); color: var(--ink-faint); }
.evx__bad { display: flex; gap: var(--sp-1); align-items: center; margin-top: .25rem; font-size: var(--step--1); font-weight: 600; }
.evx__bad .qi { color: var(--warn); flex: none; }
.evx--bad { box-shadow: inset 3px 0 0 var(--warn); }
.evx__cite { display: block; margin-top: .25rem; font: var(--step--1)/1.3 var(--mono); }
.evx__orig { margin-top: .25rem; font-size: var(--step--1); color: var(--ink-faint); }
.evx__orig > summary { cursor: pointer; color: var(--gm); font-weight: 600; }
.evx--editing .evx__what textarea { width: 100%; }
.seg--sm .seg__btn { padding: .25rem .6rem; }

/* ── Lane 4's backfill (#696) ────────────────────────────────────────────
   Every card's own controls and shapes, Find and the preview (D53), the quick
   note (D54), the canvas's other states, and the recording panel's states. */

/* The recording dot: grey when idle, red and pulsing while it records -- and
   always beside a word (SE-030, IS-295). */
.recdot { display: inline-block; width: .6rem; height: .6rem; border-radius: 999px; background: var(--table-soft, var(--ink-faint)); flex: none; margin-right: .1rem; }
.recdot--live { background: var(--live); box-shadow: 0 0 0 0 rgba(229, 83, 75, .5); animation: recpulse 1.6s ease-out infinite; }
@keyframes recpulse { 0% { box-shadow: 0 0 0 0 rgba(229, 83, 75, .55); } 80%, 100% { box-shadow: 0 0 0 .5rem rgba(229, 83, 75, 0); } }
@media (prefers-reduced-motion: reduce) { .recdot--live { animation: none; } }
.rec--unknown, .rec--idle { color: var(--ink-soft); }
.recp .recdot { background: var(--ink-faint); }
.recp .recdot--live { background: var(--live); }
.recp__src .choice--off { opacity: .6; }

/* A card's head: its title, and its controls, always visible. */
.tc__head { display: flex; align-items: flex-start; gap: var(--sp-2); }
.tc__head .tc__title { flex: 1; min-width: 0; }
/* The card's controls and number on a row of their own, so the title keeps
   the card's whole width. */
.tc__top { display: flex; align-items: center; gap: var(--sp-2); margin-top: .1rem; }
.tm__bar .btn { white-space: nowrap; }
.tc__src--rules { color: var(--warn); border-color: var(--warn); }
.tc__pron { font: 500 var(--step--1)/1 var(--sans); color: var(--table-soft); white-space: nowrap; }
.tc__ctl { display: inline-flex; align-items: center; gap: .15rem; flex: none; }
.tc__btn { display: inline-grid; place-items: center; width: 1.9rem; height: 1.9rem; padding: 0; cursor: pointer;
  background: none; border: 1px solid transparent; border-radius: var(--r-2); color: var(--table-soft); }
.tc__btn:hover { border-color: var(--table-rule); color: var(--table-ink); }
.tc__btn.is-on { color: var(--accent); border-color: var(--accent); }
.tc__btn.is-shown { color: var(--good); }
.tc__btn[aria-pressed="true"] { border-color: var(--table-soft); color: var(--table-ink); }
.tc__pin { font: 600 .72rem/1 var(--sans); letter-spacing: .04em; padding: .3rem .4rem; cursor: pointer;
  background: none; border: 1px solid var(--table-rule); border-radius: var(--r-2); color: var(--table-soft); }
.tc__pin.is-on { color: var(--accent); border-color: var(--accent); }
/* Where a card came from (TB-024), beside what it is. */
.tc__src { font: 600 .68rem/1 var(--sans); letter-spacing: .05em; text-transform: uppercase; padding: .2rem .35rem; border-radius: 4px; border: 1px solid var(--table-rule); color: var(--table-soft); white-space: nowrap; }
.tc__src--wiki { color: var(--accent); border-color: var(--accent); }
.tc__src--gen { color: var(--gm); border-color: var(--gm); }
/* An NPC's glance face. */
.tc__lead { font: var(--step-0)/1.4 var(--serif); color: var(--table-ink); }
.tc__facts { margin: 0; padding-left: 1.1rem; font-size: var(--step--1); color: var(--table-soft); line-height: 1.45; }
.tc__voice { display: flex; gap: var(--sp-1); align-items: center; font-size: var(--step--1); font-style: italic; color: var(--table-ink); }
/* The main board is taller now that cards carry their faces. */
.tm .fb, .fb--tall { height: 40rem; }
.fb--state, .tm .fb--state { display: grid; place-items: center; padding: var(--sp-5); height: 20rem; }
.fb__empty { display: grid; gap: var(--sp-2); justify-items: center; text-align: center; max-width: 34rem; color: var(--table-soft); }
.fb__empty b { color: var(--table-ink); font-family: var(--serif); font-size: var(--step-1); }
/* Moving and resizing (TB-019 to TB-021). */
.fb__card--drag { transform: rotate(-1.2deg) translateY(-4px); box-shadow: 0 16px 30px rgba(0, 0, 0, .45); cursor: grabbing; z-index: 3; }
.fb__ghost { position: absolute; height: 8rem; border: 2px dashed var(--table-rule); border-radius: var(--r-3); }
.fb__resize { position: absolute; right: 3px; bottom: 3px; width: 14px; height: 14px; cursor: nwse-resize;
  background: linear-gradient(135deg, transparent 50%, var(--accent) 50%, var(--accent) 60%, transparent 60%, transparent 70%, var(--accent) 70%, var(--accent) 80%, transparent 80%); }
.fb__card--new { border-style: dashed; border-color: var(--accent); }
.fb__newtag { position: absolute; font: 600 .7rem/1 var(--sans); letter-spacing: .05em; text-transform: uppercase; color: var(--accent); }

/* The cold open's second line: quests and what was carried. */
.coldopen__more { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); font-size: var(--step--1); color: var(--table-soft); }
.coldopen__more span { display: inline-flex; gap: var(--sp-1); align-items: center; flex-wrap: wrap; }
.coldopen__more b { color: var(--table-ink); font-weight: 600; }
.coldopen--err p { display: flex; gap: var(--sp-2); align-items: center; }
.coldfold { display: inline-flex; gap: var(--sp-1); align-items: center; }

/* The stage's top row: where it is, ‹ › and ×; and its notes. */
.spot__top { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.spot__top .btn { min-height: 36px; min-width: 36px; }
.spot--empty { padding: var(--sp-4) var(--sp-5); }
.spot__notes { display: grid; gap: var(--sp-1); }
.spot__notes .note { min-height: 3.4rem; font-size: var(--step--1); }

/* D54 · the quick note, a stamped log. */
.qn { list-style: none; margin: var(--sp-2) 0; padding: 0; display: grid; gap: var(--sp-1); font-size: var(--step--1); }
.qn li { display: grid; grid-template-columns: 4.2rem minmax(0, 1fr); gap: var(--sp-2); }
.qn__t { font-family: var(--mono); color: var(--table-soft); font-variant-numeric: tabular-nums; }
.qn__where { margin: var(--sp-1) 0 0; font-size: var(--step--1); color: var(--table-soft); }

/* D53 · Find. */
.pal { display: grid; gap: var(--sp-3); max-width: 34rem; margin: 0 auto; padding: var(--sp-4);
  background: var(--table-raised); border: 1px solid var(--table-rule); border-radius: var(--r-3); box-shadow: 0 18px 40px rgba(0, 0, 0, .4); }
.pal__box { display: flex; align-items: center; gap: var(--sp-2); }
.pal__box .field { flex: 1; }
.pal__group { display: grid; gap: var(--sp-1); }
.pal__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.pal__row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .1rem var(--sp-3); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-2); }
.pal__row.is-on { background: rgba(111, 158, 230, .18); box-shadow: inset 3px 0 0 var(--accent); }
.pal__t { font: 600 var(--step-0)/1.3 var(--serif); }
.pal__badge { font: 600 .7rem/1 var(--sans); letter-spacing: .05em; text-transform: uppercase; color: var(--table-soft); align-self: center; }
.pal__meta { grid-column: 1 / -1; font-size: var(--step--1); color: var(--table-soft); }
.pal__none { margin: 0; color: var(--table-soft); }
.pal__foot { margin: 0; font-size: var(--step--1); color: var(--table-soft); border-top: 1px solid var(--table-rule); padding-top: var(--sp-2); }
.peek__sb { max-height: 26rem; overflow: auto; }

/* What a card says, by what it is. */
.fc { position: relative; max-width: 22rem; }
.fc__body { display: grid; gap: var(--sp-1); font-size: var(--step--1); line-height: 1.45; }
.fc__body p { margin: 0; }
.fc__secret { padding: var(--sp-1) var(--sp-2); border-left: 2px dashed var(--gm); }
.fc__list { margin: 0; padding-left: 1.1rem; display: grid; gap: var(--sp-1); font-size: var(--step--1); line-height: 1.4; }
.fc__flavour { margin: 0; font: italic var(--step--1)/1.45 var(--serif); color: var(--table-ink); }
.fc__read { margin: 0; font: var(--step--1)/1.5 var(--serif); }
.fc__tbl td, .fc__tbl th { border-bottom-color: var(--table-rule); color: var(--table-ink); }
.fc__tbl td:first-child { color: var(--table-soft); }
.fc__more { justify-self: start; font-size: var(--step--1); }
.tablemode .truth { font-size: .7rem; padding: .12rem .3rem; }

/* A menu inside Table mode, on its palette. */
.tm-menu { background: var(--table-raised); border-color: var(--table-rule); color: var(--table-ink); }
.tm-menu .menu__list button { color: var(--table-ink); }
.tm-menu .menu__list button:hover { background: var(--table-bg); }
.tm-menu .menu__list--last { border-top-color: var(--table-rule); }
.menu__lab { display: block; padding: var(--sp-2) var(--sp-4) 0; font: 600 .7rem/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--table-soft); }
.menu__input { display: block; padding: .3rem var(--sp-3); }

/* D37's other states: both edges, growing, and the overview. */
.cv__edge--left { left: var(--sp-2); right: auto; box-shadow: 18px 0 22px 4px var(--table-bg); }
.cv__edge--left svg { transform: none; }
.fb--grow { width: 190%; background-color: transparent; }
.fb--grow::after { content: ''; position: absolute; top: 0; bottom: 0; left: 84%; right: 0; border-left: 2px dashed var(--accent); background: rgba(111, 158, 230, .06); }
.fb--overview { height: 16rem; }
.fb--overview .fb__card { min-height: 3.2rem; padding: var(--sp-1) var(--sp-2); }
.fb--overview .tc__title { font-size: .7rem; }
.cv__view { position: absolute; left: 0; top: 0; width: 62%; height: 100%; border: 2px solid var(--accent); border-radius: var(--r-3); pointer-events: none; }

/* The keys, and what a phone does instead. */
.keys { padding: var(--sp-4); border: 1px solid var(--table-rule); border-radius: var(--r-3); }
.keys__tbl th, .keys__tbl td { border-bottom-color: var(--table-rule); color: var(--table-ink); }
.keys__tbl td:first-child { width: auto; white-space: nowrap; }
.stale--block { border: 1px solid var(--warn); border-radius: var(--r-2); }

/* -- Lane 2 backfill (#696) ------------------------------------------------ */
/* D45: the campaign's name, system and description, at the foot of This week.
   Read once, so it sits last (D20) and its description is clamped. */
.about { display: grid; gap: .15rem; }
.about__name { margin: var(--sp-1) 0 0; font: 600 var(--step-0)/1.3 var(--sans); }
.about__sys { margin: 0; font-size: var(--step--1); color: var(--ink-soft); }
.about__d { margin: var(--sp-1) 0 0; font-size: var(--step--1); display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* The structured date and time picker (CA-214): a day, then hour, minute and
   AM/PM, each its own control, so a time cannot be typed into a wrong shape. */
.dtp { display: inline-flex; flex-wrap: wrap; gap: var(--sp-1); align-items: center; }
.dtp .field { width: auto; min-width: 0; }
.dtp__day { width: 9.5rem; }
.dtp__t { width: 4.6rem; }
.slot__hint { flex-basis: 100%; margin: 0; padding-left: calc(1.5rem + var(--sp-3)); }
/* A search match, marked where it falls (CA-096). */
.sr__mark { background: var(--accent-soft); color: inherit; border-radius: 2px; padding: 0; box-shadow: inset 0 -2px 0 var(--accent); }
/* A suggestion chip's description, drawn open (CA-126). */
.tipbub { position: relative; max-width: 22rem; margin-top: var(--sp-2); padding: var(--sp-2) var(--sp-3); font-size: var(--step--1); color: var(--ink-soft);
  background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--r-2); box-shadow: var(--shadow); }
.tipbub::before { content: ''; position: absolute; top: -6px; left: 1.4rem; width: 10px; height: 10px; background: inherit;
  border-left: 1px solid var(--rule-strong); border-top: 1px solid var(--rule-strong); transform: rotate(45deg); }
.tipbub b { color: var(--ink); }
/* Sessions list: a status that is neither confirmed nor played gets a word. */
.slist__title .chip { margin-left: var(--sp-1); vertical-align: middle; }
/* Members: wiki links, sheets, Foundry, and the forms that open under a row. */
.char__name--link { color: var(--accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
.char__sheet { font-size: var(--step--1); }
.char__fvtt { flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3); color: var(--ink-soft); }
.char__stats { color: var(--ink); font-variant-numeric: tabular-nums; }
.char__stale { color: var(--warn); }
.char__fvtt--warn { color: var(--warn); }
.char__fvtt .btn { min-height: 0; padding: 0 .3rem; }
.mem__form { margin: var(--sp-2) 0 var(--sp-1); padding: var(--sp-3) var(--sp-4); background: var(--paper-sunk); border-radius: var(--r-2); }
.mem__form .form { max-width: none; }
.mem__why { display: inline-grid; justify-items: end; gap: .1rem; }
.mem__why .form__hint { margin: 0; }
.invp { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); padding: var(--sp-4); background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--r-3); }
.invp .list { margin: 0; }
.invp__link { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.invp__url { flex: 1 1 14rem; min-width: 0; padding: .4rem .6rem; font: var(--step--1)/1.3 var(--mono); background: var(--paper-sunk);
  border: 1px solid var(--rule); border-radius: var(--r-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* On a phone the day takes its own line and the three small choices sit under
   it, beside the slot number rather than below it. */
@container app (max-width: 640px) {
  .slot > .dtp { flex: 1 1 0; min-width: 0; }
  .dtp__day { flex: 1 1 100%; width: auto; }
}

/* -- Lane 2b backfill (#696) ----------------------------------------------- */
/* Reputation levels (IS-088): an ordered list a campaign can rename. */
.levels { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: var(--sp-2); max-width: 26rem; }
.level { display: flex; gap: var(--sp-2); align-items: center; }
.level__n { width: 1.5rem; flex: none; font: 600 var(--step--1)/1 var(--mono); color: var(--ink-faint); }
.level .field { flex: 1; min-width: 0; }
/* Scenes paired with Foundry maps (IS-321). */
.pairs { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: 1px; background: var(--rule);
  border: 1px solid var(--rule); border-radius: var(--r-3); overflow: hidden; }
.pair { background: var(--paper-raised); display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); align-items: center; padding: var(--sp-3) var(--sp-4); }
.pair__scene { font-weight: 600; flex: 0 0 11rem; }
.pair__map { flex: 1 1 14rem; min-width: 0; font-size: var(--step--1); color: var(--ink-soft); }
.pair__map--bad { color: var(--warn); }
/* What an import skipped (CA-119). */
.warns { margin: var(--sp-2) 0 0; padding-left: 1.2rem; font-size: var(--step--1); color: var(--ink-soft); }

/* -- Shell backfill (#696) ------------------------------------------------- */
/* IS-160: an unread notification can be marked read on its own. Always
   there, not on hover: a phone has no hover. */
.notes__row { grid-template-columns: .9rem 1.2rem minmax(0, 1fr) auto; }
.notes__read { min-height: 0; padding: .15rem .35rem; align-self: center; }

/* -- Lane 6: threads and the audience picker (#659) ------------------------ */
/* Who can see something. Narrower than the table reads in the GM tint, so a
   private thread or note is never mistaken for a public one at a glance. */
.audpill { display: inline-flex; align-items: center; gap: .35rem; padding: .12rem .55rem; border: 1px solid var(--rule-strong);
  border-radius: 999px; font: 500 var(--step--1)/1.4 var(--sans); color: var(--ink-soft); background: var(--paper-raised); white-space: nowrap; }
button.audpill { cursor: pointer; }
.audpill--mine, .audpill--chosen, .audpill--gm { color: var(--gm); border-color: var(--gm); background: var(--gm-soft); }
.audpill__caret { font-size: .7em; }
.audmenu { width: 23rem; }
.audmenu__list { list-style: none; margin: 0; padding: var(--sp-2) 0; }
.audmenu__opt { display: grid; grid-template-columns: auto auto minmax(0, 1fr); gap: var(--sp-2); align-items: start; padding: var(--sp-2) var(--sp-4); cursor: pointer; }
.audmenu__opt.is-on { background: var(--accent-soft); }
.audmenu__opt > span { display: grid; gap: .1rem; }
.audmenu__opt .faint { font-size: var(--step--1); }
.audmenu__pick { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--rule); display: grid; gap: var(--sp-2); }
.audmenu__people { list-style: none; margin: 0; padding: 0; display: grid; gap: .35rem; font-size: var(--step--1); }
/* The board, and a Talk tab's list. */
.tlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-3); overflow: hidden; }
.trow { background: var(--paper-raised); display: flex; gap: var(--sp-3); align-items: center; padding: var(--sp-3) var(--sp-4); }
.trow--new .trow__title { font-weight: 700; }
.trow__main { flex: 1; min-width: 0; display: grid; gap: .3rem; }
.trow__top { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.trow__title { font-weight: 600; color: var(--ink); text-decoration: none; }
.trow__meta { font-size: var(--step--1); color: var(--ink-soft); }
.trow__on { display: inline-flex; align-items: center; gap: .25rem; }
.trow__side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-1); flex: none; }
.trow__new { font: 600 var(--step--1)/1 var(--sans); color: var(--accent); }
@container app (max-width: 640px) {
  .trow { flex-wrap: wrap; }
  .trow__main { flex-basis: 100%; }
  .trow__side { flex-direction: row; align-items: center; }
}
/* One thread: forum style, oldest first (D59). */
.thread { display: grid; gap: var(--sp-4); }
.thread__top { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; font-size: var(--step--1); color: var(--ink-soft); }
.thread__title { margin: var(--sp-2) 0 var(--sp-3); }
.thread__meta { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; font-size: var(--step--1); }
.thread__verdict { margin: var(--sp-3) 0 0; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-2); font-size: var(--step--1); background: var(--paper-sunk); display: flex; gap: .4rem; align-items: center; }
.thread__verdict--confirmed { background: var(--accent-soft); color: var(--accent-ink); }
.thread__posts { display: grid; gap: var(--sp-3); }
.post { border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-raised); padding: var(--sp-3) var(--sp-4); display: grid; gap: var(--sp-2); }
.post--answer { border-color: var(--accent); box-shadow: inset 3px 0 0 var(--accent); }
/* Unread when the thread was opened (#1020): a dot and the word New beside the name; never colour alone. */
.post__new { display: inline-flex; align-items: center; gap: var(--sp-1); font: 600 var(--step--1) / 1.3 var(--sans); color: var(--accent-ink); }
.post__newdot { width: 0.45rem; height: 0.45rem; border-radius: 999px; background: var(--accent); }
.thread__since { display: flex; align-items: center; gap: var(--sp-3); font: 600 var(--step--1) / 1.3 var(--sans); color: var(--accent-ink); }
.thread__since::before, .thread__since::after { content: ""; flex: 1 1 0; border-top: 1px solid var(--accent); }
.thread__since::before { flex: 0 0 var(--sp-3); }
.post--note { border-style: dashed; border-color: var(--gm); background: var(--gm-soft); }
.post--hidden { border-style: dashed; }
.post--hidden .post__body { opacity: .6; }
.post--gone { background: transparent; border-style: dashed; }
.post__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.post__who { flex: 1 1 12rem; min-width: 0; }
.post__when { font-size: var(--step--1); }
.post__more { min-height: 0; padding: .1rem .3rem; }
.post__answer { margin: 0; font: 600 var(--step--1)/1.3 var(--sans); color: var(--accent); display: flex; align-items: center; gap: .35rem; }
.post__acts { font-size: var(--step--1); }
.treply { border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-raised); padding: var(--sp-3) var(--sp-4); display: grid; gap: var(--sp-2); }
.treply__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.treply__locked { margin: 0; padding: var(--sp-3) var(--sp-4); border: 1px dashed var(--rule-strong); border-radius: var(--r-3); display: flex; gap: .4rem; align-items: center; }
/* Table rules & safety (CAMP-18). */
.rules { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-3); overflow: hidden; }
.rules li { background: var(--paper-raised); display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; padding: var(--sp-3) var(--sp-4); }
.rules__t { flex: 1 1 14rem; }
.rules__acts { display: flex; gap: var(--sp-2); }
