/* ==========================================================================
   LAYOUT — page frame, header, sticky chrome, ribbon, quires, app views.
   One max-width container; every section aligns to it with the same panel
   padding (--pad). Spacing tokens only — see tokens.css for the rules.
   ========================================================================== */
.page{
  max-width:var(--page-max);
  margin-inline:auto;
  padding:var(--s3) var(--s4) var(--s7);
}

/* ---------- app views: login / picker / sheet ---------- */
.view{min-height:60dvh}
.login-wrap{
  max-width:26rem;
  margin:clamp(var(--s6),12vh,7rem) auto 0;
}
.login-form{display:grid;gap:var(--s4);margin-top:var(--s4)}
.login-title,.picker-title{
  text-align:center;
  font-family:var(--font-scribal);
  font-weight:400;
  font-size:var(--fs-2xl);
  margin:0 0 var(--s1);
}
.login-sub,.picker-sub{
  text-align:center;
  font-family:var(--font-scribal);
  font-style:italic;
  /* These two sit straight on the page background with no panel under them,
     which is the one place --ink-faint does not clear AA: 4.29:1 on --bg-0 at
     the top of the page, 3.57:1 on --bg-1 at the bottom. --ink-soft is the
     sheet's ink for unpanelled body copy — 5.63:1 and 4.69:1. */
  color:var(--ink-soft);
  margin:0 0 var(--s3);
  font-size:var(--fs-small);
}
.login-kicker{
  text-align:center;
  margin:0 0 var(--s1);
}
.picker-list{list-style:none;margin:var(--s4) 0 0;padding:0;display:grid;gap:var(--s2)}
.picker-card{
  display:grid;
  grid-template-columns:auto 1fr auto;
  align-items:center;
  gap:var(--s3);
  width:100%;
  min-height:var(--field-tall);
  padding:var(--s3) var(--s4);
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  text-align:left;
  transition:border-color .15s ease, background-color .15s ease;
}
.picker-card:hover{border-color:var(--gold-deep);background:var(--panel)}
.picker-name{font-family:var(--font-scribal);font-size:var(--fs-lg);color:var(--ink)}
.picker-meta{font-family:var(--font-scribal);font-style:italic;font-size:var(--fs-small);color:var(--ink-faint)}
.picker-chev{color:var(--gold-deep)}
.picker-seal{
  width:40px;height:40px;
  display:grid;place-items:center;
  border-radius:50%;
  background:var(--seal-wax);
  color:var(--rubric-ink);
  font-family:var(--font-display);
  font-weight:700;
}
.logout-row{display:flex;justify-content:center;margin-top:var(--s5)}

/* ==========================================================================
   HEADER — portrait seal + identity FIELDS
   Identity gets its own full-width row (never trapped beside the seal).
   ========================================================================== */
.sheet-header{margin-bottom:var(--s3)}
.header-row{
  display:grid;
  grid-template-columns:auto 1fr auto;
  grid-template-areas:
    "seal  name  settings"
    "sync  sync  sync"
    "ident ident ident";
  gap:var(--s2) var(--s3);
  align-items:center;
}
.header-row > .seal-wrap{grid-area:seal;position:relative}
.header-row > .name-wrap{grid-area:name;min-width:0}
.header-row > .header-tools{grid-area:settings;align-self:center}
.header-row > .header-sync{grid-area:sync;justify-self:end;margin-top:calc(var(--s1) * -1)}
.header-row > .ident{grid-area:ident}

/* the name column: the character name, left-aligned */
.name-wrap{display:flex;flex-direction:column;align-items:flex-start;gap:var(--s1);min-width:0}
.name-wrap > .charname{width:100%;min-width:0}

