/* ==========================================================================
   COMPONENTS — panels, headings, the shared ROWLINE grid, pips, steppers,
   chips, dialogs, popovers. Spacing tokens only; labels are .label only.
   ========================================================================== */

/* ---------- panels: double-rule frames with corner flourishes ---------- */
.panel{
  position:relative;
  background:
    radial-gradient(140% 100% at 50% 0%, color-mix(in srgb, var(--panel) 92%, #fff 8%) 0%, var(--panel) 55%, var(--panel-2) 100%);
  border:1px solid var(--rule);
  box-shadow:var(--shadow);
  padding:var(--pad);
  border-radius:var(--r-sm);
}
.panel::before{
  content:"";
  position:absolute; inset:4px;
  border:1px solid color-mix(in srgb, var(--rule) 55%, transparent);
  border-radius:var(--r-sm);
  pointer-events:none;
}

/* Play mode keeps the table surface calm and protects character construction
   controls. Notes and live-play trackers remain available. */
body:not(.is-edit-mode) .rm-btn,
body:not(.is-edit-mode) .add-btn,
body:not(.is-edit-mode) .lang-x,
body:not(.is-edit-mode) .resource-config{display:none !important}
body:not(.is-edit-mode) .prof-btn{pointer-events:none}

.toast.has-action,.dlg-note.has-action{pointer-events:auto}
.toast-action{
  flex:none;
  min-height:var(--field-chip);
  margin-left:var(--s3);
  padding:0 var(--s3);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  color:var(--gold-deep);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:700;
  letter-spacing:.08em;
  text-transform:uppercase;
}
.toast-action:hover{background:color-mix(in srgb,var(--gold-hi) 14%,transparent)}

.sync-status{
  display:inline-flex;align-items:center;justify-content:center;gap:.4rem;
  min-height:1.15rem;padding:0 .25rem;
  color:var(--ink-soft);font:600 .75rem/1 var(--font-display);letter-spacing:.03em
}
.sync-status::before{
  content:"";width:.42rem;height:.42rem;border-radius:50%;
  background:var(--green,#58765a);box-shadow:0 0 0 1px color-mix(in srgb,currentColor 16%,transparent)
}
.sync-status[data-state="saving"]::before{background:var(--gold);animation:sync-pulse 1s ease-in-out infinite}
.sync-status[data-state="retrying"]::before,.sync-status[data-state="offline"]::before,.sync-status[data-state="conflict"]::before{background:var(--rubric)}
@keyframes sync-pulse{50%{opacity:.35}}
@media (prefers-reduced-motion:reduce){.sync-status[data-state="saving"]::before{animation:none}}
.corner{
  position:absolute;
  width:20px;height:20px;
  color:var(--gold);
  opacity:.85;
  pointer-events:none;
}
.corner svg{display:block;width:100%;height:100%}
.corner--tl{top:2px;left:2px}
.corner--tr{top:2px;right:2px;transform:rotate(90deg)}
.corner--br{bottom:2px;right:2px;transform:rotate(180deg)}
.corner--bl{bottom:2px;left:2px;transform:rotate(270deg)}

/* ---------- chapter + sub headings ---------- */
.chapter{
  display:flex;
  align-items:center;
  gap:.6em;
  margin:0 0 var(--s3);
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(.78rem,.72rem + .26vw,.9rem);
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--ink-soft);
  text-align:center;
}
.chapter::before,.chapter::after{
  content:"";
  flex:1;
  height:1px;
  background:linear-gradient(90deg,transparent,var(--rule-soft));
}
.chapter::after{background:linear-gradient(90deg,var(--rule-soft),transparent)}
.chapter .fleuron{color:var(--gold);letter-spacing:0;font-family:var(--font-scribal);text-transform:none}

/* ==========================================================================
   THE HIERARCHY SYSTEM — three tiers, one vocabulary. Read before restyling
   any reference section (Panoply, Spellcraft, Features, Persona, Faculties).

     TIER 1  CHAPTER (.chapter)      the section opening — centred small-caps
                                     between fleurons and gradient rules.
     TIER 2  SUB-SECTION (.subsection + .subhead / .sp-head)
                                     a group inside a chapter (Weapons, Coin,
                                     Attunement…). A rubricated Cinzel rubric
                                     in illuminated gold, led by a ❧ aldus
                                     leaf and closed by a solid section rule,
                                     with its rows bracketed beneath a hairline
                                     left rule so the whole group reads as one.
     TIER 3  ROW / ELEMENT           the children — lighter ink, dotted rules,
                                     tucked inside the sub-section bracket.

   The eye parses CHAPTER > SUB-SECTION > ROW instantly because each tier
   changes on THREE axes at once: weight, colour, and containment. Keep this
   discipline — a new group is a .subsection with a .subhead, never a bare
   heading, and never a new colour outside the token palette.
   ========================================================================== */

/* the sub-section group. Base = shared vertical rhythm between groups.
   The --rows modifier adds a hairline bracket down the left that binds bare
   row-lists to the rubric heading above them (proximity + containment = "these
   are mine"). Groups whose children are already bordered cards (coin, shared
   items, resources, feature folios, profiles) skip the bracket so rules never
   double up — the card borders + the rubric header carry the hierarchy there. */
.subsection{margin-top:var(--s6)}
.subsection:first-child{margin-top:0}
.subsection--rows{
  padding-left:var(--s4);
  border-left:2px solid var(--rule-soft);
}

/* the heading is a tooltip target too — pad the band, not the type */
.subhead.has-rules{padding-block:var(--s1);margin-block:calc(-1 * var(--s1))}
/* TIER 2 rubric — bolder, illuminated, and marked, so a sub-section header can
   never be mistaken for a plain .label column-head or coin key (Tier 3). */
.subhead{
  margin:0 0 var(--s3);
  display:flex;align-items:center;gap:.5em;
  font-family:var(--font-display);
  font-size:var(--fs-small);
  font-weight:700;
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--gold-deep);
}
/* the aldus-leaf rubric mark — the manuscript sign for a new passage */
.subhead::before{
  content:"❧";
  flex:none;
  font-family:var(--font-scribal);
  font-weight:400;
  font-size:1.05em;
  line-height:1;
  color:var(--rubric);
}
.subhead::after{content:"";flex:1;height:1px;background:var(--rule)}
.subhead:first-child{margin-top:0}
.subhead .add-btn{flex:none}

.marginalia{
  margin:var(--s2) 0 0;
  font-family:var(--font-scribal);
  font-style:italic;
  font-size:var(--fs-small);
  color:var(--ink-faint);
}
.marginalia--alarm{color:var(--rubric)}

/* ---------- the empty state: one voice for absence, with a way out ---------- */
.empty-state{padding:var(--s3) 0;text-align:center}
.empty-state-title{
  margin:0 0 var(--s1);
  font-family:var(--font-display);
  font-size:var(--fs-small);
  font-weight:600;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--ink-soft);
}
.empty-state-line{margin:0;font-family:var(--font-scribal);font-style:italic;font-size:var(--fs-small);color:var(--ink-faint)}
.empty-state-hint{margin:var(--s1) 0 0;font-family:var(--font-scribal);font-style:italic;font-size:var(--fs-label);color:var(--ink-faint)}
.empty-state-actions{display:flex;justify-content:center;align-items:center;gap:var(--s2);margin-top:var(--s3);flex-wrap:wrap}
.empty-state--error .empty-state-line{color:var(--rubric)}
.empty-state--loading .empty-state-line{color:var(--ink-soft)}
/* grid hosts need the block to span; the ol host wraps it in an li at the call site */
.arms-grid .empty-state{grid-column:1/-1}

