/* ============================================================
   SERF — Royal Steward theme
   Dark, warm, regal. Brass/gold hero. Parchment for trust.
   ============================================================ */

:root {
  /* grounds */
  --ink:       #100F0B;
  --ground:    #1A1813;
  --ground-2:  #232017;
  --ground-3:  #2C2819;
  --ground-hi: #36311F;

  /* hairlines */
  --line:        rgba(203,163,92,0.16);
  --line-strong: rgba(203,163,92,0.34);
  --line-cream:  rgba(236,226,204,0.10);

  /* brass / gold — the hero */
  --gold:      #CBA35C;
  --gold-hi:   #ECCE85;
  --gold-lo:   #9C7B34;
  --gold-deep: #6E5621;
  --gold-soft: rgba(203,163,92,0.12);
  --gold-glow: rgba(203,163,92,0.22);

  /* parchment — trust surfaces */
  --parchment:    #F2E7CE;
  --parchment-2:  #E7D6B2;
  --parchment-ln: rgba(43,36,23,0.14);
  --ink-on-parch: #2B2417;
  --ink-on-parch-dim: #6A5C3E;

  /* text on dark */
  --cream:     #ECE2CC;
  --cream-dim: #B3A98E;
  --cream-mut: #9A9079;

  /* signals — warm sage success (Norse cues) */
  --pine:      #8C9A63;
  --pine-bg:   rgba(140,154,99,0.15);
  --pine-deep: #44502A;
  --success-ink:  #5C6B30;
  --success-bg:   rgba(124,138,74,0.13);
  --success-line: rgba(124,138,74,0.32);
  --blood:     #B0413A;
  --blood-bg:  rgba(176,65,58,0.13);

  /* iron — the NEUTRAL/INFO signal (provisioning, waiting, asleep).
     Keeps in-progress states from defaulting to gold and diluting it. */
  --iron:      #6E6857;
  --iron-hi:   #A9A28F;
  --iron-bg:   rgba(154,148,134,0.11);
  --iron-line: rgba(154,148,134,0.30);

  /* shape */
  --r-sm: 6px;
  /* The largest icon any button may contain (components/brand/Icons.vue — currently `menu`
     at 20px). Buttons pin their line box to this, so a text-only button is exactly as tall
     as an icon'd one. Add a bigger icon and you must raise this — geometry/button-height.pw.ts
     fails otherwise. */
  --icon-size: 20px;
  --r:    10px;
  --r-lg: 16px;
  --r-xl: 22px;

  --shadow-card: 0 1px 0 rgba(236,226,204,0.04) inset, 0 18px 40px -24px rgba(0,0,0,0.7);
  --shadow-parch: 0 2px 1px rgba(255,255,255,0.4) inset, 0 22px 48px -26px rgba(0,0,0,0.65);
  --shadow-gold: 0 10px 28px -12px rgba(203,163,92,0.45);

  /* fonts */
  --display: "Cinzel", "Cormorant Garamond", serif;
  --serif:   "Cormorant Garamond", Georgia, serif;
  --sans:    "Hanken Grotesk", system-ui, -apple-system, sans-serif;

  --gold-metal: linear-gradient(150deg, #F0D699 0%, #CBA35C 38%, #A37E37 70%, #D8B36A 100%);
  --gold-rule:  linear-gradient(90deg, transparent, var(--gold-lo) 18%, var(--gold-hi) 50%, var(--gold-lo) 82%, transparent);
}

/* ---- Norse-feudal palette tweak ---- */
[data-palette="norse"] {
  --ink:       #0A0F0B;
  --ground:    #121A13;
  --ground-2:  #19241A;
  --ground-3:  #1F2D1F;
  --ground-hi: #283827;
  --line:        rgba(203,163,92,0.18);
  --line-strong: rgba(203,163,92,0.36);
  --line-cream:  rgba(220,228,206,0.09);
  --pine:      #93A566;
  --pine-bg:   rgba(147,165,102,0.17);
  --pine-deep: #424E27;
  --cream:     #E7E6D0;
  --cream-dim: #A6AE8E;
  --cream-mut: #71805C;
  --blood:     #BE3D33;
  --blood-bg:  rgba(190,61,51,0.16);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--sans);
  background: var(--ink);
  color: var(--cream);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
#root { min-height: 100vh; }

/* ambient warmth */
.app-bg {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(1100px 620px at 78% -8%, rgba(203,163,92,0.10), transparent 60%),
    radial-gradient(900px 700px at 8% 108%, rgba(110,154,111,0.06), transparent 60%),
    var(--ink);
}

/* ============================================================
   TYPE
   ============================================================ */
.display { font-family: var(--display); font-weight: 600; letter-spacing: 0.01em; line-height: 1.04; }
.proclaim { font-family: var(--display); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; }
.serif { font-family: var(--serif); }
.eyebrow {
  font-family: var(--display); font-weight: 600;
  font-size: 12px; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--gold); display: inline-flex; align-items: center; gap: 10px;
  white-space: nowrap; /* a proclamation never breaks mid-line */
  /* An inline-flex sizes to max-content, so its items are never under pressure and
     flex-shrink never fires — the box just overhangs its parent, and being centred it did
     so at BOTH ends ("/court" lost 5px a side at 360). Capping the container is what
     creates the pressure; the flanking rules then give way and the label stays whole.
     Constrain the container, not the items: `flex: 0 1 26px` on the rules collapsed them
     to 0px at every width, silently deleting them from the design. */
  max-width: 100%;
}
.eyebrow::before, .eyebrow.flank::after {
  content: ""; width: 26px; min-width: 0; height: 1px; background: var(--gold-rule); opacity: .7;
}
.text-gold { color: var(--gold); }
.text-cream { color: var(--cream); }
.text-dim { color: var(--cream-dim); }
.text-mut { color: var(--cream-mut); }
.steward {
  font-family: var(--serif); font-style: italic; font-size: 19px;
  color: var(--cream-dim); line-height: 1.45;
}
.tnum { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* gold foil text — biased light so the darkest stop clears the contrast floor on --ink */
.foil {
  background: linear-gradient(176deg, #F7E4AC 8%, #D9B472 46%, #C69B55 64%, #F0D69A 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ============================================================
   RULES / DIVIDERS
   ============================================================ */
.rule { height: 1px; background: var(--gold-rule); opacity: .5; border: 0; }
.rule-lozenge {
  display: flex; align-items: center; gap: 14px; color: var(--gold-lo);
}
.rule-lozenge::before, .rule-lozenge::after {
  content: ""; flex: 1; height: 1px; background: var(--gold-rule); opacity: .45;
}
.lozenge {
  width: 7px; height: 7px; transform: rotate(45deg);
  background: var(--gold); box-shadow: 0 0 0 3px var(--gold-soft);
}

/* ============================================================
   WAX SEAL / LOGO
   The mark itself lives in components/brand/Seal.vue — there is no
   CSS-drawn seal any more.
   ============================================================ */
.wordmark {
  font-family: var(--display); font-weight: 600;
  letter-spacing: 0.20em; text-transform: lowercase;
  color: var(--cream); font-size: 19px;
}

/* ============================================================
   COIN
   ============================================================ */
.coin {
  position: relative; border-radius: 50%; display: inline-grid; place-items: center;
  background: #14120C; border: 0.32em solid var(--gold);
  color: var(--gold-hi); font-family: var(--display); font-weight: 700;
  box-shadow: 0 0 0 1px var(--gold-deep), 0 6px 14px -6px rgba(0,0,0,0.6);
  /* A coin is a fixed-size disc. As a flex item it defaults to flex-shrink:1, so a
     wide sibling (a big treasury figure, a long line of copy) squeezes it into an
     oval. Pin it so it keeps its circle in any content-area flex/grid row — same
     guard .avatar already carries. aspect-ratio backstops the preset-less case. */
  flex: none; aspect-ratio: 1;
}
.coin::after {
  content: ""; position: absolute; inset: 7%; border-radius: 50%;
  border: 1.5px solid rgba(203,163,92,0.55);
}
.coin.c-64 { width: 64px; height: 64px; font-size: 22px; }
.coin.c-48 { width: 48px; height: 48px; font-size: 17px; }
.coin.c-28 { width: 28px; height: 28px; font-size: 12px; }
.coin-stack { position: relative; }
.coin-stack > .coin { position: absolute; }

/* ============================================================
   BUTTONS
   ============================================================ */
.btn {
  font-family: var(--sans); font-weight: 600; font-size: 15px;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 13px 22px; border-radius: var(--r); border: 1px solid transparent;
  cursor: pointer; transition: transform var(--m-fast) ease, box-shadow var(--m-quick) ease, background var(--m-quick) ease, border-color var(--m-quick) ease;
  white-space: nowrap; text-decoration: none;
  /* A button is as tall as its tallest child. With line-height:1 a text-only button
     (Hibernate, Restart, Reinstall, Apply settings, Cancel) was ~5.5px shorter than an
     icon'd neighbour (Export World, Summon), because the 19px Icons svg outgrows the
     text line box. Pin the line box to the icon height so every button in a row lines
     up, with or without an icon — at every size variant. */
  line-height: var(--icon-size);
}
.btn:active { transform: translateY(1px); }
@media (hover: hover) { .btn:hover:not(:active) { transform: translateY(-1px); } }
.btn-gold {
  background: var(--gold-metal); color: #3C2E0C;
  background-clip: padding-box; background-origin: border-box;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.45), var(--shadow-gold);
  border-color: var(--gold-deep);
  font-weight: 700;
}
.btn-gold:hover { box-shadow: inset 0 1px 0 rgba(255,255,255,0.55), 0 14px 32px -10px rgba(203,163,92,0.6); }
.btn-ghost {
  background: transparent; color: var(--cream);
  border-color: var(--line-strong);
}
.btn-ghost:hover { background: var(--gold-soft); border-color: var(--gold); color: var(--gold-hi); }
.btn-quiet {
  background: var(--ground-2); color: var(--cream-dim); border-color: var(--line);
}
.btn-quiet:hover { color: var(--cream); border-color: var(--line-strong); background: var(--ground-3); }
.btn-danger {
  background: transparent; color: var(--blood);
  border-color: rgba(176,65,58,0.5);
}
.btn-danger:hover { background: var(--blood-bg); border-color: var(--blood); }
.btn-sm { padding: 9px 15px; font-size: 13.5px; border-radius: var(--r-sm); }
.btn-lg { padding: 16px 28px; font-size: 16.5px; }
.btn-block { width: 100%; }

/* parchment-context button */
.on-parch .btn-ghost { color: var(--ink-on-parch); border-color: var(--parchment-ln); }
.on-parch .btn-ghost:hover { background: rgba(43,36,23,0.06); border-color: var(--gold-lo); color: var(--gold-deep); }

/* ============================================================
   CARDS / PANELS
   ============================================================ */
.panel {
  background: linear-gradient(180deg, var(--ground-2), var(--ground));
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}
.panel-pad { padding: 24px; }
.panel-edge { position: relative; }
.panel-edge::before {
  content: ""; position: absolute; left: 18px; right: 18px; top: 0; height: 1px;
  background: var(--gold-rule); opacity: .5;
}

/* parchment card — trust surface */
.parch {
  position: relative;
  background:
    radial-gradient(120% 140% at 50% -20%, rgba(255,255,255,0.5), transparent 50%),
    linear-gradient(180deg, var(--parchment), var(--parchment-2));
  color: var(--ink-on-parch);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-parch);
  border: 1px solid rgba(67,52,15,0.18);
}
.parch::after {
  content: ""; position: absolute; inset: 6px; border-radius: 11px;
  border: 1px solid rgba(67,52,15,0.16); pointer-events: none;
}
.parch.on-parch { /* marker for nested button styling */ }
.parch .text-dim2 { color: var(--ink-on-parch-dim); }
.parch .hr { height: 1px; background: var(--parchment-ln); border: 0; }

/* chips / pills */
.pill {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.02em;
  padding: 5px 11px; border-radius: 999px; border: 1px solid var(--line);
  color: var(--cream-dim); background: var(--ground-2);
}
.pill .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.pill-online { color: var(--pine); background: var(--pine-bg); border-color: var(--success-line); }
/* Occupied vs empty: an online realm with people in it must not look like an empty one.
   The count rides in a bold badge; an empty pill keeps the green but speaks quietly. */
.pill-occupied { border-color: var(--pine); }
.pill .pill-count {
  font-weight: 800; font-size: 11.5px; letter-spacing: 0.02em;
  color: var(--cream); background: rgba(140, 154, 99, 0.28);
  padding: 1px 8px; border-radius: 999px;
}
.pill-empty { opacity: 0.72; }
.pill-asleep { color: var(--cream-mut); background: var(--ground-3); border-color: var(--line); }
.pill-gold { color: var(--gold-hi); background: var(--gold-soft); border-color: var(--line-strong); }
.pill-danger { color: var(--blood); background: var(--blood-bg); border-color: var(--blood); }
.pill-info { color: var(--iron-hi); background: var(--iron-bg); border-color: var(--iron-line); }

/* Realm status timeline (M1-B): status-derived stepper on the active server card */
.server-timeline { padding: 16px 24px; border-top: 1px solid var(--line); }
.timeline { list-style: none; display: flex; flex-wrap: wrap; gap: 10px 20px; margin: 0; padding: 0; }
.timeline li { position: relative; padding-left: 20px; font-size: 13px; color: var(--cream-mut); }
.timeline li::before {
  content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid var(--line-strong); background: var(--ground-3);
}
.timeline li.done { color: var(--cream-dim); }
.timeline li.done::before { background: var(--pine); border-color: var(--success-line); }
.timeline li.current { color: var(--gold-hi); animation: timeline-label 1.8s ease-in-out infinite; }
.timeline li.current::before {
  background: var(--gold); border-color: var(--gold-hi);
  animation: timeline-pulse 1.8s ease-out infinite;
}
@keyframes timeline-pulse {
  0%   { box-shadow: 0 0 0 1px var(--gold-soft); }
  70%  { box-shadow: 0 0 0 8px rgba(203,163,92,0); }
  100% { box-shadow: 0 0 0 1px var(--gold-soft); }
}
@keyframes timeline-label { 0%, 100% { opacity: 1; } 50% { opacity: 0.62; } }

.nowrap { white-space: nowrap; }
.tag-live {
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  font-family: var(--sans); font-weight: 600; font-size: 12.5px; letter-spacing: .02em;
  color: var(--pine); background: var(--pine-bg);
  border: 1px solid var(--success-line); border-radius: 999px; padding: 6px 13px;
}
/* The "live" dot is a plain dot. It used to carry a pulse ring; ENG-152 took it off.
   Measured on the shipped page, that one 8px decoration cost ~10 points of a CPU core —
   a third of the landing page's 30%, and MORE than the entire WebGL atmosphere layer at
   9.2. Neither `will-change` nor `content-visibility` moved it (-0.3 / -0.7 pts), because
   it is already transform+opacity on a pseudo-element and something in the ancestry is
   refusing it a compositor layer anyway. The tag reads as live without it: it is a green
   dot next to the word "live". */
.tag-live .blip { width: 8px; height: 8px; border-radius: 50%; background: var(--pine); }

/* Pulse ring — the expanding halo, kept ONLY for transient progress states.
   `.raise-blip` marks work actually in flight (the summon ceremony's active step, and a
   realm thawing from deep sleep), where the motion means something and lives for seconds
   rather than for as long as the page is open. That is the distinction: this is not too
   expensive to use, it was too expensive to leave running forever on a marketing page.

   This used to animate box-shadow spread. box-shadow is a PAINT property: it cannot run
   on the compositor, so every frame repainted, and it measured 31 of the page's 47 points
   of CPU. A scaled pseudo-element is transform + opacity only. Any element wanting the
   halo sets position:relative and gives ::after a background and an animation-duration. */
.raise-blip::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  /* Base state is invisible and the keyframes light it up. That is what makes
     prefers-reduced-motion correct for free: the global reduce rule collapses
     duration without a fill-mode, so the element falls back to THIS state. Give
     it a visible base and reduced-motion users get a solid tinted disc welded
     over the dot forever. */
  opacity: 0;
  animation-name: blipRing; animation-iteration-count: infinite;
  animation-timing-function: ease-out;
}
@keyframes blipRing {
  0%   { transform: scale(1);   opacity: .55; }
  70%  { transform: scale(2.7); opacity: 0; }
  100% { transform: scale(2.7); opacity: 0; }
}