/* ---------- the portrait slot: a wax seal that can hold a likeness ---------- */
.seal{
  position:relative;
  width:clamp(58px,13vw,74px);
  height:clamp(58px,13vw,74px);
  flex:none;
  padding:0;
  border-radius:50%;
  align-self:center;
}
.seal svg{position:absolute;inset:0;width:100%;height:100%;display:block}
.seal .seal-wax{filter:drop-shadow(0 2px 3px rgba(50,20,5,.35))}
.seal .seal-ring{z-index:2;pointer-events:none}
.seal-img{
  position:absolute;
  inset:16%;
  z-index:1;
  width:68%;height:68%;
  object-fit:cover;
  border-radius:50%;
  clip-path:circle(50%);
  /* the stored file is a clean portrait; this colour grade is a display layer that
     warms it toward the parchment/oxblood of the wax (see --seal-grade) */
  filter:var(--seal-grade);
}
/* the wax blend: an oxblood vignette + inner shadow laid over the graded portrait
   so the likeness sinks into the seal. Display-only — the original file is untouched. */
.seal-tint{
  position:absolute;
  inset:16%;
  z-index:1;
  border-radius:50%;
  pointer-events:none;
  mix-blend-mode:multiply;
  background:
    radial-gradient(circle at 50% 38%, transparent 46%, color-mix(in srgb,var(--seal-wax) 62%,transparent) 100%),
    radial-gradient(circle at 50% 46%, color-mix(in srgb,var(--seal-wax-hi) 26%,transparent), transparent 72%);
  box-shadow:inset 0 0 7px 1px color-mix(in srgb,var(--seal-wax) 55%,transparent);
}
.seal-letter{
  position:absolute;
  inset:0;
  z-index:1;
  display:grid;
  place-items:center;
  font-family:var(--font-display);
  font-weight:700;
  font-size:var(--fs-2xl);
  color:var(--rubric-ink);
  opacity:.92;
  pointer-events:none;
}
/* letter fallback for a portrait whose file is missing: hidden until the <img>
   fails to load, at which point .portrait-missing hides the image + tint below */
.seal-letter--fallback{display:none}
.seal.portrait-missing .seal-img,
.seal.portrait-missing .seal-tint{display:none}
.seal.portrait-missing .seal-letter--fallback{display:grid}
.seal::after{
  content:"✎";
  position:absolute;
  right:-2px;bottom:-2px;
  z-index:3;
  width:19px;height:19px;
  display:grid;place-items:center;
  border:1px solid var(--gold-deep);
  border-radius:50%;
  background:var(--panel);
  color:var(--gold-deep);
  font-size:var(--fs-micro);
  line-height:1;
  opacity:0;
  transition:opacity .18s ease;
}
.seal:hover::after,.seal:focus-visible::after{opacity:1}
.seal:disabled{cursor:default}
.seal:disabled::after{display:none}

.seal-menu{
  position:absolute;
  top:calc(100% + 6px);
  left:0;
  z-index:70;
  width:max-content;
  min-width:12rem;
  padding:var(--s1);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  background:var(--panel);
  box-shadow:var(--shadow);
}
.seal-menu button{
  display:flex;
  flex-direction:column;
  gap:var(--s1);
  width:100%;
  min-height:var(--field);
  padding:var(--s2) var(--s3);
  border-radius:var(--r-sm);
  text-align:left;
  transition:background-color .15s ease;
}
.seal-menu button:hover{background:color-mix(in srgb, var(--gold-hi) 16%, transparent)}
.seal-menu button + button{border-top:1px dotted var(--rule-soft)}
.seal-menu b{
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.11em;
  text-transform:uppercase;
  color:var(--ink);
}
.seal-menu small{
  font-family:var(--font-scribal);
  font-style:italic;
  font-size:var(--fs-label);
  color:var(--ink-faint);
}