/* ==========================================================================
   THE ROWLINE — the shared row grid. Every repeating row type on the sheet
   (save/skill rows, spell rows, kit rows, trait rows, resource rows) builds
   on this template, so lead icons, text columns and trailing ✕ buttons all
   land on the same column edges sheet-wide. Dotted separators come from the
   row's own border, so they start/end on the same edges too.
   ========================================================================== */
.rowline{
  display:grid;
  grid-template-columns:var(--row-lead) minmax(0,1fr) auto var(--row-tail);
  align-items:center;
  column-gap:var(--s2);
  min-height:var(--field);
  border-top:1px dotted var(--rule-soft);
}
.rowline:first-of-type{border-top:none}
.rowline--notail{grid-template-columns:var(--row-lead) minmax(0,1fr) auto}
.row-lead{display:grid;place-items:center;width:var(--row-lead);height:var(--field)}

.feat-use-summary{
  color:var(--ink-soft);font-family:var(--font-display);font-size:var(--fs-label);
  font-weight:600;letter-spacing:.04em;white-space:nowrap
}
.feat-use-summary{display:inline-flex;align-items:center;min-height:var(--field);padding-inline:var(--s2)}
@media (max-width:600px){
  .feat-line .feat-row{grid-column:1;grid-row:1}
  .feat-line .rm-btn{grid-column:2;grid-row:1}
}

/* ---------- pips: none / proficient / expertise ---------- */
.ppip{
  position:relative;
  width:14px;height:14px;
  flex:none;
  border-radius:50%;
  border:1.5px solid var(--gold-deep);
  opacity:.55;
}
.ppip--1{
  background:radial-gradient(circle at 35% 30%,var(--gold-hi),var(--gold-deep) 75%);
  opacity:1;
  box-shadow:var(--pip-glow);
}
.ppip--2{
  background:radial-gradient(circle at 35% 30%,var(--gold-hi),var(--gold-deep) 75%);
  opacity:1;
  box-shadow:0 0 0 2px var(--panel-2), 0 0 0 3.5px var(--gold-deep), 0 0 9px color-mix(in srgb, var(--gold-hi) 80%, transparent);
}