/* ============================================================
   LAYOUT HELPERS
   ============================================================ */
.row { display: flex; align-items: center; }
.col { display: flex; flex-direction: column; }
.gap-6{gap:6px}.gap-8{gap:8px}.gap-10{gap:10px}.gap-12{gap:12px}.gap-14{gap:14px}
.gap-16{gap:16px}.gap-20{gap:20px}.gap-24{gap:24px}.gap-32{gap:32px}.gap-40{gap:40px}
.between { justify-content: space-between; }
.center { align-items: center; }
.wrap { flex-wrap: wrap; }
.grow { flex: 1; }

/* ============================================================
   APP SHELL
   ============================================================ */
.shell { position: relative; z-index: 1; display: grid; grid-template-columns: 252px 1fr; min-height: 100vh; }
.sidebar {
  border-right: 1px solid var(--line);
  background: linear-gradient(180deg, var(--ground), var(--ink));
  padding: 22px 18px; display: flex; flex-direction: column; gap: 8px;
  position: sticky; top: 0; height: 100vh;
}
.side-brand { display: flex; align-items: center; gap: 12px; padding: 6px 8px 16px; }
.side-court {
  margin: 0 6px 14px; padding: 12px 14px; border-radius: var(--r);
  background: var(--ground-2); border: 1px solid var(--line);
}
.navlink {
  display: flex; align-items: center; gap: 13px; padding: 11px 14px;
  border-radius: var(--r); color: var(--cream-dim); font-weight: 600; font-size: 14.5px;
  cursor: pointer; border: 1px solid transparent; transition: all .15s ease; position: relative; white-space: nowrap;
}
.navlink .ic { width: 19px; height: 19px; opacity: .8; flex: none; }
.navlink:hover { color: var(--cream); background: var(--ground-2); }
.navlink.active { color: var(--gold-hi); background: var(--gold-soft); border-color: var(--line-strong); }
.navlink.active::before {
  content:""; position:absolute; left:-18px; top:9px; bottom:9px; width:3px;
  background: var(--gold-metal); border-radius: 0 3px 3px 0;
}
.nav-section { font-family: var(--display); font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--cream-mut); padding: 14px 14px 7px; }
.side-legal {
  margin: 6px 14px 0; display: flex; align-items: center; gap: 7px;
  color: var(--cream-mut); font-size: 12px;
}
.side-legal a { color: inherit; text-decoration: none; }
.side-legal a:hover { color: var(--cream); }

.main { position: relative; z-index: 1; min-width: 0; }
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 20px 40px; border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 5;
  background: color-mix(in srgb, var(--ink) 82%, transparent); backdrop-filter: blur(10px);
}
.page { padding: 36px 40px 56px; max-width: 1080px; }
.page-head { margin-bottom: 28px; }
.page-title { font-family: var(--display); font-weight: 600; font-size: 34px; color: var(--cream); letter-spacing: .02em; }

/* ============================================================
   MARKETING / LANDING
   ============================================================ */
.mk { position: relative; z-index: 1; }
/* Header height, as its PARTS rather than a magic 90px, because .hero-art has to
   pull itself up by exactly this much (see .hero-art) and the two must not drift.
   The 46px is Seal's `size` prop in MkHeader.vue — the one term that lives in the
   component, not here. Change that and change this. */
.marketing { --mk-head-pad: 22px; --mk-head-h: calc(46px + 2 * var(--mk-head-pad)); }
.mk-nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--mk-head-pad) 48px; max-width: 1280px; margin: 0 auto;
  /* Sit above the hero photo so it doesn't paint over — and dim — the menu.
     Must beat .mk, not .hero-art: .mk is itself positioned at z-index 1, which
     makes it a stacking context, so .hero-art's z-index:0 is sealed INSIDE it and
     the whole .mk block competes here as one. At an equal z-index .mk would win
     on source order (the header is markup-earlier), so this has to be 2. */
  position: relative; z-index: 2;
}
.mk-nav-links { display: flex; gap: 30px; align-items: center; }
.mk-nav-links a { color: var(--cream-dim); text-decoration: none; font-weight: 600; font-size: 14.5px; transition: color .15s; white-space: nowrap; cursor: pointer; }
.mk-nav-links a:hover { color: var(--gold-hi); }
.x-btn.mk-menu-btn { display: none; }
.mk-menu-scrim {
  position: fixed; inset: 0; z-index: 80; background: rgba(8,7,5,0.6);
  backdrop-filter: blur(4px); animation: fadeIn var(--m-quick) ease;
}
.mk-menu {
  position: absolute; top: 72px; left: 16px; right: 16px;
  display: flex; flex-direction: column;
  background: linear-gradient(180deg, #232017, #1A1813);
  border: 1px solid var(--line-strong); border-radius: var(--r-lg);
  box-shadow: 0 30px 80px rgba(0,0,0,0.6); padding: 6px 0;
  animation: fadeUp var(--m-move) var(--e-settle);
}
.mk-menu-link {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 15px 20px; font-weight: 600; font-size: 16px; color: var(--cream);
  cursor: pointer; text-decoration: none; border-bottom: 1px solid var(--line);
}
.mk-menu-link:last-child { border-bottom: 0; }
.mk-menu-link:hover { color: var(--gold-hi); }
.mk-menu-link.gold { color: var(--gold-hi); }
.mk-wrap { max-width: 1280px; margin: 0 auto; padding: 0 48px; }

/* same reason as .mk-nav: sit above .hero-art so the decorative photo doesn't
   paint over — and dim — the headline, sub-copy and Treasury card */
.hero { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 56px; align-items: center; padding: 64px 0 72px; position: relative; z-index: 1; }
.hero h1 { font-family: var(--display); font-weight: 700; font-size: clamp(38px, 5.4vw, 60px); line-height: 1.04; margin: 18px 0 0; color: var(--cream); letter-spacing: .01em; text-wrap: balance; }
.hero-sub { font-size: 19px; line-height: 1.55; color: var(--cream-dim); max-width: 30em; margin-top: 22px; }
.hero-cta { display: flex; gap: 14px; margin-top: 30px; align-items: center; flex-wrap: wrap; }
.hero-trust { display: flex; gap: 22px; margin-top: 26px; color: var(--cream-mut); font-size: 13.5px; flex-wrap: wrap; }
.hero-trust span { display: inline-flex; gap: 8px; align-items: center; white-space: nowrap; }

.vp-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; padding: 14px 0 80px; }
.vp-lead { grid-column: span 1; }
.vp-card { padding: 30px; min-height: 230px; display: flex; flex-direction: column; }
.vp-card.table-stakes { min-height: 0; padding: 22px 24px; }
.vp-num { font-family: var(--display); font-size: 13px; letter-spacing: .2em; color: var(--gold); }
.vp-card h3 { font-family: var(--display); font-weight: 600; font-size: 23px; margin: 14px 0 10px; color: var(--cream); }
.vp-card p { color: var(--cream-dim); line-height: 1.55; font-size: 15px; margin: 0; }
.stakes-row { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }

/* Positioned for the same reason as .mk: the landing page's .app-bg is a FIXED,
   opaque, full-viewport layer at z-index 0, so anything static paints beneath it.
   The footer used to live inside .mk (which carries z-index:1) and rode its
   stacking context for free; ENG-101 lifted it into the shared layout as a
   sibling, and it has painted under .app-bg on / ever since. */
.mk-foot { position: relative; z-index: 1; border-top: 1px solid var(--line); margin-top: 20px; }
.mk-foot-in { max-width: 1280px; margin: 0 auto; padding: 30px 48px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 18px; }
.mk-foot-in a, .mk-foot-in span { white-space: nowrap; }
/* The footer's own rows must wrap. `.row` is a global utility with no flex-wrap, and every
   child here is `white-space: nowrap`, so the link row held its 545px max-content width and
   dragged the whole document sideways on every phone — 185px over at 360.
   `max-width: 100%` is the load-bearing half: below 560px `.mk-foot-in` turns into a column
   with `align-items: flex-start`, which sizes its children to max-content, and flex-wrap
   alone never fires because the row is never the thing being constrained. Scoped here on
   purpose — `.row` is used app-wide and call sites depend on it staying one line. */
.mk-foot-in .row { flex-wrap: wrap; max-width: 100%; row-gap: 10px; }
.mk-foot-in .sep { color: var(--cream-mut); opacity: .55; }

/* ledger rows */
.ledger { display: flex; flex-direction: column; }
.ledger-row {
  display: grid; grid-template-columns: 28px 1fr auto; gap: 14px; align-items: center;
  padding: 14px 4px; border-bottom: 1px solid var(--parchment-ln);
}
.ledger-row:last-child { border-bottom: 0; }
.ledger-ic { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; }
.amt-pos { color: var(--success-ink); font-weight: 700; }
.amt-neg { color: var(--ink-on-parch); font-weight: 700; }