/* ---------- the summon dialog: an added detail + the limner at work ---------- */
.summon-field{margin-top:var(--s4)}
.summon-label{display:block;margin-bottom:var(--s1);color:var(--ink-soft)}
.summon-opt{font-weight:400;letter-spacing:normal;text-transform:none;color:var(--ink-faint)}
.summon-field textarea{
  width:100%;
  min-width:0;
  min-height:calc(var(--field) + var(--s3));
  padding:var(--s2) var(--s3);
  border:1px solid var(--rule-soft);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  color:var(--ink);
  font:400 .92rem/1.4 var(--font-scribal);
  resize:vertical;
}
.summon-field textarea:focus{
  border-color:var(--gold-deep);
  outline:2px solid color-mix(in srgb,var(--gold-hi) 30%,transparent);
  outline-offset:1px;
}
.summon-price{
  font-family:var(--font-display);
  font-style:normal;
  letter-spacing:.04em;
  color:var(--rubric);
}
.summon-working{
  display:flex;
  align-items:center;
  gap:var(--s2);
  margin:var(--s3) 0 0;
  padding:var(--s2) var(--s3);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  background:color-mix(in srgb,var(--gold-hi) 12%,transparent);
  color:var(--ink-soft);
  font-family:var(--font-scribal);
  font-style:italic;
  font-size:var(--fs-small);
}
.summon-quill{
  flex:none;
  width:14px;height:14px;
  border-radius:50%;
  border:2px solid color-mix(in srgb,var(--gold-deep) 35%,transparent);
  border-top-color:var(--gold-deep);
  animation:summon-spin 1s linear infinite;
}
@keyframes summon-spin{to{transform:rotate(360deg)}}
/* the seal, while a likeness is being summoned, glows like warming wax */
.seal.is-summoning{animation:seal-warm 1.6s ease-in-out infinite}
@keyframes seal-warm{
  0%,100%{filter:drop-shadow(0 0 0 transparent)}
  50%{filter:drop-shadow(0 0 6px color-mix(in srgb,var(--seal-wax) 70%,transparent))}
}
@media (prefers-reduced-motion:reduce){
  .summon-quill{animation:none;border-top-color:var(--gold-deep);opacity:.85}
  .seal.is-summoning{animation:none}
}

.charname{
  margin:0;
  font-family:var(--font-scribal);
  font-weight:400;
  font-size:clamp(1.7rem,5.8vw,2.6rem);
  line-height:1.06;
  letter-spacing:.01em;
  color:var(--ink);
}
/* dropcap is the field's own ::first-letter — follows the name live */
.name-field{
  display:inline-block;
  min-width:4em;
  min-height:0;
  padding:0 .15em;
  border-bottom:1px dotted transparent;
}
.name-field:hover{border-bottom-color:var(--rule)}
.name-field::first-letter{
  float:left;
  margin:.02em .12em 0 0;
  padding:.1em .16em;
  font-family:var(--font-display);
  font-weight:700;
  font-size:.82em;
  line-height:1.16;
  color:var(--rubric);
  background:
    linear-gradient(160deg, color-mix(in srgb, var(--gold-hi) 26%, transparent), transparent 55%),
    var(--panel);
  border:1px solid var(--gold);
  box-shadow:inset 0 0 0 3px var(--panel), inset 0 0 0 4px var(--rule-soft);
  border-radius:var(--r-sm);
}

/* THE IDENTITY GRID — the first mismatch Tim named.
   Every cell is the same .kv component: one .label, one value line of the
   same --field height, one dotted rule spanning the full cell width. The
   rhythm is even because the grid owns it, not the cells. */
.ident{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:var(--s2) var(--s4);
  margin:var(--s3) 0 0;
  padding:var(--s3) 0 0;
  border-top:1px solid var(--rule-soft);
}
.kv{display:flex;flex-direction:column;gap:var(--s1);min-width:0}
.kv > .kv-v{
  display:flex;
  align-items:center;
  min-height:var(--field);
  font-size:var(--fs-small);
  color:var(--ink);
  min-width:0;
}
.kv > .kv-v .ink-field,
.kv > .kv-v .ink-sel{font-size:var(--fs-small);width:100%;min-width:0}
.header-derived{
  display:inline-flex;
  align-items:center;
  min-height:var(--field);
  font-family:var(--font-display);
  font-weight:700;
  color:var(--gold-deep);
}