/* ---------- round + diamond pips (slots, hit dice, death saves, AP) ---------- */
.pip{
  position:relative;
  width:var(--field);height:var(--field);
  flex:none;
  border-radius:50%;
  z-index:1;
}
.pip::before{
  content:"";
  position:absolute;inset:9px;
  border-radius:50%;
  border:1.5px solid var(--gold-deep);
  background:transparent;
  transition:background .18s ease, box-shadow .18s ease, transform .18s ease;
}
.pip.is-full::before{
  background:radial-gradient(circle at 35% 30%,var(--gold-hi),var(--gold-deep) 75%);
  box-shadow:var(--pip-glow);
}
.pip:active::before{transform:scale(.9)}
/* touch grows, the pip does not: ::before is the visual */
.pip--sm{width:var(--field);height:var(--field)}
.pip--sm::before{inset:13px}
.pip--dia::before{border-radius:var(--r-sm);transform:rotate(45deg);inset:11px}
.pip--dia.is-full::before{background:linear-gradient(135deg,var(--gold-hi) 10%,var(--gold) 50%,var(--gold-deep) 95%)}
.pip--dia:active::before{transform:rotate(45deg) scale(.88)}
.pip--dia.pip--sm::before{inset:15px}
.pip--succ::before{border-color:var(--mend)}
.pip--succ.is-full::before{background:linear-gradient(135deg,var(--mend),color-mix(in srgb,var(--mend) 55%, #000 10%))}
.pip--fail::before{border-color:var(--rubric)}
.pip--fail.is-full::before{background:linear-gradient(135deg,var(--rubric),var(--rubric-deep))}
.pip--ap{width:46px;height:46px}
.pip--ap::before{
  inset:10px;
  border-radius:var(--r-sm);
  transform:rotate(45deg);
}
.pip--ap.is-full::before{
  background:linear-gradient(135deg,var(--gold-hi) 10%,var(--gold) 50%,var(--gold-deep) 95%);
  box-shadow:var(--pip-glow);
}
.pip--ap:active::before{transform:rotate(45deg) scale(.88)}
.pip-row{display:flex;gap:0;flex-wrap:wrap;justify-content:center}
.vpips{display:flex;align-items:center;gap:0;flex-wrap:nowrap}

/* ---------- steppers ---------- */
.stepper{
  display:flex;
  align-items:center;
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  overflow:hidden;
}
.stepper button{
  width:var(--field);min-height:var(--field);
  font-family:var(--font-display);
  font-size:var(--fs-xl);
  font-weight:600;
  color:var(--ink-soft);
  transition:background-color .12s ease;
}
.stepper button:hover{background:color-mix(in srgb, var(--gold-hi) 18%, transparent)}
.stepper button:active{background:color-mix(in srgb, var(--gold-hi) 30%, transparent)}
.stepper output,
.stepper input[type="number"]{
  min-width:2.1em;
  text-align:center;
  font-family:var(--font-display);
  font-weight:700;
  font-size:var(--fs-lg);
  color:var(--ink);
}
.stepper input[type="number"]{
  width:4.5rem;
  min-height:var(--field);
  border:0;
  border-inline:1px solid var(--rule-soft);
  background:transparent;
  appearance:textfield;
}
.stepper input[type="number"]::-webkit-inner-spin-button,
.stepper input[type="number"]::-webkit-outer-spin-button{appearance:none;margin:0}
.stepper--tiny button{font-size:var(--fs-body)}
.stepper--tiny output,
.stepper--tiny input[type="number"]{min-width:1.8em;font-size:var(--fs-small)}
/* the dialog's standalone step buttons (− / + around a number input) */
.step-btn{
  width:var(--field);min-height:var(--field);
  display:grid;place-items:center;
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  font-family:var(--font-display);
  font-size:var(--fs-lg);
}

/* ---------- chips + switches + mode toggles ---------- */
.chip{
  display:inline-flex;
  align-items:center;
  gap:.35em;
  min-height:var(--field);
  padding:var(--s1) var(--s3);
  border:1px solid var(--rule);
  border-radius:var(--r-pill);
  background:var(--panel-2);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--ink-soft);
  transition:transform .1s ease, border-color .15s ease;
}
.chip:hover{border-color:var(--gold-deep)}
.chip:active{transform:scale(.97)}
.chip--active{
  border-color:var(--rubric);
  color:var(--rubric);
  background:color-mix(in srgb, var(--rubric) 8%, var(--panel-2));
}
.chip-x{font-size:.85em;opacity:.7}
.chip--add{border-style:dashed;color:var(--gold-deep);border-color:var(--gold-deep)}

.mode-chip{
  display:flex;
  margin:0 auto;
  border:1px solid var(--rule);
  border-radius:var(--r-pill);
  background:var(--panel-2);
  padding:3px;
  gap:3px;
}
.mode-chip button{
  min-height:var(--field);
  padding:var(--s1) var(--s4);
  border-radius:var(--r-pill);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--ink-faint);
  transition:background-color .18s ease,color .18s ease,box-shadow .18s ease;
}
.mode-chip button[aria-pressed="true"]{
  background:linear-gradient(180deg,var(--gold-btn-a),var(--gold-btn-b));
  color:var(--on-gold);
  box-shadow:inset 0 1px 0 color-mix(in srgb, var(--gold-hi) 70%, transparent), 0 1px 3px rgba(60,35,5,.35);
  text-shadow:0 1px 1px rgba(60,35,5,.35);
}
.mode-chip button:disabled{opacity:.4}

.switch{
  grid-row:span 2;
  position:relative;
  width:56px;height:32px;
  min-width:56px;
  border:1px solid var(--rule);
  border-radius:var(--r-pill);
  background:var(--panel-2);
  transition:background-color .18s ease, border-color .18s ease;
}
.switch::after{
  content:"";
  position:absolute;
  top:3px;left:3px;
  width:24px;height:24px;
  border-radius:50%;
  background:linear-gradient(180deg,#fdf6e4,#d9c9a4);
  border:1px solid var(--rule);
  transition:transform .18s ease;
}
.switch[aria-checked="true"]{background:linear-gradient(180deg,var(--gold),var(--gold-deep));border-color:var(--gold-deep)}
.switch[aria-checked="true"]::after{transform:translateX(24px)}
.switch:disabled{cursor:default;opacity:.55}



/* ==========================================================================
   RULES POPOVER — long-press a rules-bearing element
   ========================================================================== */
.rules-pop{
  position:fixed;
  z-index:120;
  width:min(23rem, calc(100vw - 1.4rem));
  max-height:min(60vh, 30rem);
  overflow-y:auto;
  padding:var(--s3) var(--s4) var(--s4);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  background:
    radial-gradient(140% 100% at 50% 0%, color-mix(in srgb, var(--panel) 94%, #fff 6%) 0%, var(--panel) 55%, var(--panel-2) 100%);
  box-shadow:0 24px 50px -22px rgba(30,15,0,.8);
  color:var(--ink);
}
.rules-pop::before{
  content:"";
  position:absolute; inset:3px;
  border:1px solid color-mix(in srgb, var(--gold) 30%, transparent);
  border-radius:var(--r-sm);
  pointer-events:none;
}
.rp-kicker{margin:0}
.rp-title{
  margin:var(--s1) 0 var(--s2);
  font-family:var(--font-display);
  font-size:var(--fs-small);
  font-weight:700;
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--ink);
  padding-bottom:var(--s1);
  border-bottom:1px solid var(--rule-soft);
}
.rp-body{font-size:var(--fs-small);line-height:1.42;color:var(--ink-soft)}
.rp-body p{margin:var(--s2) 0}
.rp-body b{
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:700;
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--gold-deep);
  margin-right:.3em;
}
.rp-body b.rp-inline{display:inline;font-size:inherit;letter-spacing:0;text-transform:none;color:inherit}
.rp-body h4{
  margin:var(--s3) 0 var(--s1);
  display:flex;align-items:center;gap:.5em;
}
.rp-body h4::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--rule-soft),transparent)}
.rp-body ul{margin:var(--s1) 0;padding-left:1.05em}
.rp-body li{margin:var(--s1) 0}
.rp-body .rp-em{
  font-family:var(--font-scribal);
  font-style:italic;
  color:var(--ink-faint);
}
.rp-close{
  display:block;
  margin:var(--s3) 0 0 auto;
  min-height:var(--field-compact);
  padding:var(--s1) var(--s3);
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.15em;
  text-transform:uppercase;
  color:var(--ink-faint);
}