/* contributors */
.avatar {
  position: relative; width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--display); font-weight: 700; font-size: 15px; color: var(--gold-hi);
  background: #14120C; border: 0.27em solid var(--gold);
  box-shadow: 0 0 0 1px var(--gold-deep);
  flex: none;
}
.avatar::after { content: ""; position: absolute; inset: 7%; border-radius: 50%; border: 1.5px solid rgba(203,163,92,0.5); }
.avatar.av-pine { background: #101812; border-color: #6FA077; color: #B7DDBB; box-shadow: 0 0 0 1px var(--pine-deep); }
.avatar.av-pine::after { border-color: rgba(111,160,119,0.5); }
.avatar.av-iron { background: #131210; border-color: #8D8778; color: #CFC9B8; box-shadow: 0 0 0 1px #3a3528; }
.avatar.av-iron::after { border-color: rgba(141,135,120,0.5); }

.copybox {
  display: flex; align-items: center; gap: 10px; padding: 6px 6px 6px 16px;
  border-radius: var(--r); border: 1px dashed var(--gold-lo); background: rgba(43,36,23,0.04);
  min-width: 0; max-width: 100%;
}
.copybox code { font-family: var(--sans); font-weight: 600; color: var(--ink-on-parch); font-size: 15px; white-space: nowrap; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* meter / progress */
.meter { height: 12px; border-radius: 999px; background: rgba(43,36,23,0.14); overflow: hidden; position: relative; }
.meter > span { position: absolute; inset: 0 auto 0 0; background: var(--gold-metal); border-radius: 999px; box-shadow: inset 0 1px 0 rgba(255,255,255,.5); }
/* dark-surface variant: a meter sitting on the app's ink ground rather than parchment */
.meter.on-ink { background: rgba(236,206,133,0.09); box-shadow: inset 0 0 0 1px var(--line); }

/* stat block */
.stat-lg { font-family: var(--sans); font-weight: 800; font-size: 52px; letter-spacing: -0.01em; line-height: 1; }
.stat-md { font-family: var(--sans); font-weight: 800; font-size: 30px; line-height: 1; }
.label { font-size: 12.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--cream-mut); }
.parch .label { color: var(--ink-on-parch-dim); }

/* coin pack cards */
.pack {
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: 22px; background: var(--ground-2);
  cursor: pointer; transition: all .15s ease; position: relative; text-align: center;
}
.pack:hover { border-color: var(--line-strong); background: var(--ground-3); transform: translateY(-2px); }
.pack.featured { border-color: var(--gold); box-shadow: var(--shadow-gold); background: linear-gradient(180deg,var(--ground-3),var(--ground-2)); }
.pack-best { position: absolute; top: -11px; left: 50%; transform: translateX(-50%);
  font-family: var(--display); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase;
  background: var(--gold-metal); color: #3C2E0C; padding: 4px 12px; border-radius: 999px; font-weight: 700; }

/* server card */
.server-card { padding: 0; overflow: hidden; position: relative; }
/* The realm's accent spine — one of six tones hashed from the realm's id (src/realm/identity.ts),
   so a stack of same-game realms is tellable apart at a glance and not by name alone. Clipped
   to the card's radius by the overflow above. */
.server-card::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; z-index: 2;
  background: var(--realm-accent, transparent); pointer-events: none;
}
/* the game's cover art, as the card's header strip */
.card-banner {
  position: relative; height: 132px; overflow: hidden;
  background: linear-gradient(150deg, var(--ground-3), var(--ground-2));
}
.card-banner-art { position: absolute; inset: 0; background: center / cover no-repeat; }
/* Two washes: the neutral fade that carries the art down into the panel, and the realm's own
   tint over it. The bottom stop must be --ground-2 (the panel's colour) or the strip ends in
   a visible seam. */
.card-banner-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, transparent 28%, var(--realm-wash, transparent) 100%),
    linear-gradient(180deg, rgba(16,15,11,0.10) 0%, rgba(16,15,11,0.50) 56%, var(--ground-2) 100%);
}
/* The house rides the banner as a chip. It used to sit stacked ABOVE the realm name inside
   the head's text column, which meant the column's height changed depending on whether a
   realm had a house — and it was centred against a fixed-height emblem, so the title never
   landed in the same place twice. Off the column, the head aligns identically every time. */
.card-house {
  position: absolute; top: 13px; right: 15px; z-index: 1;
  display: flex; align-items: center; gap: 8px; max-width: calc(100% - 30px);
  padding: 6px 13px 6px 9px; border-radius: 999px;
  border: 1px solid var(--line); background: rgba(16,15,11,0.62); backdrop-filter: blur(7px);
}
.card-house .display {
  font-size: 13.5px; color: var(--cream);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.server-head { padding: 22px 24px; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
/* align-self pins the block to the head's top, so it does not drift with however tall the
   connect box happens to be; align-items centres the seal against the title block beside it. */
.head-identity { align-self: flex-start; align-items: center; min-width: 0; }
.head-titles { min-width: 0; }
/* The realm name, status pill and wake attribution. MUST wrap: the pill's text is nowrap,
   so on a phone it was pushed past the card's right edge and cut off by overflow:hidden —
   the same bug as .server-actions, one row up. */
.head-titlerow { flex-wrap: wrap; row-gap: 8px; min-width: 0; }
/* The seal sits beside the title, NOT hanging up into the banner. It used to carry a -34px
   margin, which failed twice over: .card-banner is position:relative and its scrim
   position:absolute, so both painted above the static seal and the overlap was simply
   invisible — and the seal's centre ended up 21.5px above the realm name's. A 56px seal
   centred on the title block clears the banner edge by ~22px, so the two cannot be had at
   once; lining it up with the title it marks is the one that matters.
   The seal is now a 48×56 sigil frame (roundel or banner), so a 56px seal is 65px tall —
   still short of the banner edge, and still centred on the title block. The radius is only
   here for .emblem-bank's `border-radius: inherit` glow. */
.card-seal { display: block; border-radius: 50%; flex: none; }
/* ---- house realm card (both house-realm lists) ----------------------------------------
   The compact sibling of .server-card: same accent spine and art-strip language, sized for
   a list. The seal sits BESIDE the body, never overlapping the strip — .hrcard-strip is
   position:relative and its scrim absolute, so an overlapping static seal would be painted
   over exactly as .card-seal was before PR #185. */
.hrcard {
  position: relative; overflow: hidden; border-radius: var(--r-lg);
  border: 1px solid var(--line); background: var(--ground-2); margin-bottom: 14px;
}
.hrcard::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; z-index: 2;
  background: var(--realm-accent, transparent); pointer-events: none;
}
.hrcard-strip {
  position: relative; height: 64px; overflow: hidden;
  background: linear-gradient(150deg, var(--ground-3), var(--ground-2));
}
.hrcard-art { position: absolute; inset: 0; background: center / cover no-repeat; }
.hrcard-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, transparent 20%, var(--realm-wash, transparent) 100%),
    linear-gradient(180deg, rgba(16,15,11,0.15) 0%, rgba(16,15,11,0.50) 60%, var(--ground-2) 100%);
}
.hrcard-house {
  position: absolute; top: 9px; right: 11px; z-index: 1;
  display: flex; align-items: center; gap: 7px; max-width: calc(100% - 22px);
  padding: 4px 10px 4px 7px; border-radius: 999px;
  border: 1px solid var(--line); background: rgba(16,15,11,0.62); backdrop-filter: blur(7px);
}
/* The hearth is cold: a short strip, and the whole card grayed out — colour is what says
   LIVE in a mixed list (the accent vars are swapped to iron-gray by the card itself). */
.hrcard-rest .hrcard-strip { height: 28px; }
.hrcard-rest .hrcard-art { filter: grayscale(1) brightness(0.55); }
.hrcard-rest .hrcard-house { top: 50%; transform: translateY(-50%); padding: 2px 9px 2px 6px; }
.hrcard-rest .hrcard-seal { filter: grayscale(1); opacity: 0.55; }
.hrcard-rest .hrcard-name { color: var(--cream-mut); }
.hrcard-seal { display: inline-flex; flex: none; }
.hrcard-body { display: flex; align-items: center; gap: 14px; padding: 14px 18px; flex-wrap: wrap; }
.hrcard-titles { min-width: 0; flex: 1 1 220px; }
.hrcard-name {
  font-weight: 700; font-size: 15.5px; color: var(--cream);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hrcard-sub { margin-top: 3px; font-size: 12.5px; color: var(--cream-mut); }
/* MUST wrap: the pills carry nowrap text, and a nowrap action row is what clipped buttons
   off .server-actions and .head-titlerow before. */
.hrcard-actions {
  display: flex; align-items: center; gap: 8px; margin-left: auto; flex-wrap: wrap; row-gap: 8px;
}
.hrcard-extra { padding: 0 18px 14px; }
.hrcard-chev { display: inline-flex; transition: transform .15s; }
.hrcard-chev.open { transform: rotate(90deg); }
@media (max-width: 560px) {
  .hrcard-actions { margin-left: 0; width: 100%; }
}
.server-emblem {
  width: 54px; height: 54px; border-radius: 13px; display: grid; place-items: center; flex: none;
  background: linear-gradient(160deg, var(--pine-deep), #1a2a1f); border: 1px solid rgba(110,154,111,0.3);
  font-family: var(--display); font-weight: 700; color: var(--pine); font-size: 22px;
}
/* GameEmblem — the realm's cover art (marketing roster) inside the emblem box; the inner
   layer carries the image so the box keeps its border/radius and its lettered fallback. */
.game-emblem.has-art { background: var(--ground-2); border-color: rgba(255,255,255,0.08); overflow: hidden; }
.game-emblem-art { display: block; width: 100%; height: 100%; background: center / cover no-repeat; }
/* realms past — the hearth is cold, so the cover art rests muted */
.emblem-rest { background: var(--ground-3); border-color: var(--line); color: var(--cream-dim); }
.emblem-rest .game-emblem-art { filter: saturate(.55) brightness(.82); }
.server-stats { display: grid; grid-template-columns: repeat(4,1fr); border-top: 1px solid var(--line); }
.server-stat { padding: 16px 24px; border-right: 1px solid var(--line); }
.server-stat:last-child { border-right: 0; }
/* Wrapping is NOT a mobile concern: .btn is white-space:nowrap, and five of them plus the
   Advanced toggle need ~1150px. Below that — a laptop at 1024, a half-screen window, the
   sidebar eating 252px — a nowrap row overflowed and .server-card's overflow:hidden silently
   CLIPPED the buttons off. Wrap at every width; the ≤860px block only re-homes the toggle. */
.server-actions { padding: 18px 24px; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* disclosure */
.adv { margin-top: 12px; border-top: 1px solid var(--line); }
.adv-toggle { display: flex; align-items: center; gap: 10px; padding: 14px 4px; color: var(--cream-mut);
  font-family: inherit; font-weight: 600; font-size: 14px; cursor: pointer; background: none; border: 0; text-align: left; }
.adv-toggle:hover { color: var(--cream-dim); }

a { color: var(--gold-hi); }

/* ============================================================
   SUMMON FLOW (modal)
   ============================================================ */
.scrim {
  position: fixed; inset: 0; z-index: 100; padding: 28px;
  background: rgba(8,7,5,0.66); backdrop-filter: blur(7px);
  display: grid; place-items: center;
  animation: fadeIn var(--m-quick) ease;
}
.modal {
  width: min(660px, 100%); max-height: 92vh; overflow: auto;
  background: linear-gradient(180deg, var(--ground-2), var(--ground));
  border: 1px solid var(--line-strong); border-radius: var(--r-xl);
  box-shadow: 0 40px 100px -30px rgba(0,0,0,0.8), 0 0 0 1px rgba(0,0,0,0.4);
  animation: modalIn var(--m-move) var(--e-settle);
}
@keyframes modalIn { from { opacity: 0; transform: translateY(14px) scale(.98); } }
.modal-head { padding: 24px 28px 0; display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.modal-body { padding: 22px 28px; }
.modal-foot { padding: 18px 28px 24px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border-top: 1px solid var(--line); margin-top: 4px; }
.x-btn { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--line); background: var(--ground-2); color: var(--cream-dim); display: grid; place-items: center; cursor: pointer; flex: none; transition: all .15s; }
.x-btn:hover { color: var(--cream); border-color: var(--line-strong); }

.steps { display: flex; align-items: center; gap: 9px; }
.step-pip { width: 26px; height: 4px; border-radius: 999px; background: var(--ground-hi); transition: background .2s; }
.step-pip.on { background: var(--gold-metal); }

.gametile {
  text-align: left; cursor: pointer; padding: 16px; border-radius: var(--r);
  border: 1px solid var(--line); background: var(--ground-2); transition: all .15s; position: relative;
  display: flex; align-items: center; gap: 14px;
}
.gametile:hover:not(.soon) { border-color: var(--line-strong); background: var(--ground-3); }
.gametile.sel { border-color: var(--gold); box-shadow: var(--shadow-gold); background: linear-gradient(180deg,var(--ground-3),var(--ground-2)); }
.gametile.soon { opacity: 0.5; cursor: not-allowed; }
.gametile .check { margin-left: auto; color: var(--gold-hi); opacity: 0; transition: opacity .15s; }
.gametile.sel .check { opacity: 1; }

.field { display: flex; flex-direction: column; gap: 8px; }
.input {
  font-family: var(--sans); font-size: 16px; color: var(--cream);
  padding: 13px 15px; border-radius: var(--r); border: 1px solid var(--line-strong);
  background: var(--ink); transition: border-color .15s, box-shadow .15s; width: 100%;
  /* An <input> is a replaced element and cannot carry a ::after, so unlike every other
     control it needs real height to reach 44px. The default padding already lands at ~45,
     so this only catches the call sites that tighten the padding to fit a dense row.
     The 16px font-size is load-bearing too: below it, iOS Safari zooms the page on focus
     and never zooms back. */
  min-height: 44px;
}
.input::placeholder { color: var(--cream-mut); }
.input:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-soft); }

.chiprow { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  font-size: 13.5px; font-weight: 600; padding: 9px 14px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--ground-2); color: var(--cream-dim); cursor: pointer; transition: all .14s;
}
.chip:hover { border-color: var(--line-strong); color: var(--cream); }
.chip.sel { border-color: var(--gold); color: var(--gold-hi); background: var(--gold-soft); }