@media (min-width:900px){
  .ident--character{
    grid-template-columns:minmax(64px,.55fr) minmax(92px,.7fr) repeat(5,minmax(0,1fr));
  }
  .ident--character.ident--with-xp{
    grid-template-columns:minmax(64px,.5fr) minmax(92px,.65fr) minmax(74px,.55fr) repeat(5,minmax(0,1fr));
  }
}

/* ---------- the roster return: a corner handle at the sheet's top-left ----------
   Mirrors the bottom-left Edit FAB and bottom-right dice handle, but ANCHORED
   (position:absolute, never fixed) to the top of the sheet view, so it scrolls
   away with the page and only offers itself at the very top. The sheet view is
   the positioning context; the header is nudged clear so nothing overlaps. */
#view-sheet{position:relative;padding-top:calc(54px + var(--s2))}
/* selector out-specifies .has-tip{position:relative} so the corner stays ANCHORED
   (absolute), out of flow — the button is still its own tooltip anchor. */
/* The sheet's ONLY exit, and it used to be position:absolute — so on the app's
   longest screen (9.8 phone-screens end to end) it scrolled away and left a
   player mid-sheet with no navigation at all. `fixed` pins it to the viewport,
   so leaving is always one tap. It sits under #chrome's z-index:44 so the
   running head still wins where they overlap. */
#view-sheet > .sheet-back-fab{
  position:fixed;
  top:0;
  left:max(0px, env(safe-area-inset-left));
  z-index:40;
  width:54px;height:54px;
  display:grid;place-items:center;
  padding:0;
  border:1px solid var(--gold-deep);
  border-radius:50%;
  background:
    radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--gold-hi) 40%, transparent), transparent 60%),
    linear-gradient(180deg,var(--panel),var(--panel-2));
  color:var(--gold-deep);
  box-shadow:0 8px 20px -8px rgba(30,15,0,.8);
  transition:transform .18s ease, background-color .15s ease, border-color .15s ease;
}
.sheet-back-fab svg{width:26px;height:26px;display:block}
.sheet-back-fab:hover{background:var(--panel);border-color:var(--gold);transform:translateX(-2px)}
.sheet-back-fab:active{transform:translateX(-2px) scale(.95)}
@media (prefers-reduced-motion:reduce){
  .sheet-back-fab{transition:background-color .15s ease, border-color .15s ease}
  .sheet-back-fab:hover,.sheet-back-fab:active{transform:none}
}

/* ---------- the settings cog + its parchment popover ---------- */
.header-tools{display:flex;align-items:center;gap:var(--s2);justify-content:flex-end}
.header-sync{white-space:nowrap;font-size:var(--fs-micro);letter-spacing:.12em;text-transform:uppercase}
.settings-wrap{position:relative;flex:none}
.settings-btn{
  display:grid;place-items:center;
  width:var(--field);height:var(--field);
  min-width:var(--field);min-height:var(--field);
  padding:0;
  border:1px solid var(--rule);
  border-radius:50%;
  background:var(--panel-2);
  color:var(--gold-deep);
  transition:transform .2s ease, background-color .15s ease, border-color .15s ease;
}
.settings-btn svg{width:22px;height:22px;display:block;transition:transform .2s ease}
.settings-btn:hover,
.settings-btn[aria-expanded="true"]{background:var(--panel);border-color:var(--gold-deep)}
/* the cog turns, not the whole button — so the tooltip stays upright */
.settings-btn[aria-expanded="true"] svg{transform:rotate(35deg)}
/* while the menu is open the cog's own tooltip is redundant — keep it hidden
   even on hover (higher specificity than .has-tip:hover::after) */