/* ==========================================================================
   DIALOGS — appendix pages of the same book
   ========================================================================== */
dialog.book-dialog{
  width:min(30rem,calc(100vw - 1.4rem));
  max-height:calc(100dvh - 2rem);
  margin:auto;
  padding:0;
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:
    radial-gradient(140% 100% at 50% 0%, color-mix(in srgb, var(--panel) 92%, #fff 8%) 0%, var(--panel) 55%, var(--panel-2) 100%);
  color:var(--ink);
  box-shadow:0 30px 70px -30px rgba(30,15,0,.75);
}
dialog.book-dialog::backdrop{background:rgba(38,24,8,.55);backdrop-filter:blur(2px)}
/* dialogs carry their own grain — body::before cannot reach the top layer */
dialog.book-dialog::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:2;
  pointer-events:none;
  opacity:var(--noise-o);
  mix-blend-mode:var(--noise-blend);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}
.rules-inner{
  position:relative;
  padding:var(--s5);
  border:1px solid color-mix(in srgb, var(--rule) 55%, transparent);
  margin:5px;
  overflow-y:auto;
  max-height:calc(100dvh - 2rem - 10px);
}
.rules-kicker{
  text-align:center;
  letter-spacing:.3em;
  margin:0 0 var(--s1);
}
.rules-title{text-align:center;font-family:var(--font-scribal);font-weight:400;font-size:var(--fs-2xl);margin:0 0 var(--s1)}
.rules-sub{
  text-align:center;
  font-family:var(--font-scribal);
  font-style:italic;
  color:var(--ink-faint);
  margin:0 0 var(--s4);
  font-size:var(--fs-small);
}
.rules-list{list-style:none;margin:0;padding:0}
.rules-list li{
  display:grid;
  grid-template-columns:1fr auto;
  gap:var(--s1) var(--s4);
  align-items:center;
  padding:var(--s3) 0;
}
.rules-list li + li{border-top:1px dotted var(--rule-soft)}
.rule-name{
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--ink);
  display:flex;align-items:center;gap:.45em;flex-wrap:wrap;
}
.rule-desc{
  grid-column:1;
  font-family:var(--font-scribal);
  font-style:italic;
  font-size:var(--fs-small);
  color:var(--ink-faint);
}
.scope-tag{
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.13em;
  padding:.14em .5em;
  border:1px solid var(--rule-soft);
  border-radius:var(--r-pill);
  color:var(--ink-faint);
  text-transform:uppercase;
}
.scope-tag--game{border-color:color-mix(in srgb, var(--gold-deep) 60%, transparent);color:var(--gold-deep)}