.switch { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 13px 0; cursor: pointer; }
.switch:not(:last-child) { border-bottom: 1px solid var(--line); }
.toggle { width: 42px; height: 24px; border-radius: 999px; background: var(--ground-hi); border: 1px solid var(--line); position: relative; transition: background .18s; flex: none; }
.toggle::after { content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: var(--cream-dim); transition: transform .18s, background .18s; }
.toggle.on { background: var(--pine-bg); border-color: var(--success-line); }
.toggle.on::after { transform: translateX(18px); background: var(--pine); }

@keyframes meterStrobe { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
.meter.summoning .meter-fill { animation: meterStrobe 1.1s ease-in-out infinite; }

/* ============================================================
   RESPONSIVE (marketing / hero)
   ============================================================ */
@media (max-width: 900px) {
  .mk-nav { padding: var(--mk-head-pad) 24px; }
  .mk-wrap { padding: 0 24px; }
  .hero { grid-template-columns: 1fr; gap: 30px; padding: 40px 0 52px; }
  .hero-sub { max-width: none; }
  .vp-grid { grid-template-columns: 1fr; }
  .stakes-row { grid-template-columns: 1fr; }
  .mk-nav-links { gap: 18px; }
  /* .hero-art's height override lives with the rest of the hero art further
     down — this block is above the base rule, so an override here loses the
     cascade on equal specificity and silently does nothing. */
}
/* The hamburger takes over at 720px, not 560px, because the full nav needs 693px to fit.
   Handing control back at 560 left a 561-692px band — large phones in landscape, small
   tablets — where the header simply hung off the right edge of the screen, 132px over at
   561. The two numbers were chosen independently and never reconciled.
   Kept in its own block rather than folded into the 560px one below: that block also
   carries hero and footer rules that are correctly tuned to 560. */
@media (max-width: 720px) {
  /* Direct-child only: the dropdown's own .mk-menu-link anchors are nested
     deeper inside .mk-nav-links and must not be hidden by this rule. */
  .mk-nav-links > a:not(.btn) { display: none; }
  .x-btn.mk-menu-btn { display: grid; }
}
@media (max-width: 560px) {
  .mk-foot-in .sep { display: none; }
  .hero h1 { font-size: clamp(32px, 10.5vw, 46px); }
  .hero-cta { flex-direction: column; align-items: stretch; }
  .hero-cta .btn { width: 100%; }
  .mk-foot-in { flex-direction: column; align-items: flex-start; gap: 16px; }
}
@media (max-width: 440px) {
  /* Too narrow for the bar CTA + hamburger to coexist — the Summon action
     lives in the dropdown (gold item) at this width instead. Match any nav
     button: the marketing bar CTA is now ghost (gold diet), not gold. */
  .mk-nav-links .btn { display: none; }
}

/* ============================================================
   RESPONSIVE (app shell + screens)
   ============================================================ */
.split-2 { display: grid; grid-template-columns: 1.2fr 1fr; gap: 22px; }
/* Grid items default to min-width:auto and won't shrink below their content's
   intrinsic width — an unbreakable number/URL then forces a track past its fr
   share and the columns overlap instead of shrinking. min-width:0 lets them
   collapse cleanly until the single-column breakpoint takes over. */
.split-2 > * { min-width: 0; }
.grid-packs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.game-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.menu-btn {
  display: none; width: 38px; height: 38px; border-radius: 9px; flex: none;
  border: 1px solid var(--line); background: var(--ground-2); color: var(--cream-dim);
  align-items: center; justify-content: center; cursor: pointer; padding: 0;
}
.menu-btn:hover { color: var(--cream); border-color: var(--line-strong); }
.drawer-scrim { display: none; }
.topbar-home {
  display: none; width: 36px; height: 36px; border-radius: 9px; flex: none;
  border: 1px solid var(--line); background: transparent; align-items: center; justify-content: center;
  cursor: pointer; padding: 0;
}
.topbar-logout { display: none; }
.tabbar { display: none; }
.tab {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: none; border: 0; cursor: pointer; color: var(--cream-mut); padding: 7px 4px 4px;
  border-radius: 10px; font-family: var(--sans); transition: color .15s;
}
.tab .tab-ic { display: flex; }
.tab .tab-lb { font-size: 10.5px; font-weight: 600; letter-spacing: .02em; }
.tab.on { color: var(--gold-hi); }
.tab-summon .tab-ic {
  width: 40px; height: 40px; border-radius: 12px; margin-top: -5px;
  background: var(--gold-metal); color: #3C2E0C; display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-gold); border: 1px solid var(--gold-deep);
}
.tab-summon .tab-lb { color: var(--gold-hi); }

@media (max-width: 860px) {
  .crumb-serf { display: none; }
  .shell { grid-template-columns: minmax(0, 1fr); }
  .game-feature { flex-direction: column; }
  /* .mk-wrap scope raises specificity above the base grid rules, which are
     declared later in the file and would otherwise win at equal specificity */
  .mk-wrap .game-soon-grid { grid-template-columns: 1fr; }
  .mk-wrap .support-panel { grid-template-columns: 1fr; }
  /* featured cover art stacks on top, masking downward into the panel */
  .game-feature.has-art .game-feature-art {
    width: 100%; height: 180px; min-height: 0; align-self: auto;
    -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
  }
  /* .game-feature-body's override moved down beside the base rule — see the note there. */
  .faq { padding: 4px 20px; }

  /* drawer mode */
  [data-mnav="drawer"] .menu-btn { display: flex; }
  [data-mnav="drawer"] .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; height: 100vh; width: 272px; z-index: 60;
    overflow-y: auto; transform: translateX(-100%);
    transition: transform .26s cubic-bezier(.2,.8,.3,1); box-shadow: 0 30px 80px rgba(0,0,0,0.6);
  }
  [data-mnav="drawer"] .shell.menu-open .sidebar { transform: none; }
  [data-mnav="drawer"] .drawer-scrim {
    display: block; position: fixed; inset: 0; z-index: 55; background: rgba(8,7,5,0.6);
    backdrop-filter: blur(2px); opacity: 0; pointer-events: none; transition: opacity .22s;
  }
  [data-mnav="drawer"] .shell.menu-open .drawer-scrim { opacity: 1; pointer-events: auto; }

  /* bottom tab bar mode */
  [data-mnav="tabbar"] .sidebar { display: none; }
  [data-mnav="tabbar"] .menu-btn { display: none; }
  [data-mnav="tabbar"] .topbar-home { display: flex; }
  [data-mnav="tabbar"] .topbar-logout { display: grid; }
  [data-mnav="tabbar"] .summon-btn { display: none; }
  [data-mnav="tabbar"] .page { padding-bottom: 96px; }
  [data-mnav="tabbar"] .tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    background: color-mix(in srgb, var(--ink) 90%, transparent); backdrop-filter: blur(12px);
    border-top: 1px solid var(--line);
    padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
  }

  .topbar { padding: 13px 16px; }
  .page { padding: 22px 16px 56px; }
  .page-title { font-size: 27px; }

  .split-2 { grid-template-columns: 1fr; gap: 16px; }
  .grid-packs { grid-template-columns: 1fr 1fr; gap: 12px; }
  .game-grid { grid-template-columns: 1fr; }

  /* flex-wrap MUST go back to nowrap when the head turns into a column. A wrapping column
     flex container sizes its line from the items' max-content widths rather than from the
     container, so align-items:stretch stretched every child to the connect box's 406px
     inside a 358px card — and overflow:hidden cut off the status pill and the Copy button.
     One column, one line, and stretch finally means "the width of the card". */
  .server-head { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 16px; }
  .server-head > div:last-child { min-width: 0 !important; }
  .server-stats { grid-template-columns: 1fr 1fr; }
  .server-stat { border-bottom: 1px solid var(--line); }
  .server-stat:nth-child(2n) { border-right: 0; }
  .server-stat:nth-last-child(-n+2) { border-bottom: 0; }
  /* .server-actions wraps at every width now — see the base rule. Only the toggle's
     right-alignment needs undoing here, so it doesn't strand itself on its own line. */
  .server-actions .adv-toggle { margin-left: 0 !important; }
  .card-banner { height: 112px; }

  /* Keep realm controls labeled and wrapped so save actions stay discoverable
     on touch screens while the primary action remains prominent. */
  .server-actions > .btn { max-width: 100%; }
  .realm-past-row { flex-direction: column; align-items: stretch; gap: 16px; }
  .realm-past-info { min-width: 0; }
  .realm-past-actions { width: 100%; min-width: 0; flex-wrap: wrap; justify-content: flex-start; }
  .realm-past-actions > .btn { max-width: 100%; flex: 1 1 auto; }

  .scrim { padding: 0; align-items: flex-end; }
  .modal { max-height: 94vh; border-radius: 22px 22px 0 0; animation: sheetIn .3s var(--e-settle); }
  .modal-head, .modal-body, .modal-foot { padding-left: 20px; padding-right: 20px; }
}

@media (max-width: 480px) {
  .bal-hrs { display: none; }
  .summon-label { display: none; }
  .summon-btn { padding: 9px 12px; }
  .grid-packs { grid-template-columns: 1fr; }
  .page-title { font-size: 25px; }
  .server-actions { align-items: stretch; }
  .server-actions > .btn,
  .realm-past-actions > .btn { flex: 1 1 100%; }
  .realm-past-actions > .realm-past-primary { order: -1; }
  /* a long house name has no room left beside the banner's edge here — give the chip the
     full width and let it truncate rather than shrink the sigil */
  .card-house { left: 15px; right: 15px; max-width: none; }
}

/* The old summoning ledger's .raise-* family was replaced by the frame-3a panel (.sm-*).
   Only .raise-blip survives — RealmsPastList uses it for the thaw-in-progress pulse. */
.raise-blip {
  width: 9px; height: 9px; border-radius: 50%; background: var(--gold);
  position: relative;
}
.raise-blip::after { background: rgba(203,163,92,0.55); animation-duration: 1.6s; }

/* writ reveal (Steward's Desk / Gatehouse) */
.writ-in { animation: writIn var(--m-rise) var(--e-settle); }
@keyframes writIn { from { opacity: 0; transform: translateY(12px) scale(.985); } }

/* The Gatehouse (auth) */
.gate { position: relative; z-index: 1; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 48px 20px; gap: 22px; }
.lost {
  position: relative; z-index: 1; min-height: 100vh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 48px 20px;
}
.game-feature { padding: 30px 32px; display: flex; gap: 28px; align-items: flex-start; }
.game-feature-emblem { width: 84px; height: 84px; border-radius: 20px; font-size: 34px; flex: none; }
.game-soon-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; }
.game-soon { padding: 22px 24px; display: flex; flex-direction: column; }
.game-soon.voted { border-color: var(--line-strong); }

/* games.vue — featured Valheim cover art (bleeds to 3 edges, masked into panel bg).
   Emblem tiles remain the fallback for games without art. */