.settings-btn.has-tip[aria-expanded="true"]::after{opacity:0}
@media (prefers-reduced-motion:reduce){.settings-btn svg{transition:none}.settings-btn[aria-expanded="true"] svg{transform:none}}
.settings-menu{
  position:absolute;
  top:calc(100% + var(--s1));
  right:0;
  z-index:70;
  width:max-content;min-width:13rem;max-width:calc(100vw - 2rem);
  padding:var(--s1);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  background:var(--panel);
  box-shadow:var(--shadow);
}
.settings-item{
  display:flex;align-items:center;gap:var(--s2);
  width:100%;min-height:var(--field);
  padding:var(--s2) var(--s3);
  border-radius:var(--r-sm);
  text-align:left;
  color:var(--ink);
  font-family:var(--font-display);
  font-size:var(--fs-label);font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  transition:background-color .15s ease;
}
.settings-item + .settings-item{border-top:1px dotted var(--rule-soft)}
.settings-item:hover{background:color-mix(in srgb, var(--gold-hi) 16%, transparent)}
.settings-item .settings-item-ic{display:inline-grid;place-items:center;flex:none}
.settings-item .settings-item-ic svg{width:19px;height:19px;display:block;color:var(--gold-deep)}
.settings-item .tool-label--short{display:none}

@media (max-width:620px){
  .charname{font-size:clamp(1.45rem,8vw,1.8rem)}
  .name-field{min-width:0}
  .ident{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s2) var(--s3)}
}

/* ---------- the whispered tooltip: label on hover / focus, parchment ---------- */
.has-tip{position:relative}
.has-tip::after{
  content:attr(data-tip);
  position:absolute;
  z-index:80;
  padding:var(--s1) var(--s2);
  border:1px solid var(--gold-deep);
  border-radius:var(--r-sm);
  background:var(--panel);
  color:var(--ink);
  font:600 .62rem/1.1 var(--font-display);
  letter-spacing:.08em;text-transform:uppercase;
  white-space:nowrap;
  pointer-events:none;
  opacity:0;
  transition:opacity .15s ease;
}
.has-tip:hover::after,
.has-tip:focus-visible::after{opacity:1}
.has-tip--below-l::after{top:calc(100% + var(--s1));left:0}
.has-tip--below-r::after{top:calc(100% + var(--s1));right:0}
.has-tip--above-r::after{bottom:calc(100% + var(--s1));left:0}
@media (prefers-reduced-motion:reduce){.has-tip::after{transition:none}}

/* ==========================================================================
   CHROME — a full dock in normal flow, then a fixed-height sticky HUD + ribbon
   ========================================================================== */
#zone-dock{
  margin-bottom:var(--gap);
  scroll-margin-top:calc(var(--chrome-h) + var(--s2));
}
#chrome{
  position:sticky;
  top:var(--cbar-h,0px);
  z-index:43;
  margin:0 0 var(--gap);
}

.panel.dock{
  padding:var(--s3) var(--s4);
  border-radius:var(--r-sm);
}

/* ---------- the compact HUD: HP · Temp HP · AC · turn state ---------- */
.panel.dock-compact{
  min-height:var(--field);
  padding:0 var(--s1);
  border-radius:var(--r-sm) 3px 0 0;
  border-bottom:none;
}
.dock-compact::before{inset:2px}
.compact-vitals{
  position:relative;
  z-index:1;
  display:flex;
  align-items:center;
  min-width:0;
  min-height:var(--field);
  padding-inline:var(--s1);
}
.compact-item{
  display:inline-flex;
  align-items:baseline;
  gap:.28em;
  /* flex:none, never min-width:0 — a squeezed item lets its nowrap text paint
     over its neighbour. The row is DESIGNED to scroll, so items keep their
     size and the container does the giving. */
  flex:none;
  padding-inline:var(--s2);
  white-space:nowrap;
}
.compact-item + .compact-item{border-left:1px solid var(--rule-soft)}

/* RUNNING-HEAD ADDITIONS — Init, Save DC, Slots, Concentration.
   The head scrolls horizontally rather than wrapping: it is sticky, so any
   wrap would steal vertical space from the sheet on every screen. */
.compact-vitals{overflow-x:auto;scrollbar-width:none}
.compact-vitals::-webkit-scrollbar{display:none}
.compact-item--slots{gap:.4em}
.compact-slot{
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:700;
  color:var(--ink);
  white-space:nowrap;
}
.compact-slot small{font-weight:400;color:var(--ink-faint)}
/* A level with nothing left is the thing a caster most needs to SEE, so it is
   struck rather than merely dimmed — legible, but unmistakably spent. */