.rules-close{
  display:block;
  margin:var(--s4) auto 0;
  min-height:var(--field);
  padding:var(--s2) var(--s5);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.15em;
  text-transform:uppercase;
  color:var(--gold-deep);
}
.rules-close:active{transform:translateY(1px)}

/* ---------- enchantment + form bits ---------- */
.ench-list{list-style:none;margin:0 0 var(--s4);padding:0}
.ench-list li{display:flex;align-items:center;gap:var(--s3);padding:var(--s2) 0;border-bottom:1px dotted var(--rule-soft)}
.ench-list .e-val{
  font-family:var(--font-display);
  font-weight:700;
  font-size:var(--fs-body);
  color:var(--verdigris);
  flex:none;
  min-width:2.4em;
}
.ench-list .e-src{flex:1;min-width:0;font-family:var(--font-scribal);font-style:italic;color:var(--ink-soft);overflow-wrap:anywhere}
.ench-list li.is-derived .e-src{color:var(--ink-faint)}
.e-lock{
  flex:none;
  padding:.1em .45em;
  border:1px solid var(--ward);
  border-radius:var(--r-pill);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:700;
  letter-spacing:.11em;
  text-transform:uppercase;
  color:var(--ward);
  white-space:nowrap;
}
.ench-rm{flex:none;width:var(--field);height:var(--field);color:var(--rubric);font-size:var(--fs-body);border-radius:var(--r-sm)}
.ench-rm:hover{background:color-mix(in srgb, var(--rubric) 12%, transparent)}

.form-row{margin-bottom:var(--s3)}
.form-k{display:block;margin-bottom:var(--s1)}
.text-in,.sel-in{
  width:100%;
  min-height:var(--field);
  padding:var(--s2) var(--s3);
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:var(--fs-body);
}
.num-row{display:flex;align-items:center;gap:var(--s3)}
.num-in{
  width:5rem;
  min-height:var(--field);
  padding:var(--s2);
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  color:var(--ink);
  font-family:var(--font-display);
  font-weight:700;
  font-size:var(--fs-body);
  text-align:center;
}
.dlg-note{
  margin:var(--s4) 0 0;
  padding:var(--s2) var(--s3);
  border:1px solid var(--verdigris);
  border-radius:var(--r-sm);
  background:color-mix(in srgb, var(--verdigris) 8%, transparent);
  color:var(--verdigris-hi);
  font-family:var(--font-scribal);
  font-style:italic;
  font-size:var(--fs-small);
  line-height:1.35;
  text-align:center;
}
.form-err{margin:var(--s1) 0 0;font-family:var(--font-scribal);font-style:italic;font-size:var(--fs-small);color:var(--rubric)}
.form-actions{display:flex;gap:var(--s3);margin-top:var(--s4)}
/* ==========================================================================
   BUTTON WEIGHT — three levels, and NO automatic stretching.

   Both button classes used to carry `flex:1`. Applied to all 99 buttons, that
   made every control in a flex row grow to fill it, so importance could never
   be encoded by size and — worse — a row containing only an EXIT gave the exit
   the whole width. Measured before this change: "Leave the Hall" rendered
   1048px wide on desktop while five real actions were exactly 130px each; on
   mobile the same rule made siblings ragged at 115/149/152/186/309.
   It also silently overrode justify-content:center at layout.css:66.

   Buttons now size to their content. Equal-width is opt-in, and it stays ON
   inside .form-actions, where a matched Cancel/Confirm pair IS correct.

   The three weights:
     .btn-ink            primary   — gold fill. The one thing to do here.
     .btn-quiet          secondary — panel fill, ruled border. Real actions.
     .btn-quiet--ghost   tertiary  — no fill, no border. Exits and sign-outs,
                                     which should be findable, never loudest.
   ========================================================================== */
.form-actions > .btn-ink,
.form-actions > .btn-quiet{flex:1}