.game-feature.has-art { padding: 0; gap: 0; overflow: hidden; }
.game-feature.has-art .game-feature-art {
  flex: none; width: 220px; align-self: stretch; min-height: 264px;
  background: var(--ground-2) center / cover no-repeat;
  -webkit-mask-image: linear-gradient(90deg, #000 55%, transparent 100%);
  mask-image: linear-gradient(90deg, #000 55%, transparent 100%);
}
.game-feature.has-art .game-feature-body { padding: 30px 32px; margin-left: -28px; min-width: 0; }
/* Must be declared AFTER the rule above, not with the other 860px overrides ~130 lines up:
   both selectors are (0,3,0), so identical specificity falls through to source order and the
   later unconditional rule wins at EVERY viewport. Stacked mode never once applied — the art
   stacked on top while the body kept the side-by-side -28px left margin, pushing it 3px past
   the frame at 360-768 (clipped, not scrolled, because .game-feature.has-art is
   overflow:hidden, which is why it stayed invisible).
   This is the second instance of this exact cascade trap in this file; the first was
   .hero-art's height, which geometry/hero-art.pw.ts now guards. */
@media (max-width: 860px) {
  /* align-self, because .game-feature is `align-items: flex-start`: once the container turns
     into a column that sizes children to max-content, so the body kept its own intrinsic
     315px inside a 310px frame and the panel quietly clipped the difference. Set on the item
     rather than flipping the container's align-items, which the emblem layout relies on. */
  .game-feature.has-art .game-feature-body { margin-left: 0; margin-top: -28px; align-self: stretch; }
}

/* games.vue — petition card cover strip (art above, content below) */
.game-soon.has-art { padding: 0; overflow: hidden; }
.game-soon-art { height: 120px; background: var(--ground-2) center / cover no-repeat; }
.game-soon-body { padding: 22px 24px; display: flex; flex-direction: column; flex: 1; }

/* marketing hero background art — atmosphere, not a picture: masked into --ink,
   content above. One image per page; the mask + opacity are load-bearing.
   The element is the stationary aperture (mask + clip); animating it directly
   would drag the mask along and the dissolve edge would visibly swim.

   The photo is deliberately PINNED. A drift over this cut read as uncanny: the
   roofline and horizon are straight high-contrast edges sitting beside fixed
   text baselines, so any pan or scale creeps against them, and a moving horizon
   reads as the ground sliding rather than a camera move. Only things that move
   in the real world are animated — the fog, and the firelight in the windows. */
.hero-art {
  /* Reaches UP behind the header. ENG-101 made the shared header a sibling of
     .mk, so this — absolute at top:0 inside .mk — began below it, and the top of
     the page was a flat band of .app-bg with a hard seam where the photo started.
     The negative top puts the photo back at the page top with the nav floating
     over it, which is the arrangement .mk-nav's own z-index exists for. Height
     grows by the same amount so the art still ENDS where it always did — nothing
     below the hero shifts. */
  position: absolute; top: calc(-1 * var(--mk-head-h)); left: 0; right: 0;
  height: calc(740px + var(--mk-head-h)); z-index: 0;
  overflow: hidden; pointer-events: none;
  opacity: .92;
  /* Dissolves DOWNWARD, into the page floor. This replaced a radial hot-spot at
     52% 92% that opened at the bottom and faded upward — a better mask for a
     still photograph, but it held the top of the frame at ~14% alpha, and the
     WebGL atmosphere puts every bolt pixel and the whole sky flash in image-space
     uv.y 0.06-0.56. The old mask erased the entire effect. The direction of this
     fade is load-bearing for the FX layer, not a taste call: re-point it at the
     sky and the lightning goes with it. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 99%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 99%);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
/* The photo — static, and deliberately so. A drift over this cut read as
   uncanny: the roofline and horizon are straight high-contrast edges sitting
   beside fixed text baselines, so any pan creeps against them. Only things that
   move in the real world are animated — the fog, and the firelight.

   A real <img> rather than a background, because the FX layer reads its
   rendered rect each frame to map canvas uv -> image uv, and reads its pixels
   to extract the firelight mask. Neither is possible against a CSS background.
   The oversize + pull-up bottom-anchors the cover crop, lifting the hall clear
   of the body copy and behind the display type. */
/* Must sit AFTER the base rule, not up with the other 900px overrides: same
   specificity, so the cascade is decided on source order alone. The old
   560px override was declared above the base rule and had never once applied. */
@media (max-width: 900px) {
  .marketing { --mk-head-pad: 18px; }
  .hero-art { height: calc(600px + var(--mk-head-h)); }
}
/* The pull-up is 60px, not the handoff's 160px.
   RE-MEASURED 2026-08-07 against the corrected uv mapping. The old note here
   claimed 60 "opens at image-space uv.y 0.080" and that 160 cropped the bolt's
   origin off. Both numbers came from the object-fit-blind mapping and were wrong,
   and the real answer is not a single number at all — where the frame opens
   depends on VIEWPORT WIDTH, because cover discards more height the wider it gets:

       width    pull=0   pull=60   pull=160
        1440     -0.012    0.025     0.086
        1800      0.090    0.120     0.169
        2560      0.212    0.233     0.267
        3440      0.286    0.301     0.327

   So the bolt's designed 0.06-0.12 origin is only in frame up to ~1800px, and
   past that NO pull-up recovers it (it would take a negative one). That is now
   handled where it belongs — uTopUv in HeroAtmosphere.vue floors the bolt's start
   at the visible top of the frame — rather than by tuning this.
   Which leaves 60 doing very little: it slides the crop window by 0.021 uv at
   2560, 0.037 at 1440. Kept because it is harmless and bottom-anchors the crop a
   touch, NOT because the old rationale held up. Nothing here rides on it now. */
.hero-photo {
  position: absolute; top: -60px; left: 0; right: 0; display: block;
  height: calc(100% + 60px);
}
.hero-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* drifting mist over the treeline. Fog genuinely moves, so this reads as
   weather rather than as the landscape sliding. Overhangs far past both edges
   so the translate never exposes one, and transform-only to stay off paint. */
.hero-fog {
  /* Sits in the mask's opaque band (0-55%) rather than pinned to the bottom as
     before: under the old upward fade the valley was the brightest part of the
     frame, under this one the bottom is where the art dissolves out, and fog
     anchored there was fading to nothing. */
  position: absolute; left: -55%; right: -55%; top: 26%; height: 34%;
  background:
    radial-gradient(56% 100% at 32% 62%, rgba(216,205,183,0.19), transparent 72%),
    radial-gradient(42% 92% at 71% 48%, rgba(216,205,183,0.14), transparent 74%);
  /* Both radials are still ~4-6% opaque where this box ends, so the box edge
     cut a hard horizontal line across the frame. Dissolve the layer into its
     own top edge instead — and keep this mask even if the alphas change again,
     since it makes the edge unconditionally safe rather than safe-by-tuning. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 42%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 42%);
  animation: fogDrift 40s var(--e-inout) infinite alternate;
}
/* firelight in the hall windows. The sprite shares the photo's 16:9 canvas and
   the identical `bottom / cover` sizing, so it tracks the windows at every
   viewport — a gradient could not, since its percentages resolve against the
   element box, whose aspect changes with the viewport while the photo's cannot.
   NOTE: the glow's position is baked into the sprite against THIS crop; re-cut
   the art and hero-hearth must be regenerated to match. */
/* Firelight in the hall windows — the fallback path only. The sprite must share
   the photo's box exactly or the glow walks off the windows, so it tracks
   .hero-photo's geometry, not the host's. Its position is baked against THIS
   crop; re-cut the art and this must be regenerated to match. (The WebGL path
   has no such coupling — it derives the same glow from the image's own warm
   pixels at runtime.) */
.hero-hearth {
  position: absolute; top: -60px; left: 0; right: 0; height: calc(100% + 60px);
  mix-blend-mode: screen;
  background: url(/brand/hero-hearth3.png) center / cover no-repeat;
  background-image: image-set(
    url(/brand/hero-hearth3.avif) type("image/avif"),
    url(/brand/hero-hearth3.png)  type("image/png")
  );
  animation: hearthFlicker 7.5s ease-in-out infinite;
}
/* Legibility scrim for the left-aligned headline. Under the old radial mask the
   top-left corner was already dimmed to near nothing and this was free; the
   linear fade holds it at full opacity, so the contrast is now this layer's job.
   Note it claims ::after, which used to carry a screened firelight bloom — the
   bloom is gone, superseded by the shader's sky flash and window glow (and by
   the scrim itself, which would have fought it). */
.hero-art::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(97deg,
    rgba(16,15,11,.50) 0%, rgba(16,15,11,.18) 34%, transparent 58%);
}
/* The WebGL layer. Renders only light on black, so `screen` adds glow without
   ever darkening the art. Sits under the scrim, above the photo. */
.hero-fx {
  position: absolute; inset: 0; width: 100%; height: 100%;
  mix-blend-mode: screen; pointer-events: none;
}
/* The shader supersedes both CSS atmosphere layers once it is actually running —
   set only after the context exists AND the program links, so a failure anywhere
   in that chain leaves the CSS hero intact rather than bare. */
.hero-art.fx-live .hero-fog,
.hero-art.fx-live .hero-hearth { display: none; }
/* transform-only: stays on the compositor, no layout or paint per frame */
@keyframes fogDrift {
  from { transform: translate3d(-12%, 0, 0); }
  to   { transform: translate3d(12%, 0, 0); }
}
/* uneven stops on purpose — evenly spaced keyframes read as a metronome, and
   firelight doesn't keep time. 0% and 100% match so the loop never snaps. */
@keyframes hearthFlicker {
  0%   { opacity: .38; }
  11%  { opacity: .80; }
  19%  { opacity: .49; }
  33%  { opacity: .98; }
  44%  { opacity: .60; }
  57%  { opacity: .90; }
  69%  { opacity: .44; }
  82%  { opacity: .95; }
  100% { opacity: .38; }
}
/* The global reduce rule only collapses duration, which would freeze these at
   their `to` frame — pin them to a deliberate resting state instead.

   This is also the whole reduced-motion story for the hero: HeroAtmosphere.vue
   never mounts the WebGL layer when reduce is set, so these two layers are what
   those visitors get. Lightning is the reason — a burst is 2-3 strobes 90-310ms
   apart across a full-bleed layer, which is squarely what the WCAG 2.3.1 flash
   threshold exists for, and gating the bolt alone would still leave a canvas
   running for no visible gain. */
@media (prefers-reduced-motion: reduce) {
  .hero-fog    { animation: none; transform: none; }
  .hero-hearth { animation: none; opacity: .78; }
}

/* marketing support panel — copy left, mini-ledger right */
.support-panel { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 30px; align-items: center; }

/* treasury widget in-play / asleep demo chips */
.tw-chips { display: flex; gap: 6px; }
.tw-chip {
  font-family: var(--sans); font-weight: 600; font-size: 12px; padding: 5px 11px;
  border-radius: 999px; white-space: nowrap; border: 1px solid var(--parchment-ln);
  background: transparent; color: var(--ink-on-parch-dim); cursor: pointer;
  transition: color var(--m-quick), border-color var(--m-quick), background var(--m-quick);
}
.tw-chip:hover { border-color: var(--gold-lo); }
.tw-chip.sel { border-color: var(--gold-lo); color: var(--gold-deep); background: rgba(43,36,23,0.05); }

/* marketing "The Realms" strip — teaser cards linking to /games */
.games-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; padding-bottom: 74px; }
.game-card { overflow: hidden; display: flex; flex-direction: column; padding: 0; text-decoration: none; }
.game-card-art { width: 100%; height: 170px; background: var(--ground-2) center / cover no-repeat; display: block; }
.game-card.featured { grid-column: 1 / -1; }
.game-card.featured .game-card-art { height: 300px; }
.game-meta { padding: 16px 20px; display: flex; align-items: center; justify-content: space-between; gap: 8px 12px; flex-wrap: wrap; }
.game-meta .pill, .game-meta .tag-live { white-space: nowrap; flex: none; }
.game-name { font-family: var(--display); font-weight: 600; font-size: 19px; color: var(--cream); }
.faq { padding: 10px 30px; }
.faq-row { border-bottom: 1px solid var(--parchment-ln); }
.faq-row:last-child { border-bottom: 0; }
.faq-q {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: none; border: 0; cursor: pointer; text-align: left;
  padding: 18px 2px; font-family: var(--sans); font-weight: 700; font-size: 16px;
  color: var(--ink-on-parch);
}
.faq-q:hover { color: var(--gold-deep); }
.faq-chev { display: inline-flex; color: var(--gold-lo); transition: transform .15s; flex: none; }
.faq-a {
  margin: -6px 0 0; padding: 0 2px 18px; font-size: 14.5px; line-height: 1.6;
  color: var(--ink-on-parch); max-width: 56em;
}
.pub-status {
  display: flex; align-items: center; justify-content: center; gap: 26px; flex-wrap: wrap;
  padding: 14px 24px; margin: -8px 0 30px; border-radius: 999px;
}
.pub-stat { font-size: 13.5px; color: var(--cream-mut); white-space: nowrap; }
.pub-stat .tnum { font-weight: 700; color: var(--cream-dim); }
.gate-brand { display: flex; flex-direction: column; align-items: center; gap: 12px; cursor: pointer; }
.gate-brand .wordmark { font-size: 21px; }
.gate-card { width: min(460px, 100%); padding: 34px 36px 30px; }
.gate-head { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; margin-bottom: 24px; }
.gate-title { font-size: 30px; margin: 0; color: var(--cream); }
.gate-sub { font-style: italic; font-size: 16px; color: var(--cream-dim); margin: 0; line-height: 1.45; text-wrap: pretty; }
.gate-notice { display: inline-flex; align-items: center; gap: 9px; max-width: min(460px, 100%); font-size: 13.5px; font-weight: 600; color: var(--gold-hi); background: var(--gold-soft); border: 1px solid var(--line-strong); border-radius: 999px; padding: 8px 18px; text-align: center; }
.gate-forgot { align-self: center; font-size: 13.5px; font-weight: 600; color: var(--cream-mut); text-decoration: none; cursor: pointer; transition: color .15s; }
.gate-forgot:hover { color: var(--gold-hi); }
.gate-links { color: var(--cream-mut); font-size: 14px; display: flex; gap: 7px; align-items: center; }
.gate-links a { cursor: pointer; font-weight: 600; text-decoration: none; }
.gate-links a:hover { text-decoration: underline; }
.gate-foot { font-style: italic; font-size: 15px; color: var(--cream-mut); margin: 4px 0 0; }
.gate-err { color: var(--blood); font-size: 13.5px; font-weight: 600; }
.key-input { text-align: center; font-size: 21px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; font-variant-numeric: tabular-nums; }
.key-input::placeholder { letter-spacing: .14em; font-size: 19px; }
.gate-writ-tag { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 13px; font-weight: 600; color: var(--pine); background: var(--pine-bg); border: 1px solid var(--success-line); border-radius: var(--r); padding: 9px 14px; }

/* scrollbar */
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-thumb { background: var(--ground-3); border-radius: 6px; border: 3px solid var(--ink); }
::-webkit-scrollbar-track { background: transparent; }

/* app-specific (not in the design bundle): centered placeholder for the "coming soon"
   pages (Treasury/Court) and the Realm stub until M1-B builds the real dashboard. */
.coming-soon {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; min-height: 60vh; text-align: center;
}
.coming-soon .steward { font-size: 18px; color: var(--cream-dim); }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.stack-16 { display: flex; flex-direction: column; gap: 16px; }

/* First-run realm hero */
.first-run {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 48px 28px;
}
.first-run-steps {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin: 22px 0 26px;
  color: var(--cream-dim);
  font-size: 14px;
}
.first-run-steps > span { white-space: nowrap; }
.first-run-steps b { color: var(--gold-hi); margin-right: 6px; font-weight: 800; }
.fr-sep { display: inline-flex; align-items: center; opacity: 0.45; }

/* ============================================================
   MOTION — tokens, loops, entrances  (binding spec: motion-spec.jsx)
   ============================================================ */
:root {
  --m-fast: 140ms;   /* hover, press, chevrons, chips */
  --m-quick: 200ms;  /* fades, pills, color/opacity crossfades */
  --m-move: 260ms;   /* overlays, drawers, page enter */
  --m-rise: 450ms;   /* ceremonial entrances (writ, fresh realm) */
  --e-settle: cubic-bezier(.2,.8,.3,1);
  --e-inout: cubic-bezier(.45,0,.25,1);
}
@keyframes fadeUp { from { opacity: 0; transform: translateY(8px); } }
@keyframes fadeIn { from { opacity: 0; } }
.page { animation: fadeUp var(--m-move) var(--e-settle) both; }
.pill { transition: color var(--m-quick), background var(--m-quick), border-color var(--m-quick); }

@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.skel { position: relative; overflow: hidden; border-radius: 8px; background: var(--ground-3); }
.skel::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 32%, rgba(240,214,153,0.09) 50%, transparent 68%);
  background-size: 200% 100%; animation: shimmer 1.8s linear infinite;
}
.skel-round { border-radius: 50%; }