.compact-slot.is-spent{color:var(--ink-faint);text-decoration:line-through}
.compact-conc{
  display:inline-flex;
  align-items:baseline;
  gap:.28em;
  padding-inline:var(--s2);
  border-left:1px solid var(--rule-soft);
  max-width:14ch;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
  font-family:var(--font-scribal);
  font-style:italic;
  font-size:var(--fs-label);
  color:var(--ward);
}
.compact-item b{
  font-family:var(--font-display);
  font-size:var(--fs-body);
  color:var(--gold-deep);
}
.compact-item b.is-low{color:var(--rubric)}
.compact-item small{
  margin-left:.12em;
  font-size:.62em;
  font-weight:600;
  color:var(--ink-faint);
}
.compact-temp{
  font-family:var(--font-display);
  font-weight:700;
  color:var(--ward);
}
.compact-conditions{
  min-width:0;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
  padding-inline:var(--s2);
  font-family:var(--font-scribal);
  font-size:var(--fs-label);
  font-style:italic;
  color:var(--rubric);
}
.compact-rest,.compact-star{
  flex:none;
  padding-inline:var(--s1);
  color:var(--gold-deep);
}
.compact-star{
  color:var(--ember);
  text-shadow:0 0 8px color-mix(in srgb, var(--gold-hi) 70%, transparent);
}
.compact-jump{
  flex:none;
  display:grid;
  place-items:center;
  width:var(--field);
  height:var(--field);
  margin-left:auto;
  color:var(--gold-deep);
  text-decoration:none;
  font-size:var(--fs-body);
}
.compact-jump:hover{background:color-mix(in srgb, var(--gold-hi) 12%, transparent)}
@media (max-width:620px){
  .compact-conditions{display:none}
}
@media (max-width:380px){
  .compact-item{padding-inline:var(--s1)}
  .compact-spent-word{display:none}
  .compact-rest{display:none}
}

/* ---------- expanded combat controls ---------- */
.dock-body{position:relative}
.dock-grid{display:grid;gap:var(--s4)}
.dock-extras-toggle{
  display:flex;
  align-items:center;
  gap:var(--s2);
  width:100%;
  min-height:var(--field);
  padding:0 var(--s3);
  border:1px solid var(--rule);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  color:var(--ink);
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.1em;
  text-transform:uppercase;
  text-align:left;
  transition:background-color .15s ease,border-color .15s ease;
}
.dock-extras-toggle:hover{border-color:var(--gold-deep);background:color-mix(in srgb, var(--gold-hi) 10%, var(--panel-2))}
.dock-extras-summary{
  margin-left:auto;
  font-family:var(--font-scribal);
  font-size:var(--fs-label);
  font-style:italic;
  font-weight:400;
  letter-spacing:0;
  text-transform:none;
  color:var(--ink-faint);
}
.dock-extras-chev{color:var(--gold-deep);font-size:var(--fs-small);transition:transform .18s ease}
.dock-extras-toggle[aria-expanded="true"] .dock-extras-chev{transform:rotate(90deg)}
@media (max-width:919px){
  .dock-grid:not(.is-open) > .dz-turn,
  .dock-grid:not(.is-open) > .dz-cond,
  .dock-grid:not(.is-open) > .dz-rest{display:none}
}

/* AT 0 HP, DEATH SAVES COME FIRST.
   The vitals zone stacks in DOM order — shield, HP, Temp HP, Inspiration, the
   bar, Damage/Heal, Critical — and the death-save row is appended after all of
   it by renderVitalRows(). Measured on a 375x812 phone, that put the row at
   document-Y 815: three pixels below the fold, at the one moment in the game
   when it is the only thing that matters.
   Scoped to body.is-dying (registry.js:116 toggles it at exactly 0 HP) so the
   normal-play stack is not touched at all. `order` needs a flex/grid parent,
   which is why display flips here and only here. */