/* ==========================================================================
   THE CAMPAIGN BAR — ONE spine for every campaign-scoped view.

   The app had six page headers built six different ways across four
   stylesheets, and the Live Table, Board and Workshop existed ONLY as chips in
   the Roster's row — so the Roster was a single point of failure with
   out-degree 8 while every other view had 2 or fewer. You could not go from the
   Board to the Workshop without travelling back through the Roster, and the
   Board's back button said "The Live Table", a screen you had never been on.

   Every campaign view now carries the same two bands:
     band 1   [‹ up]   KICKER / Title / subtitle        (identity, centred)
     band 2   Roster · Live Table · Board · Workshop  ...  this view's tools

   The destination group is identical everywhere and marks the current view, so
   the four places are always one tap apart and you can always see where you are.
   ========================================================================== */
/* ---------- ONE page shell for every campaign view ----------
   Tim, 2026-08-05: "every single one of these has a different padding and
   arrangement." They did — three wraps, three widths, three margins. One now.
   main.campaign-wrap outranks the legacy per-view classes (tag+class). */
main.campaign-wrap{
  width:min(var(--page-max),calc(100% - 2*var(--s4)));
  margin:var(--s4) auto var(--s7);
  padding:0;
}

/* ==========================================================================
   THE TOOLS SYSTEM — one shell, every screen, built to grow.

   Markup contract (add a tool = add one .tool button; nothing else changes):
     .rail-shell            positions the whole apparatus per tier
       .rail-fab            the circular hamburger (hidden on wide desktop)
       .rail                the toolbar itself
         .rail-label        "Tools"
         .tool              icon + sentence-case label
         .tool--switch      adds a slider knob (role=switch, aria-checked)
         .tool--primary     the page's headline action, gold icon

   Tiers:
     >=1440px   fixed far left, collapsed to icons; expands on hover/focus
     769-1439   docked as a row inside the header (campaign screens)
     <=768px    one circular button at the bottom; press expands the stack
     (.rail-shell--sheet skips the docked tier: the sheet has no header bar,
      so below 1440 it goes straight to the circular button.)
   ========================================================================== */
.rail-shell{z-index:45}
.rail{display:flex;flex-direction:column;gap:2px}
/* the caption floats ABOVE the box (Tim, test pass 4) — small, since it no
   longer has to fit inside the 58px pill that used to clip it to "TOOL" */
.rail-label{
  margin:0 0 2px;
  padding:0;
  font-family:var(--font-display);
  font-size:var(--fs-micro);
  font-weight:700;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--ink-faint);
  white-space:nowrap;
  text-align:center;
}
.tool{
  display:flex;
  align-items:center;
  gap:var(--s2);
  min-height:40px;
  /* 14px + 22px icon + 14px = 50px button in a 58px rail: icon truly centred */
  padding:0 14px;
  border-radius:var(--r-sm);
  color:var(--ink-soft);
  font-family:var(--font-body);
  font-size:var(--fs-small);
  white-space:nowrap;
  text-align:left;
}
.tool:hover{background:color-mix(in srgb, var(--gold-hi) 14%, transparent);color:var(--ink)}
.tool-ic{flex:none;width:22px;height:22px;color:var(--gold-deep)}
.tool--primary .tool-ic{color:var(--rubric)}
.tool-label{min-width:0;overflow:hidden;text-overflow:ellipsis}
/* the slider knob */
.tool--switch .tool-knob{
  flex:none;
  margin-left:auto;
  width:30px;height:16px;
  border:1px solid var(--rule);
  border-radius:var(--r-pill);
  background:var(--panel-2);
  position:relative;
  transition:background .15s ease;
}
.tool--switch .tool-knob::after{
  content:"";
  position:absolute;top:1px;left:1px;
  width:12px;height:12px;
  border-radius:50%;
  background:var(--ink-faint);
  transition:left .15s ease, background .15s ease;
}
.tool--switch[aria-checked="true"] .tool-knob{background:linear-gradient(180deg,var(--gold-btn-a),var(--gold-btn-b));border-color:var(--gold-deep)}
.tool--switch[aria-checked="true"] .tool-knob::after{left:15px;background:var(--on-gold)}
/* the circular hamburger — borrows the corner-fab language */
.rail-fab{
  width:54px;height:54px;
  border-radius:50%;
  border:1px solid var(--gold-deep);
  background:var(--panel);
  color:var(--gold-deep);
  display:flex;align-items:center;justify-content:center;
  box-shadow:var(--shadow);
}
.rail-fab .tool-ic{width:24px;height:24px}

/* ---- tier 1: wide desktop — far-left icon rail, hover to expand ---- */
@media (min-width:769px){
  .rail-shell{position:fixed;left:var(--s3);top:50%;transform:translateY(-50%)}
  .rail-fab{display:none}
  .rail{
    width:58px;
    overflow:hidden;
    padding:var(--s1);
    background:var(--panel);
    border:1px solid var(--rule);
    border-radius:var(--r-md);
    box-shadow:var(--shadow);
    transition:width .16s ease;
  }
  .rail:hover,.rail:focus-within{width:14rem}
  .tool-label,.tool--switch .tool-knob{opacity:0;transition:opacity .12s ease}
  .rail:hover .tool-label,.rail:hover .tool--switch .tool-knob,
  .rail:focus-within .tool-label,.rail:focus-within .tool--switch .tool-knob{opacity:1}
  /* the caption stays pinned over the icon column, even while the rail expands */
  .rail-label{width:58px}
}