.loading-state {
  display: grid;
  place-items: center;
  gap: 14px;
  padding: 40px 0;
  text-align: center;
}
.loading-state.compact {
  padding: 8px 0;
}
.loading-state-text {
  font-style: italic;
  font-size: 16.5px;
  color: var(--cream-dim);
  animation: fadeIn .3s ease;
}
.loading-state.compact .loading-state-text {
  font-size: 14.5px;
}

@keyframes goldPulse { from { box-shadow: 0 0 0 0 rgba(203,163,92,0.4); } to { box-shadow: 0 0 0 16px rgba(203,163,92,0); } }
.just-summoned { animation: writIn var(--m-rise) var(--e-settle), goldPulse 1.1s ease-out var(--m-rise); }
.gold-pulse { animation: goldPulse 1.1s ease-out; }
@keyframes sheetIn { from { opacity: 0; transform: translateY(44px); } }

/* --- SealLoader (calm loader): a sheen sweep + slow breath; no spin --- */
.seal-loader { position: relative; display: inline-grid; place-items: center; flex: none;
  animation: sealBreath 3s ease-in-out infinite; }
.seal-loader.no-breath { animation: none; }
.seal-loader .seal-sheen {
  position: absolute; inset: 0; border-radius: 50%; overflow: hidden; pointer-events: none;
  background: linear-gradient(115deg, transparent 38%, rgba(255,250,235,0.6) 50%, transparent 62%);
  background-size: 240% 240%; mix-blend-mode: screen;
  animation: sealSheen 1.9s linear infinite;
}
@keyframes sealSheen { from { background-position: 210% 0; } to { background-position: -130% 0; } }
@keyframes sealBreath { 0%, 100% { transform: scale(.97); } 50% { transform: scale(1.01); } }

/* --- MintLoader (ceremonial): a press strikes the seal, flash + ripple. Summon modal only. --- */
.mint-loader { position: relative; display: block; width: 116px; height: 150px; flex: none; margin: 0 auto; }
.mint-loader .mint-seal {
  position: absolute; left: 50%; bottom: 30px; margin-left: -28px; z-index: 2; transform-origin: center;
  animation: mintFlash 1.6s var(--e-inout) infinite;
}
.mint-loader .mint-press {
  position: absolute; top: 6px; left: 50%; width: 54px; height: 32px; margin-left: -27px; z-index: 3;
  background: linear-gradient(180deg, #423b2c, #25211a);
  border: 1px solid var(--line-strong); border-bottom-color: var(--gold-deep);
  border-radius: 5px 5px 7px 7px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  animation: mintStrike 1.6s var(--e-inout) infinite;
}
.mint-loader .mint-press::after {
  content: ""; position: absolute; left: 50%; bottom: -4px; width: 24px; height: 5px; margin-left: -12px;
  background: var(--gold-lo); border-radius: 0 0 3px 3px; opacity: .7;
}
.mint-loader .mint-anvil {
  position: absolute; bottom: 16px; left: 50%; width: 70px; height: 12px; margin-left: -35px;
  background: linear-gradient(180deg, #2c2820, #1b1813); border: 1px solid var(--line); border-radius: 4px;
}
.mint-loader .mint-ripple {
  position: absolute; top: 92px; left: 50%; width: 52px; height: 52px; margin: -26px 0 0 -26px;
  border-radius: 50%; z-index: 1; animation: mintRipple 1.6s ease-out infinite;
}
@keyframes mintStrike { 0%, 32%, 100% { transform: translateY(0); } 48% { transform: translateY(42px); } 60% { transform: translateY(0); } }
@keyframes mintFlash  { 0%, 44%, 100% { filter: brightness(1); transform: scale(1); } 50% { filter: brightness(1.4); transform: scale(1.05); } 64% { filter: brightness(1); transform: scale(1); } }
@keyframes mintRipple { 0%, 46% { box-shadow: 0 0 0 0 rgba(203,163,92,0); } 52% { box-shadow: 0 0 0 0 rgba(203,163,92,0.55); } 100% { box-shadow: 0 0 0 24px rgba(203,163,92,0); } }

/* --- recall / undo toast (banking the hearth) --- */
.toast-stack { position: fixed; left: 0; right: 0; bottom: 0; z-index: 90; pointer-events: none; }
.toast-summon {
  display: flex; align-items: center; gap: 13px;
  background: var(--ground-2); border: 1px solid var(--line-strong); border-radius: var(--r);
  box-shadow: 0 18px 50px rgba(0,0,0,0.5); padding: 11px 12px 11px 15px;
  pointer-events: auto;
}
.toast-fixed {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); z-index: 90;
  width: min(440px, calc(100% - 32px)); animation: toastIn .3s var(--e-settle);
}
@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 18px); } }

/* dying-ember dot for the busy "Dismissing…" button */
.ember {
  width: 9px; height: 9px; border-radius: 50%; background: var(--gold); flex: none;
  box-shadow: 0 0 8px 1px rgba(203,163,92,0.6);
  animation: ember 1.1s ease-in-out infinite alternate;
}
@keyframes ember {
  from { opacity: 1;  box-shadow: 0 0 8px 1px rgba(203,163,92,0.6); }
  to   { opacity: .4; box-shadow: 0 0 2px 0 rgba(203,163,92,0.12); }
}
/* one-shot: the card cools as it goes dormant */
.hearth-cool { animation: hearthCool .7s var(--e-settle) both; }
@keyframes hearthCool { 0% { filter: saturate(1.16) brightness(1.05); } 100% { filter: saturate(.92) brightness(.98); } }
/* one-shot: warm glow contracts off the emblem — embers banked */
.emblem-bank { position: relative; }
.emblem-bank::after {
  content: ""; position: absolute; inset: -3px; border-radius: inherit; pointer-events: none;
  animation: emberGlow .8s var(--e-settle) both;
}
@keyframes emberGlow { 0% { box-shadow: 0 0 18px 5px rgba(203,163,92,0.4); } 100% { box-shadow: 0 0 0 0 rgba(203,163,92,0); } }
/* ledger crossfade (200ms) */
.fade-enter-active, .fade-leave-active { transition: opacity .2s var(--e-settle); }
.fade-enter-from, .fade-leave-to { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
}

/* ============================================================
   MENUS · SELECT · LIST TOOLBAR (added 2026-07-20)
   Popover menus, the styled select, segmented filters, inline
   confirm bars, and the row-list pattern (Realms Past et al).
   ============================================================ */

/* popover menu */
.menu-wrap { position: relative; display: inline-flex; }
.menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 40; min-width: 200px;
  padding: 6px; display: none;
  background: linear-gradient(180deg, var(--ground-3), var(--ground-2));
  border: 1px solid var(--line-strong); border-radius: var(--r);
  box-shadow: 0 18px 44px -12px rgba(0,0,0,0.65), inset 0 1px 0 rgba(236,206,133,0.07);
}
.menu-wrap.open > .menu, .select.open > .menu { display: block; animation: fadeUp var(--m-quick) var(--e-settle); }
/* A menu teleported out of a clipping card (components/brand/DropMenu.vue). It is no longer a
   child of .menu-wrap, so it cannot inherit the open rule above — and it is positioned in
   viewport coordinates by the component, not by `top/right` here. */
.menu-float { display: block; position: fixed; right: auto; animation: fadeUp var(--m-quick) var(--e-settle); }
.menu.left { right: auto; left: 0; }
.menu-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; border: 0; border-radius: var(--r-sm); background: none;
  font-family: var(--sans); font-size: 14px; font-weight: 600; color: var(--cream-dim);
  cursor: pointer; text-align: left; white-space: nowrap; text-decoration: none;
}
.menu-item:hover { background: var(--gold-soft); color: var(--gold-hi); }
.menu-item.danger { color: var(--blood); }
.menu-item.danger:hover { background: var(--blood-bg); color: var(--blood); }
.menu-item .mi-sub { margin-left: auto; padding-left: 18px; font-size: 12px; font-weight: 500; color: var(--cream-mut); }
.menu-item .mi-check { margin-left: auto; display: inline-flex; visibility: hidden; color: var(--gold); }
.menu-item .mi-sub + .mi-check { margin-left: 0; }
.menu-item.sel { color: var(--cream); }
.menu-item.sel .mi-check { visibility: visible; }
.menu-sep { height: 1px; margin: 6px 4px; background: var(--line); }
.menu-head { padding: 8px 12px 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--cream-mut); }

/* select — an input-shaped trigger that opens a .menu */
.select { position: relative; display: inline-flex; flex-direction: column; }
.select-btn {
  display: flex; align-items: center; gap: 9px; cursor: pointer; width: 100%;
  font-family: var(--sans); font-size: 14px; font-weight: 600; color: var(--cream);
  padding: 10px 12px 10px 14px; border-radius: var(--r);
  border: 1px solid var(--line-strong); background: var(--ink); text-align: left;
  transition: border-color var(--m-quick) ease, box-shadow var(--m-quick) ease;
}
.select-btn:hover { border-color: var(--gold-lo); }
.select-btn .sel-lab { color: var(--cream-mut); font-weight: 600; flex: none; }
.select-btn .sel-chev { display: inline-flex; margin-left: auto; color: var(--cream-mut); transform: rotate(90deg); transition: transform var(--m-fast) ease; }
.select.open .select-btn { border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-soft); }
.select.open .sel-chev { transform: rotate(-90deg); }
.select > .menu { top: calc(100% + 6px); left: 0; right: auto; min-width: 100%; }
.menu.up, .select > .menu.up { top: auto; bottom: calc(100% + 6px); }
.select.open > .menu.up { animation: fadeIn var(--m-quick) var(--e-settle); }

/* native <select> fallback — never ship the browser default */
select.input {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23B8AD93' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center; background-size: 15px;
}
select.input option { background: var(--ground-2); color: var(--cream); }

/* square icon button (overflow kebab, toolbar glyphs) */
.btn-icon {
  width: 36px; height: 36px; padding: 0; flex: none; display: inline-grid; place-items: center;
  border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--ground-2);
  color: var(--cream-dim); cursor: pointer;
  transition: color var(--m-fast) ease, border-color var(--m-fast) ease, background var(--m-fast) ease;
}
.btn-icon:hover { color: var(--cream); border-color: var(--line-strong); background: var(--ground-3); }
.btn-icon.open { color: var(--gold-hi); border-color: var(--gold); background: var(--gold-soft); }

/* segmented filter */
.seg { display: inline-flex; gap: 4px; padding: 4px; border-radius: 999px; border: 1px solid var(--line); background: var(--ground-2); }
.seg-btn {
  display: inline-flex; align-items: center; gap: 7px; border: 1px solid transparent;
  background: none; border-radius: 999px; padding: 6px 13px; cursor: pointer;
  font-family: var(--sans); font-size: 13.5px; font-weight: 600; color: var(--cream-mut);
  transition: color var(--m-fast) ease, background var(--m-fast) ease, border-color var(--m-fast) ease;
}
.seg-btn:hover { color: var(--cream); }
.seg-btn.on { background: var(--gold-soft); border-color: var(--line-strong); color: var(--gold-hi); }
.seg-n { font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px; border: 1px solid var(--line); background: var(--ground-3); color: var(--cream-mut); font-variant-numeric: tabular-nums; }
.seg-btn.on .seg-n { background: none; border-color: var(--line-strong); color: var(--gold-hi); }