body.is-dying .dz-vit{display:flex;flex-direction:column}
body.is-dying .dz-vit > .vrow--alarm{order:-1;margin-bottom:var(--s2)}
@media (min-width:920px){
  .dock-extras-toggle{display:none}
  .dock-grid{
    grid-template-columns:1fr 1.06fr;
    grid-template-areas:
      "vit  turn"
      "cond turn"
      "rest turn";
    align-items:start;
    column-gap:var(--s5);
  }
  .dz-vit{grid-area:vit}
  .dz-turn{grid-area:turn}
  .dz-cond{grid-area:cond}
  .dz-rest{grid-area:rest}
}

/* the headline is one defence shield, dominant HP, a Temp HP capsule, and
   the Heroic Inspiration star — four distinct meanings, four distinct forms */
.dock .hp-figure{gap:var(--s2)}
.dock .ac-badge{width:58px;height:68px}
.dock .ac-badge .ac-num{inset:2px 0 24px}
.dock .ac-badge .ac-label{bottom:12px}
.dock .init-badge{width:52px;height:68px}
.dock .temp-hp-badge{
  position:relative;
  flex:none;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:2px;
  width:132px;
  min-width:132px;
  box-sizing:border-box;
  padding:2px var(--s1);
  border:1px solid var(--ward);
  border-radius:var(--r-pill);
  background:color-mix(in srgb, var(--ward) 8%, var(--panel-2));
  color:var(--ward);
  transition:opacity .2s ease,background-color .2s ease;
}
.dock .temp-hp-badge.is-empty{background:color-mix(in srgb, var(--ward) 3%, var(--panel-2))}
/* Slim to the eye, full-size to the finger: the pill is dieted (Tim: "bloated")
   but the +/− keep the 44px touch floor hud-scroll-verify enforces. */
.dock .temp-hp-controls{display:grid;grid-template-columns:44px minmax(2rem,1fr) 44px;align-items:center;width:100%}
.dock .temp-hp-controls button{min-width:44px;min-height:44px;color:var(--ward);font-size:var(--fs-small);border-radius:50%}
.dock .temp-hp-controls button:hover{background:color-mix(in srgb,var(--ward) 10%,transparent)}
.dock .temp-hp-controls input{
  width:100%;min-width:0;height:22px;padding:0;border:0;background:transparent;color:var(--ward);
  text-align:center;font:700 var(--fs-small)/1 var(--font-display);appearance:textfield
}
.dock .temp-hp-controls input::-webkit-inner-spin-button,.dock .temp-hp-controls input::-webkit-outer-spin-button{appearance:none;margin:0}
.dock .temp-hp-label{color:var(--ward);line-height:1;font-size:var(--fs-micro)}
.dock .insp--headline{
  flex:none;
  width:var(--field);
  height:var(--field);
  border-radius:50%;
  font-size:var(--fs-2xl);
}
@media (max-width:520px){
  .dock .hp-figure{
    display:grid;
    grid-template-columns:auto auto minmax(0,1fr) auto;
    grid-template-areas:"ac init hp insp" "temp temp temp temp";
    justify-items:center;
  }
  .dock .ac-badge{grid-area:ac}
  .dock .init-badge{grid-area:init}
  .dock .hp-nums{grid-area:hp}
  .dock .temp-hp-badge{grid-area:temp;width:min(140px,100%);min-width:min(140px,100%)}
  .dock .insp--headline{grid-area:insp}
}
@media (max-width:360px){
  .dock .hp-figure{gap:var(--s1)}
  .dock .ac-badge{width:48px;height:60px}
  .dock .init-badge{width:44px;height:60px}
  .dock .hp-nums b{font-size:var(--fs-3xl)}
  .dock .hp-nums .maxnum{font-size:var(--fs-lg)}
  .dock .temp-hp-badge{width:min(132px,100%);min-width:min(132px,100%);padding-inline:var(--s1)}
}
.dock-sub{
  display:flex;
  align-items:center;
  gap:.5em;
  margin:0 0 var(--s2);
}
.dock-sub::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--rule-soft),transparent)}