/* ---- tier 3: mobile — the circular button at the bottom, stack on press ---- */
@media (max-width:768px){
  .rail-shell{position:fixed;right:var(--s4);bottom:calc(var(--s4) + env(safe-area-inset-bottom))}
  .cbar .rail-shell{position:fixed}
  /* the pop (caption + box) hides behind the wrench until pressed */
  .rail-pop{display:none;position:absolute;right:0;bottom:64px}
  .rail-shell.is-open .rail-pop{display:block}
  .rail{
    display:flex;
    width:max-content;
    min-width:13rem;
    padding:var(--s2);
    background:var(--panel);
    border:1px solid var(--rule);
    border-radius:var(--r-md);
    box-shadow:var(--shadow);
  }
  .rail-label{text-align:right;padding-inline:var(--s1)}
}

/* ==========================================================================
   THE CAMPAIGN HEADER — one component, rendered identically on all four
   campaign views. Replaces four bespoke headers that each invented their own
   alignment (a centred kicker over a left title, a back button at its own
   inset, three parts of one identity block on two axes).

   Structure, top to bottom, every edge on ONE inset (--s4):
     row 1   [‹ up]   Campaign › Here                    [this view's tools]
     row 2   subtitle (optional)
     row 3   Roster · Live Table · The Board · Workshop
   ========================================================================== */
/* THE one campaign bar — a single element above the .page shell, so the four
   screens can never drift apart again (Tim: "make this literally one element").
   Sticky, full natural width — no 100vw hacks, so no scrollbar overflow. */
#campaign-bar{position:sticky;top:0;z-index:44}
.cbar{
  display:grid;
  row-gap:var(--s2);
  /* Tim picked the Map's full-width configuration as THE header: flush to the
     viewport, no radius, one border below, identical padding on every view. */
  margin:0;
  padding:var(--s2) var(--s4);
  border-radius:0;
  border-inline:0;
  border-top:0;
}
.cbar-top{
  display:grid;
  /* [‹][campaign › here][site-menu nav][mobile nav hamburger] — one row, no sub */
  grid-template-columns:auto minmax(0,1fr) auto auto;
  align-items:center;
  column-gap:var(--s3);
  min-height:var(--field);
}
.cbar-go .btn-quiet{min-height:36px;padding-inline:var(--s3)}
/* the mobile places-hamburger: inverted — a leather field with parchment lines */
.nav-fab{
  display:none;
  width:40px;height:40px;
  border-radius:50%;
  border:1px solid var(--gold-deep);
  background:linear-gradient(180deg,var(--gold-btn-a),var(--gold-btn-b));
  color:var(--on-gold);
  align-items:center;justify-content:center;
}
.nav-fab .tool-ic{width:20px;height:20px;color:inherit}
@media (max-width:768px){
  #cbar-nav{display:none}
  .cbar.nav-open #cbar-nav{
    display:block;
    position:absolute;
    right:var(--s3);
    top:calc(100% + var(--s1));
    padding:var(--s2);
    background:var(--panel);
    border:1px solid var(--rule);
    border-radius:var(--r-md);
    box-shadow:var(--shadow);
    z-index:46;
  }
  .cbar.nav-open .cbar-go{flex-direction:column;align-items:stretch}
  .nav-fab{display:flex}
  .cbar{position:relative}
}
/* The ghost has no visible box, so what reads as its position is its TEXT.
   Zero inline padding puts that text on exactly the inset every button BOX
   below sits on — the top-left/bottom-left mismatch was this padding. */
/* .cbar-top .cbar-up, not .cbar-up alone: .btn-quiet declares padding-inline
   later in this file and would win the single-class specificity tie — which is
   exactly the 17px ghost the measurement caught (16px padding + 1px transparent
   border). The border goes too; hover keeps its colour shift. */