/* inline confirm bar — confirmations get a full-width row, never squeezed beside buttons */
.confirm-bar {
  display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; width: 100%;
  padding: 12px 14px; border-radius: var(--r);
  border: 1px solid var(--iron-line); background: var(--iron-bg);
  animation: fadeUp var(--m-quick) var(--e-settle);
}
.confirm-bar .cb-text { flex: 1 1 260px; min-width: 0; font-size: 13.5px; line-height: 1.45; color: var(--cream-dim); }
.confirm-bar .cb-text b, .confirm-bar .cb-text strong { color: var(--cream); font-weight: 700; }
.confirm-bar .cb-actions { display: flex; gap: 8px; margin-left: auto; flex: none; }
.confirm-bar.danger { border-color: rgba(176,65,58,0.45); background: var(--blood-bg); }

/* row list — Realms Past and any stacked record list */
.rowlist > :last-child { border-bottom: 0; }
.rowlist .group-head { display: flex; align-items: center; gap: 9px; padding: 18px 18px 9px; border-bottom: 1px solid var(--line); }
.rowlist .group-head .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.lrow { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; padding: 13px 18px; border-bottom: 1px solid var(--line); transition: background var(--m-fast) ease; }
.lrow:hover { background: rgba(236,206,133,0.025); }
.lrow-main { display: flex; align-items: center; gap: 14px; flex: 1 1 240px; min-width: 0; }
.lrow-title { display: flex; align-items: center; gap: 8px; min-width: 0; font-weight: 700; font-size: 15.5px; color: var(--cream); }
.lrow-title > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lrow-sub { display: flex; align-items: center; gap: 7px; margin-top: 3px; font-size: 12.5px; color: var(--cream-mut); }
.lrow-sub .dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.lrow-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; flex: none; }
.lrow-extra { flex-basis: 100%; min-width: 0; }
/* ENG-220 — the join band: connect address + join password as one full-width strip beneath a
   realm row. flex-basis:100% with NO max-width is what makes it a row of its own; the earlier
   inline max-width let each box shrink below full width, so the address floated up beside the
   action buttons and pushed the sub-line into a two-line wrap while the password dropped to
   the far left on its own. auto-fit puts the pair side by side when there is room and stacks
   them when there isn't. */
.joinband { flex-basis: 100%; min-width: 0; max-width: 860px; display: grid; gap: 12px 16px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.joinband .label { margin-bottom: 6px; }
.edit-ic { display: inline-grid; place-items: center; padding: 3px; border: 0; background: none; color: var(--cream-mut); cursor: pointer; border-radius: 6px; flex: none; }
.edit-ic:hover { color: var(--gold-hi); background: var(--gold-soft); }

/* list toolbar + pager */
.list-toolbar { display: flex; align-items: center; gap: 10px 12px; flex-wrap: wrap; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 18px; border-top: 1px solid var(--line); }
.pager .pg-info { font-size: 12.5px; color: var(--cream-mut); font-variant-numeric: tabular-nums; }
.pager .pg-btns { display: flex; gap: 6px; }

/* ============================================================
   Houses (ENG-126) — ported from the houses handoff's
   patterns-houses.css; kit chrome stripped, tokens shared.
   ============================================================ */

/* sigil mount */
.sigil { display: inline-grid; place-items: center; flex: none; line-height: 0; }
.sigil svg { display: block; filter: drop-shadow(0 2px 5px rgba(0,0,0,.35)); }

/* house tag — the struck code. Always uppercase, tabular, quiet. */
.tag-code { font-family: var(--sans); font-weight: 800; font-size: 12px; letter-spacing: .09em; text-transform: uppercase; font-variant-numeric: tabular-nums; color: var(--cream-dim); background: var(--ground-3); border: 1px solid var(--line); border-radius: 6px; padding: 3px 8px; white-space: nowrap; }
.on-parch .tag-code, .parch .tag-code { color: var(--ink-on-parch); background: rgba(43,36,23,.06); border-color: var(--parchment-ln); }

/* role pill */
.pill-role-leader { color: var(--gold-hi); background: var(--gold-soft); border-color: var(--line-strong); }

/* ENG-163: the Founding Steward title — same engraved gold as the leader pill, its own
   hook so the honor can diverge from the role without a template hunt */
.pill-title-founding { color: var(--gold-hi); background: var(--gold-soft); border-color: var(--line-strong); }

/* house index cards */
.house-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 18px; }
.house-card { display: flex; align-items: center; gap: 16px; padding: 20px; cursor: pointer; text-align: left; transition: border-color var(--m-fast) ease, background var(--m-fast) ease, transform var(--m-fast) ease; }
.house-card:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.house-card .hc-name { font-family: var(--display); font-weight: 600; font-size: 19px; color: var(--cream); }
.house-card .hc-sub { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 6px; font-size: 12.5px; color: var(--cream-mut); }

/* house detail header */
.house-head { display: flex; align-items: flex-start; gap: 22px; flex-wrap: wrap; margin-bottom: 26px; }
.house-head .hh-name { font-family: var(--display); font-weight: 600; font-size: 32px; color: var(--cream); letter-spacing: .01em; line-height: 1.1; }
.house-head .hh-desc { font-family: var(--serif); font-style: italic; font-size: 16.5px; color: var(--cream-dim); margin-top: 8px; max-width: 40em; }
.house-head .hh-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; flex: none; }
.crumb-back { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; color: var(--cream-mut); cursor: pointer; text-decoration: none; margin-bottom: 16px; }
.crumb-back:hover { color: var(--gold-hi); }
.crumb-back .flip { display: inline-flex; transform: rotate(180deg); }

/* who-pays line — the plain-register money fact, never flavored */
/* `white-space: nowrap` on a centred inline-flex overhangs SYMMETRICALLY — the box centres
   on its max-content width, so at 390px this lost the coin icon and the "$0." of "$0.15"
   off the left edge as well as "asleep" off the right, and read as "15 / hour · …". It is
   the first-run screen's only statement of the pricing model. Four independent clauses:
   let them wrap. Single call site (components/realm/FirstRunHouse.vue). */
.pays-line { display: inline-flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 7px; row-gap: 4px; font-size: 12.5px; color: var(--cream-mut); font-variant-numeric: tabular-nums; white-space: normal; }

/* parchment fact box inside modals (trust surface for money moments) */
.fact-parch { padding: 14px 18px; font-size: 14px; line-height: 1.55; color: var(--ink-on-parch); font-variant-numeric: tabular-nums; }
.fact-parch b { font-weight: 800; }

/* tag validation checklist (create step 2) */
.tagcheck { display: flex; flex-direction: column; gap: 7px; margin-top: 12px; }
.tc-row { display: flex; align-items: center; gap: 9px; font-size: 13.5px; color: var(--cream-mut); }
.tc-row .tc-ic { width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; border: 1px solid var(--line-strong); color: transparent; flex: none; transition: all var(--m-quick); }
.tc-row.ok { color: var(--cream-dim); }
.tc-row.ok .tc-ic { background: var(--pine-bg); border-color: var(--success-line); color: var(--pine); }
.tc-row.bad { color: var(--blood); }
.tc-row.bad .tc-ic { background: var(--blood-bg); border-color: var(--blood); color: var(--blood); }
.tc-row .tc-ic svg { width: 11px; height: 11px; }

/* sigil forge (create step 3) */
.forge { display: grid; grid-template-columns: 1fr auto; gap: 26px; align-items: start; }
.swatch-row { display: flex; gap: 9px; flex-wrap: wrap; }
.swatch { width: 40px; height: 40px; border-radius: 10px; border: 1px solid var(--line-strong); cursor: pointer; padding: 0; transition: all var(--m-fast); }
.swatch:hover { transform: translateY(-1px); }
.swatch.sel { border-color: var(--gold); box-shadow: var(--shadow-gold), 0 0 0 3px var(--gold-soft); }
.charge-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.charge-btn { display: grid; place-items: center; padding: 10px 6px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--ground-2); color: var(--cream-dim); cursor: pointer; transition: all var(--m-fast); }
.charge-btn:hover { border-color: var(--line-strong); color: var(--cream); }
.charge-btn.sel { border-color: var(--gold); color: var(--gold-hi); background: var(--gold-soft); }
.forge-preview { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 20px 26px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--ink); }
.forge-scales { display: flex; align-items: flex-end; gap: 18px; }
.forge-scales figure { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 7px; }
.forge-scales figcaption { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--cream-mut); }

/* the writ raven — email preview on parchment */
.writ-mail { padding: 24px 28px; font-size: 14.5px; line-height: 1.6; }
.writ-mail .wm-meta { font-size: 12px; color: var(--ink-on-parch-dim); display: flex; flex-direction: column; gap: 3px; padding-bottom: 14px; border-bottom: 1px solid var(--parchment-ln); margin-bottom: 16px; }
.writ-mail .wm-cta { display: inline-flex; margin: 14px 0 4px; }
.writ-mail .wm-fine { font-size: 12px; color: var(--ink-on-parch-dim); margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--parchment-ln); }

/* danger zone footer on the house page */
.danger-zone { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--line); }
.danger-zone .dz-note { font-size: 12.5px; color: var(--cream-mut); flex: 1 1 260px; min-width: 0; }

/* empty-section note inside a panel */
.panel-empty { padding: 26px 24px; text-align: center; }
.panel-empty .pe-steward { font-family: var(--serif); font-style: italic; font-size: 15.5px; color: var(--cream-dim); }
.panel-empty .pe-plain { font-size: 12.5px; color: var(--cream-mut); margin-top: 7px; }

@media (max-width: 860px) {
  .forge { grid-template-columns: 1fr; }
  .house-head .hh-actions { margin-left: 0; width: 100%; }
}

/* ============================================================
   TOUCH TARGETS (ENG-146)
   ============================================================
   Every control below measured under the 44px WCAG 2.5.5 / Apple HIG minimum in the
   2026-08-09 mobile audit. The fix expands the HIT AREA with a centred pseudo-element
   and leaves the painted box exactly as designed — so nothing reflows, nothing changes
   size, and no layout can overflow as a side effect. Resizing the boxes themselves would
   have meant re-tuning every dense row they sit in.

   Only the deficient axis is expanded. The icon buttons are square and short in both, so
   they get both; chips and link rows are wide enough already and only want height, which
   also avoids two neighbours' hit areas overlapping across a small gap.

   `inset: 50% auto auto 50%` + translate(-50%,-50%) centres the area on the control
   regardless of its painted size. A pseudo-element is part of its element for hit
   testing, so this is a real target, not a visual hint. */

.x-btn, .btn-icon, .topbar-home,
.chip, .tw-chip,
.mk-foot-in .row a, .mk-nav-links a, .gate-links a, .side-legal a { position: relative; }

/* square icon buttons — deficient on both axes (34x34 / 36x36) */
.x-btn::after, .btn-icon::after, .topbar-home::after {
  content: ""; position: absolute; inset: 50% auto auto 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}

/* wide but short — height only (chips 28-35px, link rows 16-19px). Expanding only the
   deficient axis also means horizontal neighbours in a row can never overlap. */
.chip::after, .tw-chip::after,
.mk-nav-links a::after, .gate-links a::after, .side-legal a::after {
  content: ""; position: absolute; inset: 50% auto auto 50%;
  width: 100%; height: 44px; transform: translate(-50%, -50%);
}

/* The footer link row is the one that WRAPS, so its hit areas stack vertically as well as
   sit side by side. At 18px links and a 10px row-gap the pitch is 28px, so a flat 44px
   area would overlap its neighbour above and below by 16px — and a tap in the gap would
   navigate to whichever happened to paint last. Overlapping targets are a worse bug than
   small ones. Widen the gap to 18px and match the area to the resulting 36px pitch: the
   areas then tile exactly, edge to edge, with nothing ambiguous between them. */
.mk-foot-in .row { row-gap: 18px; }
.mk-foot-in .row a::after {
  content: ""; position: absolute; inset: 50% auto auto 50%;
  width: 100%; height: 36px; transform: translate(-50%, -50%);
}

/* ============================================================
   The Founding Steward kit (design_handoff_founding_steward).
   One glyph per job: the flat seal stamp is the founder's mark everywhere;
   the numbered chip carries it in rows; the charm carries it where a chip
   won't fit; the engraved tab is the badge on the Steward's Desk; the writ
   is the certificate. The crown stays rank — the seal is provenance, and
   the two never combine.
   ============================================================ */

/* the flat seal stamp — a struck letter, not an icon. Sized by its own
   custom property so every mount (chip, charm, lore title, roll) is one rule. */
.seal-stamp {
  --seal: 15px;
  display: inline-grid; place-items: center; flex: none;
  width: var(--seal); height: var(--seal); border-radius: 50%;
  background: var(--gold); color: #241B08; line-height: 1;
  font-family: var(--display); font-weight: 700; font-size: calc(var(--seal) * 0.6);
}

/* the charm — the mark on an avatar's corner, ringed by the ground it sits on
   so it reads against any tone. .av-wrap is the mount. */
.av-wrap { position: relative; display: inline-flex; flex: none; }
.founding-charm {
  position: absolute; right: -3px; bottom: -3px;
  box-shadow: 0 0 0 2px var(--ground);
}

/* a founder's row, ennobled: a gold breath off the top edge, laid as
   background-image so it composites over whatever ground the row already has
   (the roll's rows are flat inside a panel, not standalone cards). Stays inside
   the one-gold-object budget because no Summon button shares these surfaces.
   The :hover rule repeats the image because .lrow:hover sets the background
   shorthand, which would otherwise wipe it. */