/* ==========================================================================
   INDEX RIBBON — the sticky anchor nav
   ========================================================================== */
.ribbon{
  position:relative;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--panel) 96%, #fff 4%), var(--panel-2));
  border:1px solid var(--rule);
  border-radius:0 0 2px 2px;
  box-shadow:0 6px 14px -10px rgba(50,28,4,.7);
}
.ribbon::before{
  content:"";
  position:absolute; inset:3px;
  border-block:1px solid color-mix(in srgb, var(--rule) 40%, transparent);
  pointer-events:none;
}
.ribbon ul{
  list-style:none;
  margin:0;
  padding:0 var(--s1);
  display:flex;
  gap:var(--s1);
  overflow-x:auto;
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
}
.ribbon ul::-webkit-scrollbar{display:none}
.ribbon li{flex:1 0 auto;display:flex}
.ribbon li + li{border-left:1px solid color-mix(in srgb, var(--rule-soft) 70%, transparent)}
.ribbon a{
  flex:1;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:.45em;
  min-height:var(--field);
  padding:var(--s1) var(--s3);
  text-decoration:none;
  white-space:nowrap;
  font-family:var(--font-display);
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.11em;
  text-transform:uppercase;
  color:var(--ink-faint);
  transition:color .18s ease, background-color .18s ease;
}
.ribbon a::before{
  content:"❦";
  font-family:var(--font-scribal);
  font-size:.8em;
  letter-spacing:0;
  color:var(--gold);
  opacity:0;
  transition:opacity .18s ease;
}
.ribbon a:hover{color:var(--ink)}
.ribbon a[aria-current="location"]{
  color:var(--gold-deep);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--gold-hi) 22%, transparent), transparent 70%);
  box-shadow:inset 0 -2px 0 var(--gold-deep);
}
.ribbon a[aria-current="location"]::before{opacity:1}
/* Inset the focus ring so it stays visible inside the ribbon's overflow clip. */
.ribbon a:focus-visible{outline:2px solid var(--gold-deep);outline-offset:-3px;border-radius:var(--r-sm)}
.ribbon-ico{
  flex:none;
  width:1.15rem;height:1.15rem;
  fill:none;
  stroke:currentColor;
  stroke-width:1.6;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.ribbon-label{display:inline}

/* MOBILE + TABLET — glyph-only rail so every section fits with no horizontal
   scroll. The six uppercase labels only stop overflowing their track at ~860px,
   and below that they scrolled behind a hidden scrollbar (clipping the last
   section with no affordance), so the rail holds through the whole tablet band.
   The label collapses out of layout (aria-label keeps the accessible name);
   links share the width equally and hold a >=44px square tap target. */
@media (max-width:900px){
  .ribbon ul{padding-inline:0;gap:0}
  .ribbon li{flex:1 1 0}
  .ribbon li + li{border-left-color:color-mix(in srgb, var(--rule-soft) 45%, transparent)}
  .ribbon a{
    gap:0;
    padding-inline:var(--s1);
    min-width:44px;
    min-height:var(--field);
  }
  .ribbon-label{
    position:absolute;
    width:1px;height:1px;
    padding:0;margin:-1px;
    overflow:hidden;
    clip:rect(0 0 0 0);
    clip-path:inset(50%);
    white-space:nowrap;
    border:0;
  }
  .ribbon-ico{width:1.4rem;height:1.4rem}
}

/* ==========================================================================
   QUIRES — the reference stacks
   ========================================================================== */
.quire{
  display:grid;
  gap:var(--gap);
  margin-bottom:var(--gap);
  scroll-margin-top:calc(var(--chrome-h) + 6px);
}

/* gear's two-column split on wide screens */
.gear-grid{display:grid;gap:var(--s3) var(--s5)}
@media (min-width:720px){.gear-grid{grid-template-columns:1fr 1fr}}
.gear-full{grid-column:1 / -1}