.cbar-top .cbar-up{padding-inline:0;border:0;justify-self:start;white-space:nowrap}
.cbar-crumb{
  margin:0;
  display:flex;
  align-items:baseline;
  gap:.5em;
  min-width:0;
  font-size:var(--fs-lg);
  font-weight:400;
}
.cbar-campaign{
  font-family:var(--font-display);
  font-weight:600;
  color:var(--ink);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.cbar-sep{color:var(--ink-faint);flex:none}
.cbar-here{font-family:var(--font-scribal);font-style:italic;color:var(--ink-soft);white-space:nowrap}
.cbar-sub{margin:0;font-family:var(--font-scribal);font-style:italic;font-size:var(--fs-small);color:var(--ink-faint)}
.cbar .cbar-nav{display:flex;align-items:center}
.cbar-top .cbar-tools{justify-content:flex-end}
/* The board's bar runs edge to edge over the stage. */
.cbar--flush{/* absorbed into .cbar 2026-08-05 */}
@media (max-width:760px){
  .cbar-top{grid-template-columns:auto minmax(0,1fr)}
  .cbar-top .cbar-tools{grid-column:1 / -1;justify-content:stretch;padding-top:var(--s2)}
  .cbar-top .cbar-tools > *{flex:1}
}

.cbar-nav{
  /* The four headers this drops into are built three different ways — one flex,
     one two-column grid, one bespoke bar. Rather than rewrite each parent (and
     risk four regressions), the bar claims a full row in EITHER layout model:
     `grid-column` spans every column of a grid parent, `flex:1 0 100%` forces
     its own line in a flex parent. Harmless in whichever one does not apply. */
  grid-column:1 / -1;
  flex:1 0 100%;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--s3);
  flex-wrap:wrap;
  margin-top:var(--s3);
  padding-top:var(--s3);
  border-top:1px solid var(--rule-soft);
}
.cbar-go,.cbar-tools{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
/* You-are-here. Not a button you press again — it is the label of the room you
   are standing in, so it loses the button chrome and gains the ink. */
.cbar-go [aria-current="page"]{
  background:none;
  border-color:transparent;
  color:var(--ink);
  cursor:default;
}
.cbar-go [aria-current="page"]::before{content:"❧ ";color:var(--gold-deep)}

.btn-ink{
  min-height:var(--field);
  padding-inline:var(--s4);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  background:linear-gradient(180deg,var(--gold-btn-a),var(--gold-btn-b));
  color:var(--on-gold);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:700;
  letter-spacing:.15em;
  text-transform:uppercase;
  text-shadow:0 1px 1px rgba(60,35,5,.35);
}
.btn-quiet{
  min-height:var(--field);
  padding-inline:var(--s4);
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  color:var(--ink-soft);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.15em;
  text-transform:uppercase;
}
/* Tertiary. Leaving is not an achievement — it should be findable, never the
   loudest thing on the page. Keeps the full 44px target and the same type, and
   drops only the fill and the border, so it reads as a link cast in the
   sheet's own voice rather than a fourth competing chip. */
.btn-quiet--ghost{
  border-color:transparent;
  background:none;
  color:var(--ink-faint);
}
.btn-quiet--ghost:hover{
  color:var(--ink-soft);
  border-color:var(--rule-soft);
}

.prompt-box{
  margin:0;
  padding:var(--s3);
  border:1px solid var(--rule-soft);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  font-family:var(--font-scribal);
  font-size:var(--fs-small);
  line-height:1.42;
  color:var(--ink-soft);
  white-space:pre-wrap;
  max-height:12rem;
  overflow-y:auto;
}
.cost-note{
  margin:var(--s4) 0 0;
  padding:var(--s2) var(--s3);
  border:1px solid var(--rubric);
  border-radius:var(--r-sm);
  background:color-mix(in srgb, var(--rubric) 7%, transparent);
  font-family:var(--font-scribal);
  font-style:italic;
  font-size:var(--fs-small);
  line-height:1.38;
  color:var(--ink-soft);
}
.cost-note b{
  font-family:var(--font-display);
  font-style:normal;
  font-size:var(--fs-label);
  font-weight:700;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--rubric);
  display:block;
  margin-bottom:var(--s1);
}

/* The corner fabs folded into the sheet's Tools shell (2026-08-05). The
   originals stay in the DOM as proxy targets — their wiring, state painting,
   and tests all still run — but nothing floats in the corners any more. */
.edit-fab,
#tray-handle{display:none !important}

/* Row discipline for the one bar (Tim, 2026-08-05): the places-menu and its
   mobile hamburger live ON the crumb row, hard right. These pin them there
   regardless of any earlier band-era rules. */
#cbar-nav{grid-row:1;grid-column:3;justify-self:end;display:flex;margin:0;padding:0;border:0;flex:none;width:auto}
#cbar-nav-fab{grid-row:1;grid-column:4;justify-self:end}

/* The Tools caption reads at label size; the rail widens to keep icons centred:
   14px + 22px icon + 14px = 50px content in a 58px rail. */

/* ==========================================================================
   THE CONFIRMATION MODAL — one shared gate (confirm.js): rests, level-up,
   removing a combatant. Above every drawer and tray (routine drawer is 120).
   ========================================================================== */
.confirm-scrim{
  position:fixed;inset:0;z-index:200;
  display:grid;place-items:center;
  padding:var(--s4);
  background:color-mix(in srgb, #14100a 46%, transparent);
}
.confirm-card{
  max-width:26rem;width:100%;
  padding:var(--s4);
  display:grid;gap:var(--s3);
}
.confirm-title{margin:0;font-family:var(--font-display);font-size:var(--fs-xl);color:var(--ink)}
.confirm-body{margin:0;color:var(--ink-soft)}
.confirm-row{display:flex;justify-content:flex-end;gap:var(--s2)}
.confirm-yes--danger{
  background:linear-gradient(180deg,var(--danger-a),var(--danger-b));
  border-color:var(--danger-b);
  color:var(--on-danger);
}