.founding-row {
  border-color: var(--line-strong);
  background-image: linear-gradient(180deg, rgba(203,163,92,.05), transparent 40%);
}
.founding-row:hover {
  background-color: rgba(236,206,133,0.025);
  background-image: linear-gradient(180deg, rgba(203,163,92,.05), transparent 40%);
}
/* the gold sub-line that replaces the chip in a dense row */
.founding-sub { color: var(--gold); }

/* the engraved tab — no fill, hairline and smallcaps. The profile badge. */
.founding-tab {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  padding: 5px 12px; background: none;
  font-family: var(--display); font-weight: 600; font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--gold);
}
.founding-tab svg { display: block; flex: none; }

/* the lore card — hover/focus on any mark. Fixed, and placed from the trigger's
   own rect on open, because these marks live inside rows and panels that clip:
   an absolutely-positioned card would be cut off on the one surface (the roll)
   where founders most want to read it. */
.founding-anchor { position: relative; display: inline-flex; }
.founding-trigger { cursor: help; }
.founding-trigger:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.founding-pop {
  display: block; position: fixed; z-index: 60;
  width: 300px; max-width: min(300px, calc(100vw - 24px));
}
/* spans throughout: the card is anchored inside inline content, so it may not
   introduce block elements */
.lore-card {
  display: block; text-align: left;
  background: linear-gradient(180deg, var(--ground-3), var(--ground-2));
  border: 1px solid var(--line-strong); border-radius: var(--r-lg);
  padding: 18px 20px; box-shadow: var(--shadow-card);
}
.lore-card .lc-title {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--display); font-weight: 600; font-size: 15px; color: var(--gold-hi);
}
.lore-card .lc-lore {
  display: block; margin-top: 9px; line-height: 1.45;
  font-family: var(--serif); font-style: italic; font-size: 14px; color: var(--cream-dim);
}
.lore-card .lc-plain {
  display: block; font-size: 12px; color: var(--cream-mut); line-height: 1.45;
  border-top: 1px solid var(--line); margin-top: 10px; padding-top: 10px;
}

/* the Founding Writ — parchment as the certificate, with its inner hairline */
.founding-writ {
  position: relative; text-align: center;
  background: linear-gradient(180deg, var(--parchment), var(--parchment-2));
  color: var(--ink-on-parch); border-radius: var(--r-lg);
  padding: 30px 34px 26px; box-shadow: var(--shadow-parch);
}
.founding-writ::before {
  content: ""; position: absolute; inset: 9px; pointer-events: none;
  border: 1px solid var(--parchment-ln); border-radius: 10px;
}
.founding-writ .fw-eyebrow {
  font-family: var(--sans); font-weight: 700; font-size: 10.5px;
  letter-spacing: .22em; text-transform: uppercase; color: var(--ink-on-parch-dim);
}
.founding-writ .fw-title {
  font-family: var(--display); font-weight: 700; font-size: 24px; margin: 8px 0 2px;
}
.founding-writ .fw-line {
  font-family: var(--serif); font-style: italic; font-size: 15.5px;
  color: var(--ink-on-parch-dim); margin: 6px 0 0; line-height: 1.5;
}
.founding-writ .fw-num {
  font-family: var(--display); font-weight: 700; font-size: 15px;
  letter-spacing: .08em; margin-top: 14px;
}
.founding-writ .fw-plain { font-size: 12px; color: var(--ink-on-parch-dim); margin-top: 14px; }
/* the wax — the one place the seal is struck rather than stamped flat */
.founding-writ .fw-wax {
  width: 52px; height: 52px; border-radius: 50%; margin: 16px auto 0;
  display: grid; place-items: center; color: #241B08;
  font-family: var(--display); font-weight: 700; font-size: 22px;
  background: radial-gradient(circle at 35% 30%, #D9BC77, #CBA35C 45%, #9C7B34 80%);
  box-shadow: var(--shadow-gold),
              inset 0 2px 3px rgba(255,255,255,.35),
              inset 0 -3px 5px rgba(0,0,0,.3);
}

@media (max-width: 560px) {
  .founding-writ { padding: 24px 20px 22px; }
  .founding-writ .fw-title { font-size: 21px; }
  .founding-writ .fw-line { font-size: 14.5px; }
}

/* ============================================================
   SUMMON PROGRESS PANEL (frame 3a) + STAMP LOADER (frame 1a)
   binding spec: docs/handoff/design_handoff_summon_progress/
   ============================================================ */
/* The Realm-page host for an in-flight summon — the handoff's container spec: a padded
   panel at ~660px max content width. Unconstrained it stretched to the full page column,
   leaving the ledger, log, and footer looking sparse. margin-bottom matches .server-card. */
.summon-live{max-width:660px;padding:24px 26px;margin-bottom:26px}
.sm-head{display:flex;align-items:baseline;gap:10px;margin:0 0 14px;text-align:left}
.sm-head h3{font-family:var(--display);font-weight:600;font-size:17px;margin:0;color:var(--cream)}
.sm-elapsed{margin-left:auto;font-size:12px;color:var(--cream-mut);font-variant-numeric:tabular-nums}
.sm-grid{display:grid;grid-template-columns:190px 1fr;gap:18px;align-items:stretch;text-align:left}
.sm-stagebox{border:1px solid var(--line);border-radius:var(--r);background:var(--ground-2);position:relative;overflow:hidden;min-height:230px}
.sm-stages{display:grid;gap:0;margin:0;padding:0;list-style:none}
.sm-st{display:grid;grid-template-columns:18px 1fr;gap:12px;padding:11px 0;border-bottom:1px solid var(--line)}
.sm-st:last-child{border-bottom:none}
.sm-dot{width:16px;height:16px;border-radius:50%;border:1.5px solid var(--line-strong);margin-top:1px;position:relative}
.sm-st.done .sm-dot{background:var(--pine);border-color:var(--pine)}
.sm-st.done .sm-dot::after{content:"";position:absolute;left:4.5px;top:2px;width:4px;height:7px;border:solid #14120C;border-width:0 2px 2px 0;transform:rotate(40deg)}
.sm-st.cur .sm-dot{border-color:var(--gold);box-shadow:0 0 0 3px rgba(203,163,92,.15);animation:smDotPulse 1.8s ease-in-out infinite}
@keyframes smDotPulse{0%,100%{box-shadow:0 0 0 3px rgba(203,163,92,.12)}50%{box-shadow:0 0 0 5px rgba(203,163,92,.28)}}
.sm-st .t1{font-weight:700;font-size:13.5px;color:var(--cream-mut)}
.sm-st.done .t1{color:var(--cream-dim)}
.sm-st.cur .t1{color:var(--cream)}
.sm-st .t2{font-size:11.5px;color:var(--cream-mut);margin-top:2px;font-variant-numeric:tabular-nums}
.sm-bar{height:4px;border-radius:999px;background:var(--ground-3);margin-top:7px;overflow:hidden;position:relative}
.sm-bar::after{content:"";position:absolute;top:0;bottom:0;left:-40%;width:40%;border-radius:999px;background:linear-gradient(90deg,transparent,var(--gold),transparent);animation:smBar 2.2s var(--e-inout) infinite}
@keyframes smBar{0%{left:-40%}100%{left:100%}}
.sm-stall{margin-top:10px;padding:9px 12px;border:1px solid var(--iron-line);border-radius:var(--r-sm);background:var(--iron-bg);font-size:12px;color:var(--iron-hi);text-align:left;animation:fadeUp var(--m-move) var(--e-inout)}
.sm-note{font-size:12.5px;color:var(--cream-mut);text-align:center;margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.sm-foot{display:flex;align-items:center;gap:12px;margin-top:14px;padding-top:12px;border-top:1px solid var(--line);text-align:left}
.sm-foot .steward{font-family:var(--serif);font-style:italic;font-size:13.5px;color:var(--cream-dim)}
.sm-notify{margin-left:auto;flex:none}
.sm-horn{margin-left:auto;flex:none;font-size:12px;color:var(--cream-mut)}
.sm-log{border:1px solid var(--line);border-radius:var(--r);background:var(--ground-2);margin-top:14px;padding:10px 14px;height:78px;overflow:hidden;position:relative;text-align:left}
.sm-log::before{content:"";position:absolute;inset:0 0 auto;height:22px;background:linear-gradient(180deg,var(--ground-2),transparent);z-index:2;pointer-events:none}
.sm-logroll{display:grid;gap:5px;align-content:end;min-height:100%}
.sm-line{font-size:11.5px;color:var(--cream-mut);display:flex;gap:10px;font-variant-numeric:tabular-nums;height:16px;animation:fadeUp var(--m-quick) var(--e-inout)}
.sm-line b{color:var(--cream-dim);font-weight:600}
.sm-line .tt{color:var(--cream-mut);opacity:.7;flex:none}
@media (max-width:540px){ .sm-grid{grid-template-columns:1fr} .sm-stagebox{min-height:190px} }

/* stamp loader — 1a "Sealing the Writ"; fills a positioned parent, bottom-anchored, 3.4s cycle */
.stamp-scene{position:absolute;inset:0;transform:scale(.78);transform-origin:50% 100%}
.stamp-sheet{position:absolute;left:50%;bottom:34px;width:190px;height:118px;margin-left:-95px;background:linear-gradient(180deg,#F6EDD8,var(--parchment));border-radius:3px;box-shadow:var(--shadow-parch);animation:stampSheet 3.4s var(--e-inout) infinite}
.stamp-lines{position:absolute;left:20px;right:20px;top:18px;height:44px;background:repeating-linear-gradient(180deg,rgba(43,36,23,.28) 0 1.5px,transparent 1.5px 11px)}
.stamp-sig{position:absolute;left:20px;bottom:16px;width:64px;height:2px;background:rgba(43,36,23,.35)}
.stamp-imp{position:absolute;right:16px;bottom:12px;width:46px;height:46px;animation:stampImp 3.4s var(--e-inout) infinite;filter:drop-shadow(0 1px 2px rgba(43,36,23,.35))}
.stamp-tool{position:absolute;left:50%;bottom:60px;width:56px;margin-left:28px;display:grid;justify-items:center;animation:stampDrop 3.4s cubic-bezier(.55,0,.6,1.4) infinite;z-index:3}
.stamp-knob{width:20px;height:20px;border-radius:50%;background:radial-gradient(circle at 35% 30%,#5b4e35,#332b1d 70%);border:1px solid #6a5a3c}
.stamp-shaft{width:9px;height:24px;background:linear-gradient(90deg,#2e2719,#4a3f2a,#2e2719)}
.stamp-base{width:52px;height:13px;border-radius:4px 4px 2px 2px;background:linear-gradient(180deg,var(--gold-hi),var(--gold) 55%,#8A6A2C);box-shadow:inset 0 1px 0 rgba(255,255,255,.35)}
.stamp-die{width:44px;height:5px;border-radius:0 0 3px 3px;background:#8A6A2C}
.stamp-flash{position:absolute;left:50%;bottom:44px;width:120px;height:60px;margin-left:-4px;border-radius:50%;background:radial-gradient(closest-side,rgba(236,206,133,.85),transparent 70%);opacity:0;animation:stampFlash 3.4s ease-out infinite;z-index:2}
.stamp-ring{position:absolute;left:50%;bottom:46px;width:56px;height:56px;margin-left:28px;border-radius:50%;border:2px solid rgba(236,206,133,.7);opacity:0;animation:stampRing 3.4s ease-out infinite;z-index:2}
.stamp-dust{position:absolute;left:50%;bottom:66px;width:4px;height:4px;margin-left:54px;border-radius:50%;background:var(--gold-hi);opacity:0;animation:stampDust 3.4s ease-out infinite;z-index:4}
@keyframes stampSheet{0%{transform:translateX(160px);opacity:0}10%,86%{transform:translateX(0);opacity:1}96%,100%{transform:translateX(-190px);opacity:0}}
@keyframes stampDrop{0%,16%{transform:translateY(-116px)}26%{transform:translateY(0)}30%{transform:translateY(4px) scaleY(.93)}44%,100%{transform:translateY(-116px)}}
@keyframes stampImp{0%,27%{opacity:0;transform:scale(1.5)}31%{opacity:1;transform:scale(.96)}34%,100%{opacity:1;transform:scale(1)}}
@keyframes stampFlash{0%,26%{opacity:0}29%{opacity:1}42%,100%{opacity:0}}
@keyframes stampRing{0%,27%{opacity:0;transform:scale(.4)}30%{opacity:.9}52%,100%{opacity:0;transform:scale(1.9)}}
@keyframes stampDust{0%,27%{transform:translate(0,0) scale(1);opacity:0}30%{opacity:1}52%,100%{transform:translate(var(--dx),var(--dy)) scale(.3);opacity:0}}
@media (prefers-reduced-motion: reduce){
  .stamp-scene *,.sm-st.cur .sm-dot,.sm-bar::after,.sm-stall,.sm-line{animation:none!important}
  .stamp-sheet{transform:none;opacity:1}
  .stamp-imp{opacity:1;transform:scale(1)}
  .stamp-tool{transform:translateY(-116px)}
  .stamp-flash,.stamp-ring,.stamp-dust{display:none}
}
