/* Granado Espada — private server portal. Fonts are local so CSP and visitors'
   privacy do not depend on a third-party stylesheet. */
@font-face{
  font-family:'Cormorant Garamond';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('/assets/fonts/cormorant-garamond-latin.woff2') format('woff2');
}
@font-face{
  font-family:'Inter';font-style:normal;font-weight:100 900;font-display:swap;
  src:url('/assets/fonts/inter-latin.woff2') format('woff2');
}

:root{
  --bg:#05091a; --bg2:#0a1330; --panel:#0d1836cc; --panel-solid:#0d1836;
  --gold:#e7c979; --gold-2:#c9a24a; --ink:#eaf0ff; --muted:#9fb0d6;
  --line:#26365f; --accent:#6ec3ff; --danger:#ff6b6b; --ok:#5cd6a0;
  --serif:'Cormorant Garamond',Georgia,'Times New Roman',serif;
  --serif2:'Cormorant Garamond',Georgia,serif;
  --sans:'Inter','Segoe UI',Arial,'Microsoft YaHei',sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
  min-height:100vh;color:var(--ink);background:var(--bg);font-family:var(--sans);
  line-height:1.6;-webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
h1,h2,h3{font-family:var(--serif);font-weight:700;letter-spacing:.04em;line-height:1.15}

/* ---- top nav ---- */
.nav{
  position:fixed;inset:0 0 auto 0;z-index:50;display:flex;align-items:center;
  justify-content:space-between;height:76px;padding:0 clamp(20px,5vw,64px);
  background:linear-gradient(180deg,rgba(5,9,26,.92),rgba(5,9,26,0));
  transition:background .3s;
}
.nav.solid{background:rgba(5,9,26,.96);border-bottom:1px solid #1c2a4d;box-shadow:0 6px 30px #0008}
.brand{display:flex;align-items:center;gap:12px;font-family:var(--serif);font-weight:900;
  font-size:22px;letter-spacing:.14em;color:var(--gold);text-shadow:0 2px 12px #000a}
.brand .mark{width:34px;height:34px;border:2px solid var(--gold);transform:rotate(45deg);
  display:grid;place-items:center}
.brand .mark::after{content:"";width:12px;height:12px;background:var(--gold);transform:rotate(0)}
.brand small{font-family:var(--sans);font-weight:600;font-size:11px;letter-spacing:.32em;
  color:var(--muted);display:block;margin-top:2px}
.menu{display:flex;align-items:center;gap:clamp(14px,2vw,34px)}
.menu a{font-size:14px;letter-spacing:.14em;text-transform:uppercase;color:#cdd8f5;
  padding:8px 2px;position:relative;transition:color .2s}
.menu a:hover,.menu a.active{color:var(--gold)}
.menu a::after{content:"";position:absolute;left:0;right:100%;bottom:0;height:2px;
  background:var(--gold);transition:right .25s}
.menu a:hover::after,.menu a.active::after{right:0}

/* ---- buttons ---- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  font-family:var(--serif);font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  font-size:14px;padding:13px 30px;color:#1a1305;cursor:pointer;border:0;position:relative;
  background:linear-gradient(180deg,#f4dc94,#c9a24a);
  clip-path:polygon(10px 0,100% 0,calc(100% - 10px) 100%,0 100%);
  box-shadow:0 6px 22px #0007, inset 0 1px 0 #fff8;transition:transform .12s,filter .2s}
.btn:hover{filter:brightness(1.08);transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
.btn.ghost{background:transparent;color:var(--gold);border:1px solid var(--gold-2);
  clip-path:none;box-shadow:none}
.btn.ghost:hover{background:#e7c9791a}
/* clip-path cuts the UA focus ring off with everything else outside the border
   box, so the ring is drawn inside instead (the same treatment .ledger uses). */
.btn:focus-visible{outline:0;box-shadow:inset 0 0 0 2px #1a1305,inset 0 0 0 4px var(--gold)}
.btn.ghost:focus-visible{outline:2px solid var(--gold);outline-offset:2px;box-shadow:none}

/* ---- nav chips: hover must not composite a hairline ---- */
/* .btn:hover lifts and filters, and either one gives the chip its own
   composited layer. These chips sit at fractional coordinates in the flex row
   (measured on the live nav: x .83, y .5), and a composited layer is snapped to
   whole device pixels - so their 1px border falls partly outside the snapped
   texture and the box comes apart on hover, worst at 125%/150% Windows display
   scaling. A 38px chip does not need a lift; colour is the feedback instead.
   The filled buttons keep the lift: they have a background, so their layer edge
   has no hairline to lose. */
.nav .menu .btn:hover,.nav .menu .btn:active{transform:none;filter:none}
.nav .menu .btn.ghost:hover{background:#e7c97926}
@media (min-width:901px){
  /* Below 901px the chip is a drawer row with border:0 and a bottom divider -
     see the .nav.nav-ready block - and that divider is not ours to recolour. */
  .nav .menu .btn.ghost:hover{border-color:var(--gold)}
}
.btn.lg{font-size:16px;padding:17px 44px}

/* ---- hero ---- */
/* Full height, by the owner's choice between the two variants he was shown. It
   costs the fold: every checkable fact on this page starts below it, which is why
   the scroll cue further down is not optional here. The crop, the veil and the
   >=1500px overrides below are tuned to this footage and are NOT touched. */
.hero{position:relative;height:100vh;min-height:640px;overflow:hidden;background:#04091b}
/* The source footage is the Chinese promo: heavy 封神 calligraphy fills its left
   third. object-fit:cover on a wide screen reveals MORE of that side, so bias the
   crop toward the character and let the veil below fade what remains.

   Y STAYS AT center, and that is a consequence of the height above, not an
   oversight. cover() scales by whichever axis needs it most: with height:100vh
   the box is taller than 9:16-of-its-width on nearly every window, so the HEIGHT
   drives the scale and almost nothing is lost off the top — recomputed against
   the 1920x1080 source, the top loss is 0.6% at 1440x800, 7.7% at 1366x650 and
   8.5% at 1499x700, all inside the band the 404 page was signed off on. The head
   sits at 14-20% of frame height (measured off four extracted frames) and is
   never reached.

   A SHORTER hero would be width-driven and would need Y lifted to about 28%.
   That variant was shown to the owner and rejected. Do not import its numbers. */
.hero video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:62% center}
.hero .veil{position:absolute;inset:0;background:
  /* Left wash: kills the Chinese calligraphy that fills the left of the frame.
     Matched to the 404 page's, which is the reference for how open this should be. */
  linear-gradient(90deg,#05091ae6 0,#05091ab8 24%,#05091a66 42%,#05091a26 62%,#05091a0d 100%),
  /* A soft pool behind the copy only. The 404 page needs nothing like this
     because its text sits inside a glass card that darkens its own backdrop;
     here the 96px title is painted straight onto the picture, so without some
     shade behind it white lands on orange flame. Half the strength of the old
     full-frame radial, and it no longer reaches the edges. */
  radial-gradient(64% 52% at 50% 46%,#05091a5c 0,#05091a26 58%,transparent 100%),
  /* Top and bottom, so the frame meets the fixed nav and the page below cleanly. */
  linear-gradient(180deg,#05091a99 0,transparent 26%,transparent 72%,#05091a 98%)}
.hero-inner{position:relative;z-index:2;height:100%;display:flex;flex-direction:column;
  align-items:center;justify-content:center;text-align:center;padding:0 20px}
.hero h1{font-size:clamp(40px,7vw,96px);font-weight:900;color:#fff;
  letter-spacing:.06em;
  /* rim, halo, pool - see the note above; the blue is the original accent glow */
  text-shadow:0 2px 5px #000000d9, 0 6px 22px #000000e6, 0 0 64px #000000bf,
              0 0 70px #6ec3ff33}
.hero h1 .sub{display:block;font-family:var(--serif2);font-weight:400;
  font-size:clamp(15px,2vw,24px);letter-spacing:.5em;color:var(--gold);
  margin-top:14px;text-transform:uppercase;
  text-shadow:0 1px 3px #000000d9, 0 3px 14px #000000e6, 0 0 34px #000000b3}
.hero .tag{margin:26px auto 34px;max-width:620px;color:#dbe6ff;font-size:clamp(15px,1.4vw,18px);
  text-shadow:0 1px 3px #000000d9, 0 3px 14px #000000e6, 0 0 30px #000000b3}
.hero .cta{display:flex;gap:16px;flex-wrap:wrap;justify-content:center}
/* Gold on transparent, directly over the brightest part of the frame. The filled
   button carries its own gradient and needs none of this. */
.hero .btn.ghost{background:#05091a8c;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  text-shadow:0 1px 3px #000000b3}
.hero .btn.ghost:hover{background:#0b1633b3}
.hero .btn:not(.ghost){box-shadow:0 6px 22px #000000a6, inset 0 1px 0 #ffffff8c}
/* The cue earns its place again: with a 100vh hero the next section starts at
   exactly the fold, so without it the first screen gives no sign the page goes on.
   It is a flow item inside .herofoot, which owns the bottom edge — the 18px bottom
   margin is the whole of its positioning, and it therefore clears the bar whatever
   height the bar happens to have. It was written with a constant first and that
   constant was wrong at every width below 900px, where the bar becomes two rows.
   The animation is opt-in, so a visitor who asked for less motion gets a static mark.

   Hidden by DEFAULT and switched on only where it fits. Measured: below 700px of
   viewport height the cue lands on the Download button (18-28px into it), and on
   a 360px phone the gap between the buttons and the bar is 32px against a 61px
   cue - there is no position for it. Those sizes do not need it: the bar is
   itself cut by the fold there, which says the same thing. The height gate is 740
   and not 700 because the clearance from the buttons grows by half a pixel per pixel
   of viewport height: measured 1px at 700 and 21px at 740. 1px reads as a collision. */
.scrollcue{display:none;align-self:center;margin:0 0 18px;
  color:var(--gold);font-size:12px;letter-spacing:.3em;text-transform:uppercase;
  text-decoration:none;opacity:.85}
@media (min-width:901px) and (min-height:740px){.scrollcue{display:block}}
.scrollcue:hover,.scrollcue:focus-visible{opacity:1}
.scrollcue::after{content:"";display:block;width:1px;height:34px;margin:8px auto 0;
  background:linear-gradient(#e7c979,transparent)}
@media (prefers-reduced-motion:no-preference){
  .scrollcue{animation:bob 1.8s ease-in-out infinite}
}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(8px)}}

/* ---- generic section ---- */
.section{position:relative;padding:clamp(60px,9vw,120px) clamp(20px,6vw,80px)}
.section.stars{background:
  radial-gradient(60% 50% at 80% 20%,#132a5e55,transparent 70%),
  radial-gradient(50% 50% at 15% 80%,#1b1b4a55,transparent 70%),var(--bg)}
.wrap{max-width:1240px;margin:0 auto}
.eyebrow{display:inline-block;font-size:12px;letter-spacing:.4em;text-transform:uppercase;
  color:var(--gold);border:1px solid #e7c97944;padding:6px 16px;border-radius:2px;margin-bottom:18px}
.section h2{font-size:clamp(28px,4vw,46px);color:#fff;margin-bottom:16px}
.section .lead{color:var(--muted);max-width:640px;font-size:17px}
.grid{display:grid;gap:24px;margin-top:44px}
.grid.g3{grid-template-columns:repeat(3,1fr)}
.feature{background:var(--panel);border:1px solid #22315a;
  border-radius:12px;padding:30px 26px;backdrop-filter:blur(4px);transition:transform .2s,border-color .2s}
.feature:hover{transform:translateY(-5px);border-color:var(--gold-2)}
/* .feature .ic / .feature .ic b removed with the homepage's three Unicode glyphs
   (star, crossed swords, chess queen). The cards now carry Cinzel numerals in an
   octagon frame — see .cardnum at the end of this file. The rotated-square frame
   is left to .brand .mark alone. */
.feature h3{font-size:20px;color:var(--gold);margin-bottom:10px;letter-spacing:.06em}
.feature p{color:var(--muted);font-size:15px}

/* The .banner Get Started box is gone, and with it the only use of
   /assets/index.jpg as a decorative panel. The file itself STAYS on disk:
   .auth-page::before below uses it on register and login. */

/* ---- footer ---- */
.foot{background:#04081a;border-top:1px solid #1a294d;
  padding:46px clamp(20px,6vw,80px);color:var(--muted);font-size:13px}
.foot .wrap{display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap;align-items:center}
.foot .brand{font-size:16px}
.foot .disc{max-width:620px;line-height:1.7;font-size:12px;color:#6c7ba3}

/* ---- auth (register/login) ---- */
.auth-page{min-height:100vh;display:grid;place-items:center;padding:110px 20px 60px;position:relative;
  background:linear-gradient(180deg,#05091a 0,#0a1330 100%)}
.auth-page::before{content:"";position:absolute;inset:0;
  background:url('/assets/index.jpg') top center/cover no-repeat;opacity:.28;
  -webkit-mask-image:linear-gradient(180deg,#000 0,transparent 85%);mask-image:linear-gradient(180deg,#000 0,transparent 85%)}
.card{position:relative;width:min(480px,100%);background:var(--panel-solid);
  border:1px solid #2b3d6b;border-radius:16px;padding:clamp(30px,4vw,46px);
  box-shadow:0 30px 80px #000a,inset 0 1px 0 #ffffff12}
.card::before,.card::after{content:"";position:absolute;width:20px;height:20px;border:2px solid var(--gold-2)}
.card::before{top:12px;left:12px;border-right:0;border-bottom:0}
.card::after{bottom:12px;right:12px;border-left:0;border-top:0}
.card h1{font-size:30px;color:var(--gold);text-align:center;letter-spacing:.08em}
.card .sub{text-align:center;color:var(--muted);font-size:14px;margin:8px 0 30px}
.field{margin-bottom:18px}
.field label{display:block;font-size:12px;letter-spacing:.18em;text-transform:uppercase;
  color:#b9c6ea;margin-bottom:8px}
.field input{width:100%;height:50px;padding:0 16px;color:#fff;font-size:16px;
  background:#0a1230;border:1px solid #2b3d6b;border-radius:8px;transition:border-color .2s,box-shadow .2s}
.field input:focus{outline:0;border-color:var(--gold-2);box-shadow:0 0 0 3px #e7c9791f}
.field .hint{font-size:13px;color:var(--muted);margin-top:6px}
.consent-field{display:grid;grid-template-columns:18px minmax(0,1fr);gap:10px;align-items:start;margin:2px 0 18px}
.consent-field input{width:18px;height:18px;margin:1px 0 0;accent-color:var(--gold-2)}
.consent-field label{color:#aebbdc;font-size:12px;line-height:1.55}
.consent-field a{color:var(--gold);text-decoration:underline;text-decoration-color:#e7c97966;text-underline-offset:3px}
.consent-field a:hover{color:var(--gold-2)}
.consent-field input:focus-visible{outline:2px solid var(--gold-2);outline-offset:3px}
.card .btn{width:100%;margin-top:8px}
.card .alt{text-align:center;margin-top:20px;font-size:14px;color:var(--muted)}
.card .alt a{color:var(--gold)}
.msg{border-radius:8px;padding:12px 16px;font-size:14px;margin-bottom:18px;display:none}
.msg.show{display:block}
.msg.err{background:#3a12124d;border:1px solid #ff6b6b55;color:#ffb3b3}
.msg.ok{background:#0e3a2a4d;border:1px solid #5cd6a055;color:#a9f0d1}
.strength{height:4px;border-radius:3px;background:#22315a;margin-top:8px;overflow:hidden}
.strength i{display:block;height:100%;width:0;background:var(--danger);transition:width .3s,background .3s}
.steps{list-style:none;margin:6px 0 28px;padding:0}
.steps li{color:#c8d4f2;font-size:15px;padding:11px 0;border-bottom:1px solid #1b2a4d}
.steps li:last-child{border-bottom:0}
.steps li b{color:var(--gold);margin-right:8px}
code{background:#0a1230;border:1px solid #2b3d6b;border-radius:5px;padding:1px 7px;
  font-family:Consolas,monospace;font-size:13px;color:var(--gold)}

/* ---- content page (rankings etc.) ---- */
.page{min-height:100vh;padding:120px clamp(20px,6vw,80px) 80px;
  background:radial-gradient(70% 60% at 80% 0,#132a5e40,transparent 70%),var(--bg)}
.page-h1{font-size:clamp(30px,5vw,52px);color:#fff;margin:6px 0 26px;overflow-wrap:anywhere}
.statstrip{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:34px}
.statstrip div{background:var(--panel);border:1px solid #22315a;border-radius:12px;
  padding:20px;text-align:center}
.statstrip b{display:block;font-family:var(--serif);font-size:clamp(22px,3vw,34px);color:var(--gold)}
.statstrip span{font-size:12px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.tabs{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:22px;border-bottom:1px solid #22315a}
.tabs a{padding:12px 22px;font-family:var(--serif);font-size:14px;letter-spacing:.1em;
  text-transform:uppercase;color:#b9c6ea;border-bottom:2px solid transparent;margin-bottom:-1px}
.tabs a:hover{color:var(--gold)}
.tabs a.on{color:var(--gold);border-bottom-color:var(--gold)}
.tablewrap{overflow-x:auto}
.ranks{width:100%;border-collapse:collapse;min-width:520px}
.ranks th,.ranks td{padding:13px 16px;text-align:left;border-bottom:1px solid #1b2a4d}
.ranks th{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);font-weight:600}
.ranks td.rk,.ranks th.rk{width:56px;text-align:center;color:var(--muted);font-family:var(--serif)}
.ranks td.num,.ranks th.num{text-align:right;font-variant-numeric:tabular-nums}
.ranks td.nm{color:var(--gold);font-weight:600}
.ranks tbody tr:hover{background:#0e1a3a}
.ranks tr.top td.rk{color:var(--gold);font-weight:700}
.ranks tr.top td.nm{color:#fff}

/* ---- server status pill ---- */
.status-pill{display:inline-flex;align-items:center;gap:9px;margin-bottom:22px;
  padding:8px 18px;border-radius:40px;font-size:13px;letter-spacing:.12em;text-transform:uppercase;
  background:#05091abb;border:1px solid #2b3d6b;color:#dbe6ff;backdrop-filter:blur(4px)}
.status-pill .dot{width:9px;height:9px;border-radius:50%;background:var(--ok);
  box-shadow:0 0 10px var(--ok)}
.status-pill.down .dot{background:var(--danger);box-shadow:0 0 10px var(--danger)}
.status-pill em{font-style:normal;color:var(--gold);margin-left:4px}
.section.slim{padding-top:clamp(40px,6vw,70px);padding-bottom:0}

/* ---- news ---- */
.newsgrid{margin-top:34px}
.newscard{display:block;background:var(--panel);border:1px solid #22315a;border-radius:12px;
  padding:24px;transition:transform .2s,border-color .2s}
.newscard:hover{transform:translateY(-5px);border-color:var(--gold-2)}
.newscard h3{color:var(--gold);font-size:19px;margin:12px 0 8px;letter-spacing:.04em}
.newscard p{color:var(--muted);font-size:14px}
.meta{display:flex;align-items:center;gap:12px;font-size:12px;color:var(--muted)}
.meta .cat{letter-spacing:.14em;text-transform:uppercase;color:var(--gold);
  border:1px solid #e7c97944;padding:3px 10px;border-radius:3px;font-size:11px}
.meta .cat-update{color:var(--accent);border-color:#6ec3ff44}
.meta .cat-event{color:#ff9ecb;border-color:#ff9ecb44}
.meta .cat-maintenance{color:var(--danger);border-color:#ff6b6b44}
.wrap.narrow{max-width:820px}
.newsitem{border-bottom:1px solid #1b2a4d;padding:28px 0}
.newsitem:last-child{border-bottom:0}
.newsitem h2{color:#fff;font-size:24px;margin:10px 0;overflow-wrap:anywhere}
.newsitem .body{color:#c8d4f2;line-height:1.8}

/* ---- news, rebuilt module ----
   The chips are a CLOSED set of four: lib/news.php only ever emits cat-news,
   cat-update, cat-event or cat-maintenance, so a GM cannot invent a class here.
   cat-news was the one that had no rule and fell through to the bare .cat. */
.cat-news{color:var(--gold);border-color:#e7c97944}
.cat.pin{color:var(--gold-2);border-color:#c9a24a55;background:#c9a24a14}
/* The card grid follows the item count so one or two items do not leave holes. */
.grid.g1{grid-template-columns:1fr}
.grid.g2{grid-template-columns:repeat(2,1fr)}
@media(max-width:900px){.grid.g2{grid-template-columns:1fr}}
.newsitem.is-pinned{border-left:2px solid var(--gold-2);padding-left:18px;margin-left:-20px}
.newsitem h2 a:hover{color:var(--gold)}
.newsitem .body a{color:var(--accent)}
.newsitem .body a:hover{color:var(--gold)}
.newsitem .body p{margin:0 0 14px}
.newsitem .body p:last-child{margin-bottom:0}
.newsitem .body h3{color:var(--gold);font-size:19px;margin:24px 0 10px;letter-spacing:.04em}
.newsitem .body ul{margin:0 0 14px;padding-left:22px;list-style:disc}
.newsitem .body li{margin:4px 0}
.newsitem .body strong{color:#eef3ff}
.readmore{color:var(--gold);font-size:14px;letter-spacing:.04em}
.readmore:hover{color:var(--gold-2)}
.newsimg{max-width:100%;border-radius:12px;border:1px solid #22315a;margin:18px 0}
.news-pager{display:flex;gap:14px;align-items:center;margin-top:34px}
/* Scroll target for the legacy /news.php#YYYY-MM-DD links. The offset clears the
   76px fixed nav, which would otherwise cover the heading it jumped to. */
.anchor{display:block;position:relative;top:-90px;visibility:hidden}

/* ---- account panel ---- */
.panelgrid{display:grid;grid-template-columns:1.5fr 1fr;gap:24px;align-items:start}
.pcard{background:var(--panel);border:1px solid #22315a;border-radius:14px;padding:26px 24px}
.pcard h2{font-size:20px;color:var(--gold);margin-bottom:16px;letter-spacing:.05em}
.pcard .sub2{font-size:12px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);
  margin:20px 0 8px}
.pcard .field input{background:#0a1230}
.muted{color:var(--muted);font-size:15px}

@media(max-width:900px){
  .grid.g3{grid-template-columns:1fr}
  .menu{gap:14px}.menu a{font-size:12px}
  .brand{font-size:18px}
  .statstrip{grid-template-columns:repeat(2,1fr)}
  .panelgrid{grid-template-columns:1fr}
}

/* =========================================================================
   LARGE / ULTRAWIDE SCREENS

   Geometry note: the hero video is 1920x1080 (1.78) and a wide window is ~2.7:1.
   cover() therefore scales the video to match the WIDTH, so nothing is cropped
   horizontally - only top and bottom. That means:
     * object-position's X value is a NO-OP here; only the Y value matters.
     * the Chinese calligraphy cannot be cropped away, it can only be veiled.
   The character's head sits high in the frame, so Y must be well above centre
   or she gets decapitated by the crop + the 76px nav.

   Copy stays centred (owner's call); a soft scrim sits behind it so it reads
   over the artwork without washing the character out.
   ========================================================================= */
@media (min-width:1500px){
  /* 26%, tuned for this 100vh box. On the owner's 3440x1440 the frame is scaled
     to 3440x1935 and the box keeps 1440 of it, so the lift is what centres the
     character rather than the calligraphy. A previous draft of this comment
     prescribed 13% — that was for the clamped hero, which was rejected. */
  .hero video{object-position:50% 26%}

  .hero .veil{background:
    /* Scrim behind the centred copy. Kept, because unlike the 404 page the hero
       has no panel under its 88px title — but at about half the old strength and
       pulled in tight, so it shades the words and not the character. */
    radial-gradient(38% 46% at 50% 46%,#05091a5c 0,#05091a26 58%,transparent 86%),
    /* Mute the calligraphy on the left; release sooner than before so the flames
       on that side are not flattened along with it. */
    linear-gradient(90deg,#05091ac9 0,#05091a5c 24%,#05091a1f 40%,transparent 56%),
    /* Top and bottom fades: nav legibility, and a clean join to the next section. */
    linear-gradient(180deg,#05091ab3 0,transparent 24%,transparent 74%,#05091a 98%)}

  .hero-inner{align-items:center;text-align:center;padding:0 clamp(40px,5vw,80px)}
  .hero h1{font-size:clamp(64px,4.8vw,88px);letter-spacing:.05em}
  .hero h1 .sub{font-size:22px;letter-spacing:.46em;margin-top:16px}
  .hero .tag{margin:24px auto 32px;max-width:660px;font-size:18px;line-height:1.75}
  .hero .cta{justify-content:center;gap:20px}
  .btn.lg{padding:0 44px;height:56px;font-size:15px}

  .wrap{max-width:1440px}
  .section .lead{max-width:780px;font-size:18px}
  .section{padding:clamp(90px,7vw,140px) clamp(40px,5vw,90px)}
}

@media (min-width:1900px){
  .wrap{max-width:1600px}
  .hero .tag{max-width:700px}
}

/* Wide but SHORT windows lose the most height to the crop, so lift the frame
   further and stop the hero from occupying an absurd amount of screen. */
@media (min-width:1500px) and (max-height:900px){
  /* Capped at 820px: on a wide, short window a full-height hero would take the
     whole screen precisely where there is least of it, so the cap keeps the truth
     bar and the top of the next section in view. */
  .hero{height:min(100vh,820px);min-height:560px}
  /* One step less lift than the block above, because the cap makes this case
     partly width-driven again. A previous draft prescribed 11%; that belonged to
     the rejected clamped hero. */
  .hero video{object-position:50% 21%}
  .hero h1{font-size:clamp(56px,4.2vw,76px)}
  .hero .tag{margin:20px auto 26px;font-size:17px}
}

/* ---- Download page -------------------------------------------------------
   Only what the existing components do not already cover. Layout, cards and
   stats come from .section/.wrap/.panelgrid/.pcard/.statstrip/.btn. */
.dlcta{display:flex;gap:14px;flex-wrap:wrap;margin-top:30px;align-items:center}
.dlcta .note{width:100%;color:var(--muted);font-size:14px;margin-top:4px}
.dlcta .note a{color:var(--gold)}
.dlcta .off{opacity:.45;pointer-events:none}

/* numbered steps on a gold rule */
.dlsteps{list-style:none;counter-reset:s;margin:0;padding:0}
.dlsteps li{counter-increment:s;position:relative;margin-left:16px;
  padding:0 0 24px 50px;border-left:1px solid #22315a}
.dlsteps li:last-child{border-left-color:transparent;padding-bottom:0}
.dlsteps li::before{content:counter(s);position:absolute;left:-16px;top:-3px;
  width:32px;height:32px;border-radius:50%;border:1px solid var(--gold-2);background:var(--bg);
  display:grid;place-items:center;color:var(--gold);font-family:var(--serif);font-size:15px}
.dlsteps > li > b:first-child{display:block;color:#fff;font-size:17px;
  margin-bottom:6px;letter-spacing:.03em}
.dlsteps p b{color:#dbe4fb}
.dlsteps p{color:var(--muted);font-size:15px;line-height:1.65;margin:0}
.dlsteps a{color:var(--gold)}

code.k{background:#0a1230;border:1px solid #22315a;border-radius:4px;
  padding:2px 7px;font-size:.9em;color:var(--gold)}

.dlnote{margin-top:30px;padding:18px 20px;border:1px solid #22315a;
  border-left:3px solid var(--gold-2);border-radius:10px;
  background:#e7c9790d;color:var(--muted);font-size:15px;line-height:1.65}
.dlnote b{color:#fff}

.dlhash{border:1px solid #22315a;border-radius:12px;background:var(--panel-solid);overflow:hidden}
.dlhash .h{display:flex;justify-content:space-between;align-items:center;gap:12px;
  padding:11px 16px;border-bottom:1px solid #22315a;
  font-size:12px;letter-spacing:.18em;text-transform:uppercase;color:#fff}
.dlhash .h em{font-style:normal;color:var(--muted)}
.dlhash code{display:block;padding:14px 16px;color:var(--gold);
  font-size:13px;line-height:1.7;word-break:break-all;user-select:all}

.mirror{padding:16px 0;border-top:1px solid #22315a}
.mirror:first-child{border-top:0;padding-top:0}
.mirror.off{opacity:.5}
.mirror .t{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.mirror .t b{color:#fff;font-size:16px}
.mirror .t em{font-style:normal;font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  padding:3px 9px;border-radius:20px;border:1px solid var(--gold-2);
  background:#e7c97922;color:var(--gold)}
.mirror .t em.soon{background:transparent;border-color:#22315a;color:var(--muted)}
.mirror p{color:var(--muted);font-size:14px;line-height:1.55;margin:0 0 8px}
.mirror a{color:var(--gold);font-size:14px}

.reqs{margin:0;font-size:14px}
.reqs dt{color:var(--muted);margin-top:14px;font-size:12px;
  letter-spacing:.14em;text-transform:uppercase}
.reqs dt:first-child{margin-top:0}
.reqs dd{margin:3px 0 0;color:#dbe4fb;line-height:1.5}

@media (max-width:900px){ .panelgrid{grid-template-columns:1fr} }

/* The nav is position:fixed and 76px tall; .section.slim tops out at 70px, so a
   page that starts with a section instead of a .hero slides under it. */
.section.dl-top{padding-top:calc(76px + clamp(28px,4vw,52px));padding-bottom:0}
/* Section padding on both sides of the break stacked up to ~120px of nothing. */
.section.dl-body{padding-top:clamp(44px,6vw,72px)}

/* =========================================================================
   PHONES  (<=600px)

   The stylesheet stopped at a 900px breakpoint. Nothing was actually broken —
   an earlier "overflow" reading turned out to be a headless-screenshot artefact —
   but 900px is a tablet, not a phone, and at 390-430px the nav cannot fit six
   items and the display type is oversized. SEA players browse on phones.
   ========================================================================= */

@media (max-width:600px){
  .section{padding-left:18px;padding-right:18px}
  .wrap{width:100%}

  /* The menu cannot fit six items on a 390px screen at any readable size, so it
     scrolls sideways instead of pushing the page wider. */
  .nav{height:64px;padding:0 14px;gap:10px}
  .brand{font-size:15px;gap:8px;flex:0 0 auto}
  .brand .mark{width:26px;height:26px}
  .brand small{font-size:9px;letter-spacing:.22em}
  .menu{
    gap:16px;overflow-x:auto;flex:1 1 auto;justify-content:flex-end;
    scrollbar-width:none;-ms-overflow-style:none;
  }
  .menu::-webkit-scrollbar{display:none}
  .menu a{font-size:12px;white-space:nowrap;flex:0 0 auto}
  .menu .btn{padding:9px 14px;font-size:11px}

  .hero h1{font-size:clamp(30px,9vw,44px);letter-spacing:.02em}
  .hero h1 .sub{font-size:13px;letter-spacing:.24em}
  .hero .tag{font-size:15px}
  .cta{flex-direction:column;align-items:stretch}
  .cta .btn{width:100%}

  .page-h1{font-size:clamp(26px,8vw,36px)}
  .section h2{font-size:clamp(24px,7vw,32px)}

  .statstrip{grid-template-columns:repeat(2,1fr);gap:12px}
  .statstrip div{padding:14px 10px}
  .statstrip b{font-size:20px}
  .statstrip span{font-size:10px;letter-spacing:.12em}

  .btn{padding:12px 20px;font-size:13px}
  .btn.lg{width:100%}

  /* the download page */
  .section.dl-top{padding-top:calc(64px + 26px)}
  .dlcta{flex-direction:column;align-items:stretch}
  .dlcta .btn,.dlcta .off{width:100%}
  .dlsteps li{padding-left:42px;margin-left:14px}
  .dlhash code{font-size:11px}
  .pcard{padding:20px 18px}
  code.k{word-break:break-all}
}


/* .herochips removed: the two chips it centred above the hero copy are now the
   first and third cells of the truth bar welded to the hero's bottom edge, where
   they read as instrumentation instead of decoration. .status-pill and
   .status-pill.ver are KEPT — the pill is a general component and nothing here
   proves the homepage was its only caller. */
.status-pill.ver{border-color:#e7c97955;background:#e7c9791a;color:var(--gold)}
.status-pill.ver b{font-family:var(--serif);font-weight:700;letter-spacing:.1em}
.claim{margin:16px 0 0;font-size:14px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--gold-2)}
/* On the hero this line is small gold caps directly over flame - the least
   readable thing in the block. Scoped, so .claim elsewhere is untouched. */
.hero .claim{color:var(--gold);
  text-shadow:0 1px 3px #000000d9,0 3px 12px #000000e6,0 0 26px #000000b3}
.claim::before,.claim::after{content:"";display:inline-block;width:5px;height:5px;
  margin:0 12px;vertical-align:middle;background:var(--gold-2);transform:rotate(45deg)}
@media (max-width:600px){
  .claim{font-size:11px;letter-spacing:.1em}
  .claim::before,.claim::after{margin:0 7px}
}

/* ---- site-wide notice ----------------------------------------------------
   Starts hidden and is revealed by script, so a visitor without JavaScript is
   never shown a dialog they cannot close. */
.noticewrap[hidden]{display:none}
.noticewrap{position:fixed;inset:0;z-index:200;display:flex;align-items:center;
  justify-content:center;padding:24px}
.noticebg{position:absolute;inset:0;background:#02040ccc;backdrop-filter:blur(6px)}
.noticebox{position:relative;width:min(520px,100%);max-height:88vh;overflow:auto;
  background:var(--panel-solid);border:1px solid #2b3d6b;border-radius:16px;
  padding:clamp(26px,4vw,40px);box-shadow:0 40px 100px #000c,inset 0 1px 0 #ffffff12;
  animation:noticein .22s ease-out}
@keyframes noticein{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
/* the same corner brackets the login card uses, so it reads as part of the set */
.noticebox::before,.noticebox::after{content:"";position:absolute;width:20px;height:20px;
  border:2px solid var(--gold-2)}
.noticebox::before{top:12px;left:12px;border-right:0;border-bottom:0}
.noticebox::after{bottom:12px;right:12px;border-left:0;border-top:0}
.noticebox h2{font-size:clamp(21px,3vw,27px);color:#fff;margin:14px 0 12px;line-height:1.25}
.noticebox p{color:var(--muted);line-height:1.7;margin:0}
.noticelist{list-style:none;margin:18px 0 26px;padding:0}
.noticelist li{position:relative;padding:0 0 11px 22px;color:#dbe4fb;
  font-size:14.5px;line-height:1.6}
.noticelist li::before{content:"";position:absolute;left:0;top:9px;width:6px;height:6px;
  background:var(--gold-2);transform:rotate(45deg)}
.noticebox .btn{width:100%}
.noticex{position:absolute;top:10px;right:14px;z-index:2;background:none;border:0;
  color:var(--muted);font-size:26px;line-height:1;cursor:pointer;padding:6px 10px}
.noticex:hover{color:var(--gold)}
@media (max-width:600px){
  .noticewrap{padding:16px}
  .noticebox{padding:26px 20px}
  .noticelist li{font-size:13.5px}
}

/* ---- Discord ------------------------------------------------------------- */
.dclink{display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;border-radius:50%;border:1px solid #2b3d6b;
  color:#cdd8f5;transition:color .2s,border-color .2s,background .2s;flex:0 0 auto}
.dclink:hover{color:#fff;border-color:#5865f2;background:#5865f22a}
.footlinks{margin:0 0 10px}
.footlinks a{display:inline-block;padding:6px 0;color:var(--gold);font-size:14px;letter-spacing:.04em}
.footlinks a:hover{color:var(--gold-2)}
.footlegal{display:flex;flex:1 0 100%;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px 10px;margin:0;padding-top:2px;text-align:center}
.footlegal .footsep{color:#526182}
.noticelink{display:block;margin-top:14px;text-align:center;
  color:var(--gold);font-size:14px;letter-spacing:.06em}
.noticelink:hover{color:var(--gold-2)}
@media (max-width:600px){ .dclink{width:32px;height:32px} }

/* The registration select must match the text inputs beside it; the base sheet
   only ever styled .field input. */
.card select,.field select{
  width:100%;padding:12px 14px;border-radius:8px;
  background:#0a1230;border:1px solid #2b3d6b;color:var(--ink);
  font-family:var(--sans);font-size:16px;appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--gold-2) 50%),
                   linear-gradient(135deg,var(--gold-2) 50%,transparent 50%);
  background-position:calc(100% - 20px) 50%,calc(100% - 14px) 50%;
  background-size:6px 6px,6px 6px;background-repeat:no-repeat;
}
.card select:focus,.field select:focus{outline:0;border-color:var(--gold-2)}
.card select option{background:#0a1230;color:var(--ink)}

/* ---- error pages (error.php, 50x.html) --------------------------------------
   Namespaced .err-* because .err already exists here as the red form-message
   modifier (.msg.err) and must not be disturbed.

   THREE THINGS WERE WRONG BEFORE, AND THE FIXES ARE THE DESIGN:

   1. THE CHARACTER'S HEAD WAS CROPPED OFF on the owner's 3440x1440. Measured,
      not guessed: the clip is 1920x1080, so object-fit:cover on a 3440x1364 box
      scales it to 3440x1935 and throws away 571px of height. Centred, that is
      285px off the TOP — the top 14.8% of the frame, which is exactly where a
      head is. The same page loses 2.6% at 2560x1440, 3.5% at 1920x1080 and
      nothing at all on a laptop, which is why it looked fine everywhere except
      on the one screen that mattered. object-position Y is now 8%, so at most
      2.4% of the frame goes, and the head survives every aspect ratio.
      The horizontal 72% still matters, but only on narrow screens: on ultrawide
      the width drives the scale, so there is no horizontal crop to bias.

   2. THE POSTER WAS A DIFFERENT PICTURE. index.jpg is 1920x2520 — a portrait
      image of two characters in blue water — while the clip is a landscape shot
      of a red character in fire. It is not a frame of this video at all, so
      until the 4.7MB arrived the visitor saw unrelated art, cropped brutally.
      The poster is gone; with preload="metadata" the browser paints the clip's
      own first frame instead, and the panel colour below covers the moment
      before that.

   3. A 560px CARD IN THE MIDDLE OF A 3440px SCREEN sat on the character's chest
      and read as small and stranded. Above 1400px it moves into the left third,
      onto the darkest part of the frame, and leaves the artwork whole. That is
      the ordinary hero composition and it is what the veil was already built for. */

.errpage{
  position:relative;min-height:calc(100vh - 76px);display:grid;place-items:center;
  overflow:hidden;padding:120px clamp(20px,6vw,80px) 90px;
  /* Painted before the clip decodes, so nothing flashes. */
  background:radial-gradient(120% 90% at 70% 40%,#0a1330,#04091b 70%);
}
.err-video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 8%;
  pointer-events:none;
}
.err-veil{
  position:absolute;inset:0;pointer-events:none;background:
    /* left wash — drowns the Chinese calligraphy that fills the left of the frame
       and gives the card something to sit on */
    linear-gradient(90deg,#05091ae6 0,#05091ab8 24%,#05091a66 42%,#05091a26 62%,#05091a0d 100%),
    /* top and bottom, to meet the fixed nav and the footer cleanly */
    linear-gradient(180deg,#05091acc 0,transparent 20%,transparent 74%,#04091b 100%);
}

.err-card{
  position:relative;z-index:2;width:min(560px,100%);text-align:center;
  padding:clamp(32px,5vw,52px) clamp(24px,4vw,48px);
  /* Glass. The tint is deliberately light; the darkening that keeps the text
     readable is done by the backdrop filter below, not by opacity. */
  background:linear-gradient(180deg,#0a122c52,#060c1f7a);
  border:1px solid #e7c97933;
  border-radius:2px;
  box-shadow:0 30px 80px #000000a6, inset 0 1px 0 #ffffff0d;
  backdrop-filter:blur(13px) saturate(1) brightness(.78);
  -webkit-backdrop-filter:blur(13px) saturate(1) brightness(.78);
  overflow:hidden;
}
/* No backdrop-filter — mostly older WebKit and anything with it disabled.
   Those browsers get none of the darkening, so the panel has to carry the
   contrast itself or white text lands on orange flame. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .err-card{background:linear-gradient(180deg,#0a122ce6,#060c1ff2)}
}

/* Corner ticks — restrained ornament, drawn in CSS so the page needs no images. */
.err-card::before,.err-card::after{
  content:"";position:absolute;width:16px;height:16px;border:1px solid #e7c97966;
  pointer-events:none;
}
.err-card::before{top:10px;left:10px;border-right:0;border-bottom:0}
.err-card::after{bottom:10px;right:10px;border-left:0;border-top:0}

/* The numeral, demoted to a watermark. aria-hidden in the markup: a screen
   reader gets the code from the eyebrow, not from decoration. */
.err-ghost{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-52%);
  font-family:var(--serif);font-weight:900;font-size:clamp(150px,26vw,230px);
  line-height:1;letter-spacing:.02em;color:#e7c9790e;
  user-select:none;pointer-events:none;z-index:0;white-space:nowrap;
}
.err-body{position:relative;z-index:1}

.err-eyebrow{margin-bottom:20px}     /* reuses the site .eyebrow component */
.err-title{
  font-size:clamp(26px,4.4vw,42px);color:#fff;letter-spacing:.04em;
  text-shadow:0 4px 24px #000;margin-bottom:14px;
}
.err-lead{
  color:#c8d4f2;font-size:clamp(14px,1.3vw,16px);line-height:1.75;
  margin:0 auto 30px;max-width:44ch;
}
.err-links{display:flex;flex-direction:column;align-items:center;gap:18px}
.err-links .btn{min-width:230px}
.err-alt{display:flex;flex-wrap:wrap;justify-content:center;gap:6px 20px;
  font-size:13.5px;letter-spacing:.06em;color:var(--muted)}
.err-alt a{color:#cdd8f5;border-bottom:1px solid transparent;padding-bottom:1px;
  transition:color .2s,border-color .2s}
.err-alt a:hover,.err-alt a:focus-visible{color:var(--gold);border-bottom-color:#e7c97966}
.err-help{
  margin-top:26px;padding-top:20px;border-top:1px solid #ffffff12;
  font-size:13px;color:#8fa0c6;
}
.err-help a{color:var(--gold);border-bottom:1px solid #e7c97955}
.err-help a:hover{border-bottom-color:var(--gold)}

/* Focus must be visible on a dark, busy background. */
.errpage a:focus-visible,.errpage .btn:focus-visible{
  outline:2px solid var(--gold);outline-offset:3px;border-radius:2px;
}

/* The card stays centred at every width. It was briefly moved into the
   left third above 1400px to keep the artwork clear, but centred is the
   owner's call: the composition reads as symmetrical, and the centre pool
   in the veil keeps the frame dark under the panel wherever the clip is
   bright. */
@media(max-width:560px){
  .errpage{min-height:calc(100vh - 66px);padding:100px 16px 70px}
  .err-links .btn{width:100%;min-width:0}
  .err-ghost{font-size:clamp(120px,40vw,170px)}
}

/* Short windows: a laptop in landscape, or a rotated phone. Without this the
   card plus the fixed nav exceed the viewport and the page scrolls awkwardly. */
@media(max-height:560px){
  .errpage{min-height:auto;padding:100px 20px 60px}
  .err-card{padding:26px 24px}
  .err-ghost{display:none}
  .err-lead{margin-bottom:22px}
}

/* Motion is decoration here; someone who asked for less gets the panel colour
   rather than a still of unrelated artwork. */
@media(prefers-reduced-motion:reduce){
  .err-video{display:none}
}

/* =========================================================================
   THE LEDGER — the player's account console (/account/, five pages)

   It was one page with five chapters stacked down it and is now five pages:
   index (overview), currency, family, security, vote. Every one of them prints
   the same header, rail and email banner out of lib/ledger.php, so this block
   is unchanged but for three things, each marked below: the chapter heading row
   no page emits any more, the gap that used to separate stacked chapters, and
   the two numbers that keep the rail inside a window. The spine's current-item
   rule needed no change at all — only its explanation.

   NAMESPACE. The mock-up shipped generic names (.shell .spine .chapter .tender
   .ledger-table .steps .num .tablewrap .field .btn .status .note .content).
   Four of them already existed in this stylesheet — .steps (the register page's
   numbered list), .tablewrap and .num (the rankings tables), .field and .btn
   (the whole site) — so nothing from the mock-up is used under its own name.
   Every class below is prefixed `lg-` AND every rule is scoped to `.ledger`,
   the class lg_head() puts on each of those pages' <main>. Two things are NOT
   re-declared and are reused as-is, so the panel looks like the same website:
   the site's .btn / .btn.ghost, and the site's .field + .msg form furniture.

   Tokens come from :root at the top of this file (--gold, --ink, --muted,
   --line, --serif, --serif2 …). The three the mock-up added are declared on
   .ledger itself, so they cannot leak either.
   ========================================================================= */

.ledger{
  --lg-line-soft:#1b2748;
  --lg-gold-ghost:rgba(231,201,121,.16);
  --lg-nav:76px;                 /* the fixed nav's height, for sticky + anchors */
  position:relative;
}
/* the site nav shrinks to 64px on phones; the sticky rail must follow it */
@media (max-width:600px){ .ledger{--lg-nav:64px} }

/* Ruled-paper texture. On the mock-up this was body::before, which would have
   applied it to every page on the site; here it is a child of the panel. */
.ledger::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:repeating-linear-gradient(180deg,rgba(159,176,214,.045) 0 1px,transparent 1px 34px);
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 12%,#000 88%,transparent 100%);
          mask-image:linear-gradient(180deg,transparent 0,#000 12%,#000 88%,transparent 100%);
}
.ledger > .wrap{position:relative;z-index:1}

.ledger .lg-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* the site's .btn has no disabled state; the panel needs one */
.ledger .btn[disabled],.ledger .btn[aria-disabled="true"]{
  cursor:not-allowed;filter:grayscale(.55);opacity:.55}
.ledger .btn[disabled]:hover,.ledger .btn[aria-disabled="true"]:hover{
  transform:none;filter:grayscale(.55)}
/* The site's .btn is cut to a parallelogram with clip-path, and clip-path cuts
   the focus ring off with everything else outside the border box — a keyboard
   user got no visible focus at all on the two gold buttons here. Drawn inside
   instead, the same way .lg-pkg below already does it. */
.ledger .btn:focus-visible{outline:0;
  box-shadow:inset 0 0 0 2px var(--bg),inset 0 0 0 4px var(--accent)}
.ledger .btn.ghost:focus-visible{outline:2px solid var(--accent);outline-offset:2px;box-shadow:none}

/* A skip link, rendered by partials/header.php only for a page that names a
   target. Off-screen until it takes focus, and the first thing that can. */
.skip{position:absolute;left:-9999px;top:0;z-index:150;
  background:var(--gold);color:#1a1305;font-family:var(--serif);font-weight:700;
  font-size:13px;letter-spacing:.12em;text-transform:uppercase;padding:12px 20px}
.skip:focus{left:12px;top:12px}
.ledger:focus{outline:0}   /* the skip target takes focus; it must not draw a box */

/* ---------------------------------------------------------------- shell -- */
.ledger .lg-shell{display:grid;grid-template-columns:296px minmax(0,1fr);
  gap:58px;align-items:start}
.ledger .lg-content{min-width:0}

/* ---------------------------------------------------------------- spine -- */
/* Sticky rail; it scrolls inside itself on short screens so the chapter list
   and Log out stay reachable.

   STILL STICKY after the split, because the currency page is still long: its
   packages and twenty-five rows of purchases are what the rail was pinned
   against. On the four short pages it simply never engages — there is nothing
   to scroll past — and that costs nothing.

   The 40 is the rail's breathing room at the bottom of the window and used to
   be 56, i.e. the 28 above it mirrored. It is only ever visible when the rail is
   tall enough to reach its own cap, which is exactly the case this is bought
   for: an account whose name wraps to two lines makes the rail 27px taller
   (measured: 820 -> 847 at full size, 686 -> 707 compact), and those 16px are
   what keep the wrapped case off the scrollbar on a 1080-tall screen. */
.ledger .lg-spine{
  position:sticky;top:calc(var(--lg-nav) + 28px);min-width:0;
  max-height:calc(100vh - var(--lg-nav) - 40px);
  overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:var(--gold-2) transparent;
}
.ledger .lg-spine::-webkit-scrollbar{width:6px}
.ledger .lg-spine::-webkit-scrollbar-thumb{background:var(--line)}
.ledger .lg-spine::-webkit-scrollbar-thumb:hover{background:var(--gold-2)}

.ledger .lg-crest{position:relative;padding:26px 22px 24px;
  background:linear-gradient(180deg,rgba(13,24,54,.9),rgba(10,19,48,.55));
  box-shadow:inset 0 0 0 1px var(--lg-line-soft)}
.ledger .lg-crest::before,.ledger .lg-crest::after{
  content:"";position:absolute;width:16px;height:16px;pointer-events:none}
.ledger .lg-crest::before{top:0;left:0;border-top:1px solid var(--gold-2);border-left:1px solid var(--gold-2)}
.ledger .lg-crest::after{bottom:0;right:0;border-bottom:1px solid var(--gold-2);border-right:1px solid var(--gold-2)}

.ledger .lg-crest__top{display:flex;align-items:center;gap:15px}
.ledger .lg-sigil{width:52px;height:52px;flex:0 0 52px;display:grid;place-items:center;
  transform:rotate(45deg);
  background:linear-gradient(150deg,rgba(231,201,121,.2),rgba(201,162,74,.06));
  box-shadow:inset 0 0 0 1px rgba(231,201,121,.45)}
.ledger .lg-sigil span{transform:rotate(-45deg);font-family:var(--serif);font-weight:900;
  font-size:21px;color:var(--gold);letter-spacing:.02em;line-height:1}
.ledger .lg-crest__id{min-width:0}
.ledger .lg-crest__eyebrow{font-size:10px;letter-spacing:.28em;text-transform:uppercase;
  color:var(--muted);line-height:1.4}
/* NOT --serif here. Cinzel is a titling face with no lowercase: it renders
   `vasilachov` as VASILACHOV, which is not the name the player typed. Every
   player-supplied name on this page — account, house, character — is set in
   --serif2, which has real lowercase. */
.ledger .lg-crest__name{font-family:var(--serif2);font-size:22px;font-weight:400;
  letter-spacing:.04em;margin-top:4px;line-height:1.25;overflow-wrap:anywhere}

.ledger .lg-meta{margin:20px 0 0;padding-top:16px;border-top:1px solid var(--lg-line-soft);
  display:grid;gap:10px}
.ledger .lg-metarow{display:flex;justify-content:space-between;align-items:baseline;
  gap:12px;font-size:12px}
.ledger .lg-metarow dt{color:var(--muted);letter-spacing:.09em;text-transform:uppercase;
  font-size:10.5px;flex:0 0 auto}
/* font-variant-numeric here is for the FALLBACK: Marcellus has one figure set
   and ignores it, but Georgia — next in --serif2 — defaults to oldstyle figures
   that would drop below the baseline. Where digits actually have to line up in
   a column (the two tables) the face is --sans, which has tabular figures. */
.ledger .lg-metarow dd{margin:0;text-align:right;font-family:var(--serif2);
  font-variant-numeric:tabular-nums lining-nums;letter-spacing:.03em;
  min-width:0;overflow-wrap:anywhere}

/* the balance — the loudest thing on the page */
.ledger .lg-holding{position:relative;padding:24px 22px 26px;text-align:center;
  background:
    radial-gradient(120% 90% at 50% 0%,rgba(231,201,121,.10),transparent 68%),
    linear-gradient(180deg,rgba(10,19,48,.85),rgba(5,9,26,.6));
  box-shadow:inset 0 0 0 1px var(--lg-line-soft)}
.ledger .lg-holding__label{font-size:10px;letter-spacing:.32em;text-transform:uppercase;
  color:var(--muted)}
.ledger .lg-holding__fig{font-family:var(--serif2);font-size:52px;line-height:1;
  color:var(--gold);font-variant-numeric:tabular-nums lining-nums;letter-spacing:.02em;
  margin:14px 0 8px;text-shadow:0 0 34px rgba(231,201,121,.35);overflow-wrap:anywhere}
.ledger .lg-holding__unit{font-size:11px;letter-spacing:.3em;text-transform:uppercase;
  color:var(--gold-2)}
.ledger .lg-holding__rate{margin-top:14px;padding-top:13px;
  border-top:1px solid var(--lg-line-soft);font-size:11.5px;color:var(--muted);
  letter-spacing:.05em}
.ledger .lg-holding .btn{margin-top:16px;width:100%;font-size:12.5px;padding:13px 18px}
/* what stands in the button's place while the store cannot be reached */
.ledger .lg-holding__closed{margin-top:18px;font-size:10.5px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--muted)}

/* chapter list */
.ledger .lg-nav{margin-top:26px}
.ledger .lg-navlabel{font-size:10px;letter-spacing:.3em;text-transform:uppercase;
  color:var(--muted);padding-bottom:10px;border-bottom:1px solid var(--lg-line-soft)}
.ledger .lg-chapters{list-style:none;margin:0;padding:0}
.ledger .lg-chapters li{border-bottom:1px solid rgba(38,54,95,.5)}
.ledger .lg-chapters a{display:flex;align-items:baseline;gap:13px;
  padding:13px 10px 13px 14px;color:var(--muted);font-family:var(--serif);
  font-size:13px;letter-spacing:.11em;text-transform:uppercase;position:relative;
  transition:color .16s ease,background .16s ease}
.ledger .lg-chapters a:hover{color:var(--ink);background:rgba(231,201,121,.045)}
.ledger .lg-chapters a::before{content:"";position:absolute;left:0;top:0;bottom:0;
  width:2px;background:transparent;transition:background .16s ease}
/* The bare attribute, deliberately, not [aria-current="page"]. The panel used
   to be one document whose spine linked to sections of itself, and a script
   marked the one you were reading with aria-current="location"; it is five
   documents now and the server marks the page you are on with
   aria-current="page". Matching [aria-current] styles whichever token is
   present, so this rule did not have to be rewritten for the split and would
   survive the in-page form coming back. */
.ledger .lg-chapters a[aria-current]{color:var(--gold);background:rgba(231,201,121,.07)}
.ledger .lg-chapters a[aria-current]::before{background:var(--gold)}
.ledger .lg-numeral{font-family:var(--serif2);font-size:11px;color:var(--gold-2);
  letter-spacing:.1em;min-width:22px;opacity:.85}
.ledger .lg-tag{margin-left:auto;font-family:var(--sans);font-size:10px;letter-spacing:.16em;
  color:var(--gold-2);border:1px solid var(--lg-gold-ghost);padding:2px 6px;align-self:center;
  line-height:1.3}

.ledger .lg-spine__foot{margin-top:24px;padding-top:16px;
  border-top:1px solid var(--lg-line-soft);display:flex;align-items:center;
  justify-content:space-between;gap:12px;font-size:11.5px;color:var(--muted)}
/* padding, not margin: it is the hit area that has to reach 24px, on a control
   that ends the session */
.ledger .lg-logout{color:var(--muted);letter-spacing:.16em;text-transform:uppercase;
  font-size:11px;display:inline-flex;align-items:center;gap:7px;padding:5px 0;
  transition:color .16s ease}
.ledger .lg-logout:hover{color:var(--danger)}
.ledger .lg-logout span[aria-hidden]{font-size:13px;line-height:1}

/* ------------------------------------------------------------- page head -- */
.ledger .lg-pagehead{padding-bottom:26px;border-bottom:1px solid var(--line)}
.ledger .lg-pagehead .page-h1{margin:0 0 10px}
.ledger .lg-pagehead p{color:var(--muted);margin:0;max-width:62ch}
.ledger .lg-pagehead p strong{color:var(--ink);font-weight:600}

/* ----------------------------------------------------------------- alert -- */
.ledger .lg-alert{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap;
  margin-top:26px;padding:18px 22px;
  background:linear-gradient(90deg,rgba(231,201,121,.12),rgba(231,201,121,.03) 60%,transparent);
  border-left:3px solid var(--gold);box-shadow:inset 0 0 0 1px rgba(231,201,121,.12)}
.ledger .lg-alert__icon{width:26px;height:26px;flex:0 0 26px;display:grid;place-items:center;
  transform:rotate(45deg);background:rgba(231,201,121,.14);
  box-shadow:inset 0 0 0 1px var(--lg-gold-ghost);color:var(--gold)}
.ledger .lg-alert__icon span{transform:rotate(-45deg);font-family:var(--serif);font-size:14px;line-height:1}
.ledger .lg-alert__body{flex:1 1 300px;min-width:0}
/* an <h2>: it is the notice's heading, and the original page had it as one */
.ledger .lg-alert__title{font-family:var(--serif);font-size:14px;font-weight:500;
  line-height:1.4;letter-spacing:.1em;color:var(--gold);text-transform:uppercase;margin:0}
.ledger .lg-alert__text{font-size:13.5px;color:var(--muted);margin:6px 0 0;line-height:1.7}
.ledger .lg-alert__text strong{color:var(--ink);font-weight:600;overflow-wrap:anywhere}
.ledger .lg-alert form{margin:0;flex:0 0 auto}
.ledger .lg-alert .msg{width:100%;margin:0 0 12px}

/* --------------------------------------------------------------- chapter -- */
/* Still earned, and for the same reason as before the split: a form posts back
   to a fragment on its own page — #currency, #security and #email are where the
   answers to those three forms are printed — and the fixed nav would otherwise
   be painted over the top of the answer the player came back to read. */
.ledger .lg-chapter,.ledger #email{scroll-margin-top:calc(var(--lg-nav) + 24px)}
/* One chapter per page now. 64px was the distance between stacked chapters and
   it was measured to sit under a numbered heading that no longer follows it;
   left alone it is a gap with nothing in it between the page head and the first
   thing the page has to say. */
.ledger .lg-chapter{margin-top:40px}
/* GONE WITH THE SPLIT: .lg-chapter__head and its __num, __rule and __aside.
   lg_head() prints the page's own <h1>, so a numbered sub-heading underneath it
   would have said the same thing twice, and no page emits those four classes
   any more (grepped across /srv/solace/www — the only file that did is the old
   single account.php this replaces). The __aside's text moved into the intro
   line lg_head() prints, which is why the rate is still on the currency page.
   The 620px media query that hid the aside went with it — and with it the one
   thing there worth carrying forward: that text was white-space:nowrap and did
   not shrink, so between 564 and 604px it held the whole document wider than
   the window and the page scrolled sideways. Nothing nowrap goes back into this
   column without something to shrink to.
   The .lg-alert#email margin override went too: nothing sets a competing margin
   on #email any more, so .lg-alert's own 26px stands. */

/* ---------------------------------------------------------- figures strip -- */
.ledger .lg-figures{display:grid;margin:8px 0 6px;
  border-top:1px solid var(--lg-gold-ghost);border-bottom:1px solid var(--lg-gold-ghost)}
.ledger .lg-figures[data-n="2"]{grid-template-columns:repeat(2,minmax(0,1fr))}
.ledger .lg-figures[data-n="3"]{grid-template-columns:repeat(3,minmax(0,1fr))}
.ledger .lg-figures[data-n="4"]{grid-template-columns:repeat(4,minmax(0,1fr))}
.ledger .lg-figures > div{padding:22px 20px;border-right:1px solid var(--lg-line-soft);min-width:0}
.ledger .lg-figures > div:last-child{border-right:0}
.ledger .lg-figures dt{font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--muted)}
.ledger .lg-figures dd{margin:10px 0 0;font-family:var(--serif2);font-size:28px;line-height:1.1;
  letter-spacing:.03em;font-variant-numeric:tabular-nums lining-nums;overflow-wrap:anywhere}
.ledger .lg-figures dd.lg-is-gold{color:var(--gold)}
.ledger .lg-figures dd.lg-is-text{font-size:19px;letter-spacing:.05em}
.ledger .lg-figures dd small{display:block;font-size:10.5px;letter-spacing:.16em;
  color:var(--muted);margin-top:9px;font-family:var(--sans);text-transform:uppercase;
  line-height:1.5}

/* ------------------------------------------------------- key/value ledger -- */
.ledger .lg-list{margin:0;display:grid;grid-template-columns:1fr 1fr;gap:0 48px}
/* An odd number of rows — every account with no WEB_ACCOUNT row has three —
   otherwise leaves the last one stranded in the left column with its rule
   hanging into empty space. */
.ledger .lg-list > div:last-child:nth-child(odd){grid-column:1 / -1}
.ledger .lg-list > div{display:flex;align-items:baseline;justify-content:space-between;
  gap:20px;padding:14px 0;border-bottom:1px solid var(--lg-line-soft);min-width:0}
.ledger .lg-list dt{font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap;flex:0 0 auto}
.ledger .lg-list dd{margin:0;text-align:right;font-family:var(--serif2);font-size:15px;
  letter-spacing:.04em;font-variant-numeric:tabular-nums lining-nums;
  min-width:0;overflow-wrap:anywhere}

/* ----------------------------------------------------------------- pills -- */
.ledger .lg-pill{display:inline-flex;align-items:center;gap:7px;font-family:var(--sans);
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;padding:4px 11px;
  box-shadow:inset 0 0 0 1px currentColor;white-space:nowrap}
.ledger .lg-pill--ok{color:var(--ok)}
.ledger .lg-pill--warn{color:var(--gold)}
.ledger .lg-pill__mark{font-size:11px;line-height:1}

/* ----------------------------------------------------- currency: packages -- */
/* auto-fit rather than a fixed three, because the package list comes from the
   payment config and may be any length; a fixed count leaves holes. */
/* The rule between the cards is drawn ON the cards, not by letting a coloured
   container show through the 1px gaps: with any package count that does not
   fill the last row (5 in a 3-wide grid, 7, 4 at some widths) the container's
   colour painted the leftover cell as a solid slab beside the gold card. An
   empty cell now reads as empty space. */
.ledger .lg-tender{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));
  gap:1px;background:transparent}
.ledger .lg-pkg{display:flex;flex-direction:column;align-items:stretch;text-align:left;
  width:100%;cursor:pointer;border:0;padding:22px 22px 20px;color:var(--ink);
  font-family:var(--sans);
  background:linear-gradient(180deg,rgba(13,24,54,.92),rgba(8,15,38,.9));
  box-shadow:inset 0 0 0 1px var(--lg-line-soft);
  clip-path:polygon(10px 0,100% 0,calc(100% - 10px) 100%,0 100%);
  transition:background .18s ease,color .18s ease}
.ledger .lg-pkg:hover{background:linear-gradient(180deg,rgba(30,45,90,.95),rgba(13,24,54,.95))}
/* clip-path eats the outline, so the focus ring is drawn inside */
.ledger .lg-pkg:focus-visible{outline:0;
  box-shadow:inset 0 0 0 2px var(--bg),inset 0 0 0 4px var(--accent)}
.ledger .lg-pkg__ribbon{align-self:flex-start;font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;background:#141a3c;color:var(--gold);padding:3px 9px;margin-bottom:12px;
  line-height:1.4}
.ledger .lg-pkg__head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.ledger .lg-pkg__amt{font-family:var(--serif2);font-size:34px;line-height:1;color:var(--gold);
  font-variant-numeric:tabular-nums lining-nums;letter-spacing:.02em}
.ledger .lg-pkg__unit{font-size:10px;letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
.ledger .lg-pkg__rule{display:block;height:1px;background:var(--lg-line-soft);margin:16px 0 12px}
.ledger .lg-pkg__foot{display:flex;align-items:baseline;justify-content:space-between;
  gap:10px;margin-top:auto}
.ledger .lg-pkg__price{font-family:var(--serif2);font-size:15px;
  font-variant-numeric:tabular-nums lining-nums;letter-spacing:.04em}
.ledger .lg-pkg__cta{font-family:var(--serif);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--gold-2)}
.ledger .lg-pkg:hover .lg-pkg__cta{color:var(--gold)}
.ledger .lg-pkg--featured{background:linear-gradient(160deg,#f6e4ab 0%,var(--gold) 40%,var(--gold-2) 100%);
  color:#141a3c}
.ledger .lg-pkg--featured:hover{filter:brightness(1.06);
  background:linear-gradient(160deg,#f6e4ab 0%,var(--gold) 40%,var(--gold-2) 100%)}
.ledger .lg-pkg--featured .lg-pkg__amt{color:#141a3c}
.ledger .lg-pkg--featured .lg-pkg__unit,
.ledger .lg-pkg--featured .lg-pkg__cta{color:#3c3413}
.ledger .lg-pkg--featured .lg-pkg__rule{background:rgba(20,26,60,.35)}
/* The store cannot be reached: the buttons stop being buttons. Muted, not
   erased — at .45 opacity over grayscale the amounts stopped being readable,
   and the player still needs to see what is on offer once it is back. */
.ledger .lg-pkg[disabled]{cursor:not-allowed;filter:grayscale(.4);opacity:.7}
.ledger .lg-pkg[disabled]:hover{filter:grayscale(.4);
  background:linear-gradient(180deg,rgba(13,24,54,.92),rgba(8,15,38,.9))}
.ledger .lg-pkg--featured[disabled]:hover{
  background:linear-gradient(160deg,#f6e4ab 0%,var(--gold) 40%,var(--gold-2) 100%)}

.ledger .lg-tender__foot{display:flex;align-items:center;justify-content:space-between;
  gap:22px;flex-wrap:wrap;margin-top:20px;padding-top:18px;
  border-top:1px solid var(--lg-line-soft);font-size:12.5px;color:var(--muted)}
.ledger .lg-tender__foot p{margin:0}
.ledger .lg-tender__secure{display:flex;align-items:center;gap:12px;flex:0 0 auto}
.ledger .lg-tender__note{flex:1 1 320px;max-width:54ch;line-height:1.7}
/* Two spans, not <i>/<b>: they are colour, not emphasis, and the wordmark
   already reads "PayPal" as text. */
.ledger .lg-paypal{font-family:Verdana,var(--sans);font-style:italic;font-weight:700;
  font-size:17px;letter-spacing:-.01em;display:inline-flex;align-items:baseline}
.ledger .lg-paypal span:first-child{color:var(--ink)}
.ledger .lg-paypal span:last-child{color:var(--accent)}

/* --------------------------------------------------------- purchase table -- */
.ledger .lg-history{margin-top:46px}
.ledger .lg-tablewrap{overflow-x:auto}
.ledger .lg-table{width:100%;border-collapse:collapse;font-size:14px;min-width:520px}
.ledger .lg-table caption{text-align:left;color:var(--muted);font-size:12.5px;padding-bottom:14px}
/* thead th, not th: the date cell in each row is a <th scope="row"> now, and it
   has to be styled like the data it sits beside, not like a column heading. */
.ledger .lg-table thead th{font-family:var(--sans);font-size:10px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--muted);font-weight:600;text-align:left;
  padding:0 14px 11px;border-bottom:1px solid var(--lg-gold-ghost);white-space:nowrap}
.ledger .lg-table thead tr th:first-child{padding-left:0}
.ledger .lg-table thead tr th:last-child{padding-right:0;text-align:right}
.ledger .lg-table td,.ledger .lg-table tbody th{padding:16px 14px;
  border-bottom:1px solid var(--lg-line-soft);vertical-align:middle;
  font-weight:400;text-align:left}
.ledger .lg-table tbody tr > :first-child{padding-left:0}
.ledger .lg-table tbody tr > :last-child{padding-right:0;text-align:right}
.ledger .lg-table tbody tr:hover{background:rgba(231,201,121,.035)}
/* --sans, deliberately. This is the one place where digits have to line up
   underneath each other, and Marcellus has a single proportional figure set —
   its 1 is a third the width of its 0, so a column of amounts came out ragged.
   Segoe UI has tabular lining figures, and it is what /rankings.php already
   sets its numbers in. */
.ledger .lg-num{font-family:var(--sans);font-variant-numeric:tabular-nums lining-nums;
  font-size:13.5px;letter-spacing:.02em;white-space:nowrap}
.ledger .lg-num--gold{color:var(--gold)}
.ledger .lg-name{font-family:var(--serif2);letter-spacing:.03em}
.ledger .lg-receipt{font-family:var(--sans);font-variant-numeric:tabular-nums lining-nums;
  letter-spacing:.06em;color:var(--muted);font-size:12.5px;white-space:nowrap}

/* status never relies on colour alone: every one carries a mark and a word */
.ledger .lg-status{display:inline-flex;align-items:center;gap:8px;white-space:nowrap;
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase}
.ledger .lg-status__mark{width:18px;height:18px;flex:0 0 18px;display:grid;place-items:center;
  font-size:10px;line-height:1;box-shadow:inset 0 0 0 1px currentColor}
.ledger .lg-status--delivered{color:var(--ok)}
.ledger .lg-status--pending{color:var(--gold)}
.ledger .lg-status--refunded{color:var(--muted)}
.ledger .lg-status--refunded .lg-status__mark{box-shadow:inset 0 0 0 1px var(--danger);color:var(--danger)}
.ledger .lg-status--failed{color:var(--danger)}
.ledger .lg-status--other{color:var(--muted)}

.ledger .lg-legend{display:flex;flex-wrap:wrap;gap:14px 34px;margin-top:20px;padding-top:16px;
  border-top:1px solid var(--lg-line-soft);font-size:12px;color:var(--muted)}
.ledger .lg-legend div{display:flex;align-items:center;gap:9px}
.ledger .lg-footnote{margin-top:14px;font-size:12px;color:var(--muted);opacity:.9}

/* --------------------------------------------------------- empty / notice -- */
.ledger .lg-empty{padding:34px 30px;text-align:center;
  background:linear-gradient(180deg,rgba(13,24,54,.55),rgba(5,9,26,.35));
  box-shadow:inset 0 0 0 1px var(--lg-line-soft)}
/* an <h3>/<h4>: these are the headings of the states they announce, and a
   screen reader navigating by heading should find them */
.ledger .lg-empty__t{font-family:var(--serif);font-size:15px;font-weight:500;line-height:1.4;
  letter-spacing:.16em;text-transform:uppercase;color:var(--gold);margin:0 0 10px}
.ledger .lg-empty p{margin:0;color:var(--muted);font-size:13.5px;line-height:1.75;
  max-width:60ch;margin-left:auto;margin-right:auto}

/* ---------------------------------------------------------------- family -- */
.ledger .lg-house{display:grid;grid-template-columns:280px minmax(0,1fr);gap:44px;align-items:start}
.ledger .lg-house--solo{grid-template-columns:minmax(0,1fr)}
.ledger .lg-houses{display:grid;gap:18px;min-width:0}
.ledger .lg-house__crest{padding:26px 24px;text-align:center;position:relative;
  background:linear-gradient(180deg,rgba(13,24,54,.85),rgba(5,9,26,.5));
  box-shadow:inset 0 0 0 1px var(--lg-line-soft)}
.ledger .lg-house__crest::before,.ledger .lg-house__crest::after{content:"";position:absolute;width:14px;height:14px}
.ledger .lg-house__crest::before{top:0;right:0;border-top:1px solid var(--gold-2);border-right:1px solid var(--gold-2)}
.ledger .lg-house__crest::after{bottom:0;left:0;border-bottom:1px solid var(--gold-2);border-left:1px solid var(--gold-2)}
.ledger .lg-house__label{font-size:10px;letter-spacing:.28em;text-transform:uppercase;color:var(--muted)}
/* --serif2 for the same reason as the account name: a house called "Ashford"
   must not be printed ASHFORD */
.ledger .lg-house__name{font-family:var(--serif2);font-size:24px;font-weight:400;
  letter-spacing:.06em;margin:12px 0 18px;color:var(--ink);overflow-wrap:anywhere;line-height:1.3}
.ledger .lg-house__stats{margin:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  border-top:1px solid var(--lg-line-soft);padding-top:16px}
.ledger .lg-house__stats div{border-right:1px solid var(--lg-line-soft);padding:0 6px;min-width:0}
.ledger .lg-house__stats div:last-child{border-right:0}
.ledger .lg-house__stats dt{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.ledger .lg-house__stats dd{margin:7px 0 0;font-family:var(--serif2);font-size:22px;
  font-variant-numeric:tabular-nums lining-nums;overflow-wrap:anywhere}

.ledger .lg-roster{width:100%;border-collapse:collapse}
.ledger .lg-roster caption{text-align:left;color:var(--muted);font-size:12.5px;padding-bottom:14px}
.ledger .lg-roster thead th{font-size:10px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--muted);text-align:left;font-weight:600;padding:0 12px 11px;
  border-bottom:1px solid var(--lg-gold-ghost);white-space:nowrap}
.ledger .lg-roster thead th:first-child{padding-left:0}
.ledger .lg-roster thead th:last-child{text-align:right;padding-right:0}
.ledger .lg-roster td,.ledger .lg-roster tbody th{padding:15px 12px;
  border-bottom:1px solid var(--lg-line-soft);font-weight:400;text-align:left}
.ledger .lg-roster tbody tr > :first-child{padding-left:0}
.ledger .lg-roster tbody tr > :last-child{text-align:right;padding-right:0}
.ledger .lg-roster tbody tr:hover{background:rgba(231,201,121,.035)}
.ledger .lg-char{display:flex;align-items:center;gap:14px;min-width:0}
.ledger .lg-char__sigil{width:34px;height:34px;flex:0 0 34px;display:grid;place-items:center;
  transform:rotate(45deg);background:rgba(231,201,121,.09);
  box-shadow:inset 0 0 0 1px var(--lg-gold-ghost)}
.ledger .lg-char__sigil span{transform:rotate(-45deg);font-family:var(--serif);font-size:13px;
  color:var(--gold);line-height:1}
.ledger .lg-char__name{font-family:var(--serif2);font-size:16px;letter-spacing:.04em;
  overflow-wrap:anywhere}

/* -------------------------------------------------------------- security -- */
.ledger .lg-security{display:grid;grid-template-columns:minmax(0,420px) minmax(0,1fr);
  gap:52px;align-items:start}
.ledger .lg-security form{min-width:0}
.ledger .lg-formfoot{display:flex;align-items:center;gap:20px;flex-wrap:wrap;margin-top:26px}
.ledger .lg-note{font-size:11.5px;color:var(--muted);margin:0}
.ledger .lg-sidenote{padding:22px 24px;background:var(--panel);
  box-shadow:inset 0 0 0 1px var(--lg-line-soft)}
.ledger .lg-sidenote h3{font-size:13px;letter-spacing:.18em;color:var(--gold);
  text-transform:uppercase;margin-bottom:14px}
.ledger .lg-sidenote ul{margin:0;padding-left:18px;color:var(--muted);font-size:13px;
  line-height:1.85;list-style:disc}
.ledger .lg-sidenote li::marker{color:var(--gold-2)}

/* ------------------------------------------------------------ vote (soon) -- */
.ledger .lg-reserved{position:relative;padding:44px 40px 40px;overflow:hidden;
  background:
    repeating-linear-gradient(180deg,rgba(159,176,214,.05) 0 1px,transparent 1px 40px),
    linear-gradient(180deg,rgba(13,24,54,.8),rgba(5,9,26,.4));
  box-shadow:inset 0 0 0 1px var(--lg-line-soft)}
.ledger .lg-reserved::before,.ledger .lg-reserved::after{content:"";position:absolute;width:18px;height:18px}
.ledger .lg-reserved::before{top:0;left:0;border-top:1px solid var(--gold-2);border-left:1px solid var(--gold-2)}
.ledger .lg-reserved::after{bottom:0;right:0;border-bottom:1px solid var(--gold-2);border-right:1px solid var(--gold-2)}
.ledger .lg-reserved__lead{max-width:56ch;position:relative}
.ledger .lg-reserved__lead h3{font-size:22px;letter-spacing:.14em;margin-bottom:12px;color:var(--ink)}
.ledger .lg-reserved__lead p{color:var(--muted);font-size:14px;margin:0;line-height:1.8}
.ledger .lg-steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1px;
  background:var(--lg-line-soft);margin:32px 0 30px;padding:0;list-style:none;position:relative}
.ledger .lg-steps > li{list-style:none;background:rgba(5,9,26,.55);padding:24px 22px;
  border:0;min-width:0}
.ledger .lg-steps h4{font-family:var(--serif);font-size:14px;letter-spacing:.16em;
  margin:12px 0 8px;color:var(--ink)}
.ledger .lg-steps p{margin:0;font-size:12.5px;color:var(--muted);line-height:1.7}
.ledger .lg-reserved__foot{display:flex;align-items:center;gap:22px;flex-wrap:wrap;position:relative}
/* Inside the panel, not bleeding out of it: .lg-reserved is overflow:hidden, so
   a stamp hung 46px past the edge did not bleed, it was sliced flat 47px short
   of its own border. */
.ledger .lg-stamp{position:absolute;top:34px;right:0;transform:rotate(12deg);
  padding:9px 34px;color:var(--gold);opacity:.62;
  border-top:2px solid var(--gold-2);border-bottom:2px solid var(--gold-2);
  font-family:var(--serif);font-size:13px;letter-spacing:.34em;text-transform:uppercase;
  box-shadow:inset 0 0 0 1px rgba(231,201,121,.18);pointer-events:none}

/* ------------------------------------------------------------ responsive --
   Two of these are keyed to viewport HEIGHT, not width: the sticky rail is 800
   pixels of content, and on a 1366x768 laptop that is taller than the space it
   is given. Rather than hide the end of its own chapter list behind a 6px
   scrollbar, it is compacted on a short screen and stops being sticky on a
   shorter one.

   That mattered less when the rail stood beside four thousand pixels of stacked
   chapters. A page of the split panel is a few hundred pixels tall — the vote
   page is the shortest — and the rail is now regularly the tallest thing on the
   page, so anything it hides is hidden for good: no amount of page scrolling
   brings it back (sticky pins it, and the cap clips it whether pinned or not),
   and its own 6px scrollbar is the only way to it.

   Measured on the split panel at 1440 wide, with the 40px reserve above: the
   full rail is 820px and needs a 936px viewport to clear its cap, the compact
   rail is 686px and clears it from 802px up. The 940 here was therefore four
   pixels short of meeting itself — at 941 the full rail was clipped and Log out
   went behind that scrollbar — and is now 960, which also carries the account
   name that wraps to two lines (847 full / 707 compact) everywhere except a
   two-pixel sliver at 961. Below 981 wide the rail is not a rail and none of
   this applies. */
@media (min-width:981px) and (max-height:960px){
  /* The rate is repeated in the intro line of the currency page, which is the
     page that sells the ICoin; the crest can lose it. (Before the split it was
     repeated in chapter II's heading, which the split deleted.) */
  .ledger .lg-holding__rate{display:none}
  .ledger .lg-crest{padding:20px 22px 18px}
  .ledger .lg-holding{padding:18px 22px 20px}
  .ledger .lg-holding__fig{font-size:44px;margin:10px 0 6px}
  .ledger .lg-chapters a{padding:10px 10px 10px 14px}
  .ledger .lg-nav{margin-top:18px}
  .ledger .lg-spine__foot{margin-top:16px;padding-top:12px}
}
@media (min-width:981px) and (max-height:880px){
  /* below this there is no arrangement of the rail that fits, so it stops
     pretending: it scrolls with the page and nothing is out of reach */
  .ledger .lg-spine{position:static;max-height:none;overflow:visible}
}
@media (max-width:1180px){
  /* the content column is at its narrowest here — 584px at 1024 — and the
     purchase table was 594px wide, i.e. a scrollbar under five short columns */
  .ledger .lg-table td,.ledger .lg-table thead th,.ledger .lg-table tbody th{
    padding-left:8px;padding-right:8px}
  .ledger .lg-shell{grid-template-columns:262px minmax(0,1fr);gap:40px}
  .ledger .lg-holding__fig{font-size:44px}
  .ledger .lg-figures[data-n="3"],
  .ledger .lg-figures[data-n="4"]{grid-template-columns:repeat(2,minmax(0,1fr))}
  .ledger .lg-figures[data-n="3"] > div:nth-child(2n),
  .ledger .lg-figures[data-n="4"] > div:nth-child(2n){border-right:0}
  .ledger .lg-figures[data-n="3"] > div:nth-child(-n+2),
  .ledger .lg-figures[data-n="4"] > div:nth-child(-n+2){border-bottom:1px solid var(--lg-line-soft)}
  .ledger .lg-house{grid-template-columns:minmax(0,1fr);gap:30px}
  .ledger .lg-houses{grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr))}
  .ledger .lg-security{grid-template-columns:minmax(0,1fr);gap:32px}
  .ledger .lg-security form{max-width:480px}
}
@media (max-width:980px){
  /* the rail stops being a rail and becomes the ledger's header block */
  .ledger .lg-shell{grid-template-columns:minmax(0,1fr);gap:34px}
  .ledger .lg-spine{position:static;max-height:none;overflow:visible}
  .ledger .lg-spine__inner{display:grid;grid-template-columns:1fr 1fr;gap:1px;
    background:var(--lg-line-soft)}
  .ledger .lg-crest,.ledger .lg-holding{height:100%}
  /* The strip is 769px of chapters inside a 328px box on a phone. The fade is
     the only thing that says so — a touch device draws no scrollbar. */
  .ledger .lg-chapters{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;
    -webkit-mask-image:linear-gradient(90deg,#000 84%,rgba(0,0,0,.15));
            mask-image:linear-gradient(90deg,#000 84%,rgba(0,0,0,.15))}
  .ledger .lg-chapters li{border-bottom:0;border-right:1px solid var(--lg-line-soft);
    scroll-snap-align:start;flex:0 0 auto}
  .ledger .lg-chapters a{white-space:nowrap;padding:14px 18px}
  .ledger .lg-chapters a::before{top:auto;bottom:0;left:0;right:0;width:auto;height:2px}
  .ledger .lg-tag{margin-left:10px}
}
@media (max-width:720px){
  .ledger .lg-list{grid-template-columns:minmax(0,1fr);gap:0}
  .ledger .lg-reserved{padding:32px 22px}
  .ledger .lg-steps{grid-template-columns:minmax(0,1fr)}
  /* No stamp on a phone: repositioned to the bottom right it was printed across
     the sentence underneath the Vote button, two texts over each other. */
  .ledger .lg-stamp{display:none}

  /* The purchase ledger reflows into stacked entries: every cell carries its
     own label, so the table can lose its head without losing its meaning.
     This is why every <td> in the loop MUST emit data-label. The row's <th> is
     styled with them — it is a cell here like any other. */
  .ledger .lg-tablewrap{overflow:visible}
  .ledger .lg-table{min-width:0;display:block}
  .ledger .lg-table caption{display:block}
  .ledger .lg-table thead{position:absolute;width:1px;height:1px;overflow:hidden;
    clip:rect(0 0 0 0);white-space:nowrap}
  .ledger .lg-table tbody,.ledger .lg-table tr,
  .ledger .lg-table td,.ledger .lg-table tbody th{display:block;width:100%}
  .ledger .lg-table tr{border:1px solid var(--lg-line-soft);border-left:2px solid var(--gold-2);
    background:rgba(13,24,54,.5);padding:8px 18px 12px;margin-bottom:14px}
  .ledger .lg-table tr:hover{background:rgba(13,24,54,.5)}
  .ledger .lg-table td,.ledger .lg-table tbody th{display:flex;align-items:baseline;
    justify-content:space-between;gap:18px;padding:9px 0;
    border-bottom:1px solid rgba(38,54,95,.45);text-align:right}
  .ledger .lg-table tbody tr > :first-child{padding-left:0}
  .ledger .lg-table tbody tr > :last-child{border-bottom:0;text-align:right;padding-bottom:2px}
  .ledger .lg-table td::before,.ledger .lg-table tbody th::before{
    content:attr(data-label);flex:0 0 auto;text-align:left;
    font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}

  /* thead, not th — the character name is a <th scope="row"> and must survive */
  .ledger .lg-roster thead{display:none}
  .ledger .lg-roster,.ledger .lg-roster tbody,.ledger .lg-roster tr,
  .ledger .lg-roster td,.ledger .lg-roster tbody th{display:block;width:100%}
  .ledger .lg-roster tr{border-bottom:1px solid var(--lg-line-soft);padding:14px 0}
  .ledger .lg-roster tr:hover{background:transparent}
  .ledger .lg-roster td{border:0;padding:4px 0;display:flex;justify-content:space-between;
    gap:16px;text-align:right}
  .ledger .lg-roster td::before{content:attr(data-label);font-size:10px;letter-spacing:.18em;
    text-transform:uppercase;color:var(--muted);flex:0 0 auto;text-align:left}
  /* the character cell is the row's heading; it keeps the full width */
  .ledger .lg-roster tbody tr > :first-child{display:block;margin-bottom:6px;text-align:left;
    border:0;padding:4px 0}
  .ledger .lg-roster tbody tr > :first-child::before{content:none}
}
@media (max-width:560px){
  .ledger .lg-spine__inner{grid-template-columns:minmax(0,1fr)}
  .ledger .lg-pkg__amt{font-size:28px}
  .ledger .lg-chapter{margin-top:32px}
  .ledger .lg-figures[data-n]{grid-template-columns:minmax(0,1fr)}
  .ledger .lg-figures[data-n] > div{border-right:0;border-bottom:1px solid var(--lg-line-soft)}
  .ledger .lg-figures[data-n] > div:last-child{border-bottom:0}
  .ledger .lg-house__stats{grid-template-columns:minmax(0,1fr)}
  .ledger .lg-house__stats div{border-right:0;border-bottom:1px solid var(--lg-line-soft);
    padding:0 0 12px}
  .ledger .lg-house__stats div:last-child{border-bottom:0;padding-bottom:0}
  .ledger .lg-house__stats dd{margin-top:4px}
  .ledger .lg-alert{padding:16px 16px}
  .ledger .lg-alert form,.ledger .lg-alert .btn{width:100%}
  .ledger .lg-formfoot .btn{width:100%}
  .ledger .lg-empty{padding:26px 18px}
}
@media (prefers-reduced-motion:reduce){
  .ledger *{transition:none !important}
  /* The base sheet sets html{scroll-behavior:smooth}: without this, someone who
     asked for no motion still got a 3000px animated slide on every chapter
     link. The approved mock-up turned it off; the port had dropped it. The
     spine's links are page loads since the split and no longer slide anywhere,
     but this is unscoped on purpose — it is the homepage's #why/#play/#news
     anchors, and the ledger's own #currency/#security/#email, that it answers
     for now. */
  html{scroll-behavior:auto}
}

/* ------------------------------------------------------------- the nav ----
   THE MENU ITSELF. .nav is position:fixed, so anything wider than the window
   is simply painted outside it: no scrollbar appears, the page reports no
   overflow, and the button at the end of the row cannot be reached at all.
   Measured on the live markup, the row ran past the right edge from 1035px
   down — Log Out clipped at 1024, gone entirely by 834 — and the chip made it
   worse. Two changes, both to the shared nav and both invisible while the row
   fits:
     - the menu may shrink below its content (min-width:0) and scroll,
     - each item keeps its own width instead of being squeezed.
   `flex` is deliberately NOT set to `1 1 auto`: that makes the menu fill the
   bar and left-aligns the items on a wide screen, which would move the nav on
   every page of the site. */
.menu{min-width:0;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}
.menu::-webkit-scrollbar{display:none}
.menu > *{flex:0 0 auto}
.menu a{white-space:nowrap}
.nav .brand{flex:0 0 auto}

/* Between a phone and a wide laptop the row is a little too long for the bar
   (1003px of items in a 907px bar at 1024). Slightly tighter spacing and type
   makes it fit outright at 1024 and 1180 instead of scrolling. Held above
   601px so the phone rules further up keep their own, smaller, values. */
@media (min-width:601px) and (max-width:1180px){
  .brand{font-size:19px}
  .brand .mark{width:30px;height:30px}
  .menu{gap:12px}
  .menu a{font-size:12.5px}
  .menu .btn{font-size:12px;padding:9px 14px}
}
@media (max-width:600px){
  /* `safe` matters: with a plain flex-end the items overflow to the LEFT, where
     flexbox gives nothing to scroll to — on a 390px phone Home, News, Rankings,
     Download and Store were all off the left edge and unreachable, on the live
     site as it stands. `safe` falls back to flex-start the moment the row
     overflows, and the row is then scrollable in the direction it overflows. */
  .menu{justify-content:safe flex-end}
}

/* =========================================================================
   THE HOMEPAGE  (index.php)

   Everything below belongs to one page. It is appended rather than woven in
   so the two features that share this stylesheet — the error pages (.errpage
   / .err-*) and the account ledger (.ledger / .lg-*) — are provably
   untouched by it.

   NAMING. Four of the mock-up's names were already taken in this file and are
   NOT used here under their own name:
     .steps   -> the register page's numbered list.  Ours is .startsteps.
     .num     -> the rankings tables' numeric column. Ours is .cardnum/.stepnum.
     .meta    -> the news chip row. Deliberately REUSED on the dispatch rows,
                 because .meta .cat / .meta .cat-* are scoped to it and a
                 category chip outside a .meta parent would render unstyled.
     .card    -> the login panel. The why-here cards are plain .feature.

   No new colour: every value here is a :root token or a token at an alpha.
   Breakpoints are the sheet's existing ones — 1500 / 900 / 600.
   ========================================================================= */

/* ---- hero -----------------------------------------------------------------
   The height change lives up at .hero, the crop correction it forced lives with
   the crop. These rules only add, and both paddings are LONGHANDS on a
   two-class selector so the >=1500px `padding:0 clamp(...)` shorthand keeps its
   horizontal value and cannot flatten them.

   PADDING-TOP RESERVES THE NAV. .nav is position:fixed and 76px tall (64px
   under 600px) and it is transparent until the visitor scrolls 30px, so a copy
   block optically centred through it is not "behind a bar" — it is two sets of
   live text drawn over each other. Measured before this rule: the H1 started at
   y=60.9 on a 1366x650 laptop and at y=-7.9 on a 375x667 phone, i.e. clipped
   off the top by .hero{overflow:hidden}. It is unconditional, because the bar
   is not: with the status probe down .has-tb is absent and the copy would
   re-centre straight back under the nav. */
.hero .hero-inner{padding-top:76px}
/* .has-tb only: if ge_server_status() is unavailable the bar is not printed and
   nothing should reserve space for it. */
.hero.has-tb .hero-inner{padding-bottom:64px}

/* The sub-line now carries a sentence, not two words, so the 0.5em tracking
   it was set at (fine for "The Baroque of War") is loosened off.
   Restated inside BOTH of this sheet's hero breakpoints below (>=1500 and
   <=600): this selector already exists inside @media(max-width:600px) at the
   same specificity, and a top-level rule appended after it wins everywhere,
   silently killing the phone values. */
.hero h1 .sub{font-size:clamp(12px,1.5vw,19px);letter-spacing:.28em;
  max-width:900px;margin-left:auto;margin-right:auto}

/* The proposition. Second-largest type on the page, and the only sentence a
   visitor must read: it is the whole argument for this server existing. */
.hero-claim{font-family:var(--serif2);font-size:clamp(20px,2.2vw,28px);line-height:1.4;
  color:#fff;max-width:760px;margin:26px auto 16px;
  text-shadow:0 1px 3px #000000d9,0 3px 14px #000000e6,0 0 34px #000000b3}
/* For the visitor who has never heard of Granado Espada. */
.hero-line{max-width:620px;margin:0 auto 32px;color:var(--ink);font-size:17px;
  text-shadow:0 1px 3px #000000d9,0 3px 14px #000000e6,0 0 30px #000000b3}

/* ---- the truth bar --------------------------------------------------------
   Welded to the hero's bottom edge rather than floating in the copy block, so
   the four facts read as instrumentation and not as marketing. Inside .hero,
   which means the >=1500px veil and crop never have to know about it. */
/* .herofoot owns the bottom edge now; the bar is a plain block inside it. It used
   to be absolutely positioned itself, which is why the cue had to guess. */
.herofoot{position:absolute;left:0;right:0;bottom:0;z-index:3;
  display:flex;flex-direction:column;pointer-events:none}
.herofoot > *{pointer-events:auto}
.truthbar{display:flex;justify-content:center;align-items:stretch;
  background:#0a1330e6;border-top:1px solid var(--line);
  backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}
.truthbar > *{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  min-height:56px;padding:0 clamp(14px,2.4vw,30px);
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.truthbar > * + *{border-left:1px solid var(--line)}
/* text-transform:none, because the cell above it is uppercase and the value in
   here is a build string: without this the first screen printed "BUILD
   V39.27.70" while the numeral row and the footer printed "v39.27.70" — a
   one-character disagreement on the one string the whole page argues about. */
.truthbar b{font-family:var(--serif);font-weight:700;font-size:14px;
  letter-spacing:.06em;color:var(--gold);text-transform:none}
.truthbar a{transition:color .18s ease}
.truthbar a:hover,.truthbar a:focus-visible{color:var(--gold)}
.truthbar .dot{width:9px;height:9px;flex:0 0 9px;border-radius:50%;
  background:var(--ok);box-shadow:0 0 10px var(--ok);animation:tbpulse 2.4s ease-in-out infinite}
.truthbar .down .dot{background:var(--danger);box-shadow:0 0 10px var(--danger)}
@keyframes tbpulse{0%,100%{opacity:1}50%{opacity:.45}}

/* ---- ornaments ------------------------------------------------------------
   One shape, cut two ways. NOT the nav's rotated diamond — .brand .mark stays
   the only rotated square on the site. */
.oct{clip-path:polygon(6px 0,100% 0,100% calc(100% - 6px),calc(100% - 6px) 100%,0 100%,0 6px);
  border:1px solid #e7c9798c}
.cardnum{width:44px;height:44px;display:grid;place-items:center;margin-bottom:20px;
  font-family:var(--serif);font-weight:700;font-size:15px;letter-spacing:.06em;color:var(--gold)}

/* ---- section 3: the family rail ------------------------------------------
   Three panels on one hairline, not three loose cards: the point of the
   section is that they are one family, seen at once. */
.rail{position:relative;display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:44px}
.rail::before{content:"";position:absolute;left:0;right:0;top:50%;height:1px;
  background:var(--line);z-index:0}
.slot{position:relative;z-index:1;aspect-ratio:3/4;background:#0d1836ee;
  border:1px solid #22315a;padding:26px;display:flex;flex-direction:column;
  align-items:center;justify-content:center;text-align:center;
  clip-path:polygon(14px 0,100% 0,100% calc(100% - 14px),calc(100% - 14px) 100%,0 100%,0 14px);
  transition:transform .18s ease,border-color .18s ease,opacity .18s ease}
/* b3, not 66: gold at 40% over this panel measures 2.7:1, and these numerals
   are readable content, not an ornament — at 70% they clear 4.5:1. */
.slot .rn{position:absolute;top:14px;left:16px;font-family:var(--serif);font-size:14px;
  letter-spacing:.14em;color:#e7c979b3}
.slot svg{width:72px;height:72px;color:var(--gold)}
.slot h3{font-size:20px;color:var(--gold);letter-spacing:.06em;margin:22px 0 10px}
.slot p{color:var(--muted);font-size:15px;max-width:26ch}
/* Resting state is all three at full strength; the dim only happens once a
   pointer has picked one out. */
.rail:hover .slot{opacity:.45}
.rail .slot:hover,.rail .slot:focus-within{opacity:1;transform:translateY(-6px);border-color:var(--gold)}
/* No .railpips. Three static diamonds under a scroller, with nothing reading the
   scroller's position, cannot say which panel is centred — an indicator that
   never moves reads as a broken control. Wiring one needs js/main.js. */

/* ---- section 4: the numeral row ------------------------------------------
   The big-numeral treatment, spent once, on the three figures that grow the
   argument. No boxes: this is evidence, not a scoreboard. */
/* flex, not a 3-column grid: the third cell is printed only when config carries
   a build number, and a fixed template would leave a two-thirds-wide row with a
   hole in it on that path. */
.numrow{display:flex;margin-top:44px}
.numrow > div{flex:1 1 0;padding:0 24px;border-left:1px solid var(--line);min-width:0}
.numrow > div:first-child{border-left:0;padding-left:0}
.numrow b{display:block;font-family:var(--serif);font-weight:700;
  font-size:clamp(40px,6vw,72px);line-height:1.1;letter-spacing:.02em;color:var(--gold)}
/* the build number is nine characters where the others are two to six, and it
   has no space to break on: a ten-character build would otherwise leave its
   cell, since 601px is the tightest three-column case and v39.27.70 already
   measures 119.7px of a 127px cell there. */
.numrow b.sm{font-size:clamp(26px,3.4vw,44px);line-height:1.5;overflow-wrap:anywhere}
.numrow span{display:block;margin-top:10px;font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted)}

/* Source next to result. Renders only when data/translation-samples.php holds
   real pairs from the translation working set — see index.php. */
.evid{max-width:760px;margin-top:44px}
.evid .row{display:grid;grid-template-columns:1fr 28px 1fr;align-items:center;gap:14px;
  padding:14px 0;border-bottom:1px solid var(--line)}
.evid .row:last-child{border-bottom:0}
.evid .cn{font-family:'Microsoft YaHei',var(--sans);font-size:15px;color:var(--muted)}
.evid .en{font-size:15px;color:var(--ink)}
.evid .ar{color:var(--gold);display:flex;align-items:center}
.evid .ar svg{width:20px;height:8px}
.evidnote{margin-top:14px;font-size:12px;color:var(--muted)}

/* ---- section 5: where this server actually is -----------------------------
   Deliberately administrative. No cards, no hover, no animation: the section
   exists to be believed, and ornament is what makes a disclosure look sold. */
.statebody{max-width:660px;font-size:19px;line-height:1.75;color:var(--ink)}
.statebody strong{color:#fff;font-weight:600}
.statecols{display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:38px}
.statecols h3{font-family:var(--sans);font-weight:600;font-size:11px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--muted);margin-bottom:14px}
.statelist{list-style:none;margin:0;padding:0}
.statelist li{position:relative;padding:0 0 12px 24px;font-size:15px;line-height:1.7;color:var(--ink)}
.statelist li::before{content:"";position:absolute;left:0;top:10px;width:6px;height:6px;
  transform:rotate(45deg);background:var(--gold)}
.statelist.soon li{color:var(--muted)}
.statelist.soon li::before{background:transparent;border:1px solid var(--gold-2)}
.asof{margin-top:26px;font-size:12px;color:var(--muted);text-align:right}

/* ---- section 6: dispatches ------------------------------------------------
   Rows, not cards: the layout is identical at one, two or three items, which
   is the point — the old grid's column count followed the item count and left
   two empty cells every time only one thing had been published. */
.dispatches{margin-top:34px}
.dispatch{display:grid;grid-template-columns:150px 1fr;gap:24px;padding:24px 0;
  border-bottom:1px solid var(--line);transition:border-color .18s ease}
.dispatch:first-child{padding-top:0}
.dispatch:last-child{border-bottom:0}
.dispatch:hover{border-bottom-color:var(--gold-2)}
.dispatch .d-when{display:block;font-size:12px}
.dispatch .d-when time{display:block;font-family:var(--serif);font-size:14px;
  letter-spacing:.06em;color:var(--gold);margin-bottom:10px}
.dispatch .d-when .cat{display:inline-block}
.dispatch .d-what{min-width:0}
.dispatch .d-what h3{font-size:22px;color:#fff;letter-spacing:.04em;overflow-wrap:anywhere;
  transition:transform .18s ease,color .18s ease}
.dispatch:hover .d-what h3{transform:translateX(4px);color:var(--gold)}
.dispatch .d-what p{margin-top:8px;color:var(--muted);font-size:15px;line-height:1.65;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.newsnone{color:var(--muted);font-size:16px;margin-top:26px}
.newsnone a{color:var(--gold)}

/* ---- section 7: how to start ---------------------------------------------
   Same rail construction as the family panels, so the two read as one system.
   .startsteps, not .steps: .steps is the register page's list. */
.startsteps{list-style:none;position:relative;display:grid;grid-template-columns:repeat(3,1fr);
  gap:34px;margin:44px 0 0;padding:0}
.startsteps::before{content:"";position:absolute;left:0;right:0;top:22px;height:1px;
  background:var(--line);z-index:0}
.startsteps li{position:relative;z-index:1;min-width:0}
/* var(--bg), so the hairline appears to pass behind the node */
.startsteps .stepnum{width:44px;height:44px;display:grid;place-items:center;
  background:var(--bg);margin-bottom:20px;
  font-family:var(--serif);font-weight:700;font-size:15px;letter-spacing:.06em;color:var(--gold)}
/* h3, not b: three bold words gave the section one heading and no outline. */
.startsteps h3{font-size:19px;letter-spacing:.06em;color:var(--gold);margin-bottom:8px}
.startsteps p{margin:0;color:var(--muted);font-size:15px;line-height:1.7}
.startsteps a{color:var(--gold);border-bottom:1px solid #e7c97966}
.startsteps a:hover{color:var(--gold-2)}
.startfoot{margin-top:52px;text-align:center}
.startfoot .note{margin-top:16px;font-size:14px;color:var(--muted)}
.startfoot .note a{color:var(--gold)}

/* ---- section 8: the Discord band -----------------------------------------
   Full-bleed strip, one row, one button. No card and no icon circle: it is a
   signpost at the end of the page, not a ninth section competing with them. */
.dband{background:var(--bg2);border-top:1px solid var(--line);
  padding:38px clamp(20px,6vw,80px)}
.dband .wrap{display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap}
.dband .l{display:flex;align-items:center;gap:20px;min-width:0}
.dband svg{width:28px;height:21px;flex:0 0 28px;color:var(--gold)}
.dband h2{font-size:22px;color:#fff;margin:0}
.dband p{margin:6px 0 0;color:var(--muted);font-size:15px}

/* =========================================================================
   HOMEPAGE — RESPONSIVE
   ========================================================================= */

@media (min-width:1500px){
  /* Re-stated here on purpose: the >=1500px block further up sizes .sub for a
     three-word tagline at .46em, and this one is a sentence. */
  .hero h1 .sub{font-size:19px;letter-spacing:.3em}
  .hero-claim{max-width:820px}
  .slot p{max-width:28ch}
}

@media (max-width:900px){
  /* Two rows of two. The vertical rules become a grid's own hairlines, so no
     cell can end a row with a rule hanging off it. */
  .truthbar{display:grid;grid-template-columns:1fr 1fr}
  .truthbar > *{border-left:0;border-top:1px solid var(--line);
    min-height:46px;padding:8px 12px;text-align:center}
  .truthbar > :nth-child(2n){border-left:1px solid var(--line)}
  .truthbar > :nth-child(-n+2){border-top:0}
  /* The grid is 2x2 for four cells, but the bar has THREE whenever the game
     server is up and the population could not be read — the state the nullable
     count exists to show. Without this the row rule stops dead at mid-screen and
     the fourth quadrant is empty. :last-child:nth-child(odd) matches only an odd
     cell count, so the four-cell bar is untouched. */
  .truthbar > :last-child:nth-child(odd){grid-column:1 / -1;border-left:0}
  .hero.has-tb .hero-inner{padding-bottom:116px}

  /* The rail keeps three columns: seeing all three at once IS the section. */
  .rail{gap:14px}
  .slot{aspect-ratio:2/3;padding:18px}
  .slot svg{width:52px;height:52px}
  .slot h3{font-size:17px;margin:16px 0 8px}
  .slot p{font-size:14px}

  .evid .row{grid-template-columns:minmax(0,40%) 24px 1fr;gap:10px}

  /* One column, LIVE NOW first — it is first in source order, so nothing has
     to move. Both headings stay visible: NOT YET must never be mistaken for
     the other list. */
  .statecols{grid-template-columns:1fr;gap:30px}

  /* The 150px gutter goes; date and category become one gold line above. */
  .dispatch{grid-template-columns:1fr;gap:10px}
  .dispatch .d-when{display:flex;align-items:center;gap:12px}
  .dispatch .d-when time{margin-bottom:0}

  /* The steps rail rotates: nodes in a left column on a vertical hairline. */
  .startsteps{grid-template-columns:1fr;gap:0}
  .startsteps::before{display:none}
  .startsteps li{display:grid;grid-template-columns:44px 1fr;gap:20px;
    padding:0 0 26px;position:relative}
  .startsteps li::before{content:"";position:absolute;left:21px;top:44px;bottom:0;
    width:1px;background:var(--line)}
  .startsteps li:last-child{padding-bottom:0}
  .startsteps li:last-child::before{display:none}
  .startsteps .stepnum{margin-bottom:0}
  .startsteps .txt{padding-top:4px}
}

@media (max-width:600px){
  /* 672, not 560. Measured on this copy block: 64px of nav + 481px of copy at
     320px wide + a 95px two-row truth bar needs 640px, and at 560 the H1 was
     starting at y=-7.9 — clipped, not merely crowded. On a 568px-tall phone the
     bar now sits below the fold; that is the right thing to lose, because the
     alternative is losing the headline. */
  .hero{height:82vh;min-height:672px}
  .hero .hero-inner{padding-top:64px}   /* the nav is 64px here */
  .hero-claim{font-size:19px;margin:18px auto 12px}
  .hero-line{font-size:15px;margin-bottom:24px}
  /* the bar is 93-95px in its 2x2 form, so this clears it with ~10px to spare */
  .hero.has-tb .hero-inner{padding-bottom:104px}
  /* Restated: the sheet's own .hero h1 .sub rule for this breakpoint sits ~950
     lines earlier at identical specificity, so the appended base rule was
     winning inside this media query and the phone values were dead. */
  .hero h1 .sub{font-size:13px;letter-spacing:.24em}
  /* 44px of horizontal padding on a button that is already width:100% only
     wraps its own label. Scoped to .hero, so .btn.lg is untouched everywhere
     else it is used (download.php, register.php). */
  .hero .btn.lg{padding-left:18px;padding-right:18px}
  .truthbar > *{font-size:10px;letter-spacing:.1em;padding:8px 8px}
  .truthbar b{font-size:12px}

  /* The rail becomes a snap carousel. At 78vw the SECOND panel peeks by about
     34px at the right edge — not the third, which is off-screen — and that peek
     is the affordance that says swipe. This is the ONLY element on the page
     allowed to scroll sideways. */
  .rail{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:78vw;
    overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
    gap:12px;padding-bottom:4px}
  .rail::before{display:none}
  .slot{scroll-snap-align:center;aspect-ratio:4/5}
  .slot svg{width:64px;height:64px}

  /* Figure left, label right, hairline between. display:block, so the flex
     sizing above stops applying and each row is simply full width. */
  .numrow{display:block}
  .numrow > div{display:flex;align-items:baseline;justify-content:space-between;gap:16px;
    padding:16px 0;border-left:0;border-bottom:1px solid var(--line)}
  .numrow > div:first-child{padding-top:0}
  .numrow > div:last-child{border-bottom:0}
  .numrow b{font-size:34px}
  .numrow b.sm{font-size:23px}
  .numrow span{margin-top:0;text-align:right}

  /* Source over result; the one arrow is rotated rather than duplicated. */
  .evid .row{grid-template-columns:1fr;gap:6px;justify-items:start}
  .evid .ar svg{transform:rotate(90deg)}

  .statebody{font-size:17px}
  .dispatch .d-what h3{font-size:19px}
  .dband .wrap{flex-direction:column;align-items:flex-start}
  .dband .btn{width:100%}
  .startfoot{margin-top:40px}
}

/* Touch: there is no pointer to pick a panel out with, so nothing may dim.
   #22315a is not a token — it is .slot's and .feature's own resting border,
   quoted here so the reset lands on exactly the value it is undoing. It is the
   one literal in this block, and it is a repeat rather than a new colour. */
@media (hover:none){
  .rail:hover .slot{opacity:1}
  .rail .slot:hover{transform:none;border-color:#22315a}
  .dispatch:hover .d-what h3{transform:none}
}

/* A desktop window narrower than 600px gets the phone carousel AND a pointer.
   .rail is overflow-x:auto there, which forces overflow-y to compute to auto
   too, and an upward translate does not extend a scroll area — so the lift was
   being sliced off at the top. Nothing is lost by dropping it: the border and
   opacity changes still answer the pointer. */
@media (hover:hover) and (max-width:600px){
  .rail .slot:hover,.rail .slot:focus-within{transform:none}
}

@media (prefers-reduced-motion:reduce){
  .truthbar .dot{animation:none}
  .rail:hover .slot{opacity:1}
  .rail .slot:hover,.rail .slot:focus-within{transform:none}
  .dispatch:hover .d-what h3{transform:none}
  .slot,.dispatch,.dispatch .d-what h3{transition:none}
}
/* THE HOMEPAGE ends here. */

/* --- Pay-with choice (PayPal / crypto) ----------------------------------- */
/* Only rendered when crypto is configured; the store looks exactly as before
   until then. Two radios styled as cards, matching the package tiles rather
   than introducing a second visual language for the same decision. */
.lg-method{
  border:0;margin:0 0 18px;padding:0;
  display:flex;gap:10px;flex-wrap:wrap;
}
.lg-method legend{
  padding:0;margin:0 0 8px;width:100%;
  font-size:11px;letter-spacing:1.4px;text-transform:uppercase;color:var(--muted,#8b93ad);
}
.lg-method__opt{
  flex:1 1 180px;min-width:160px;
  display:flex;flex-direction:column;gap:2px;
  padding:11px 14px;cursor:pointer;
  border:1px solid var(--line,#2a2f47);border-radius:10px;
  background:var(--card,rgba(255,255,255,.02));
  transition:border-color .15s ease, background .15s ease;
}
.lg-method__opt:hover{border-color:var(--gold,#c9a24a);}
.lg-method__opt:focus-within{
  outline:2px solid var(--gold,#c9a24a);outline-offset:2px;
}
/* The radio itself stays in the flow for keyboard and screen readers; it is the
   label that carries the selected state. */
.lg-method__opt input[type=radio]{
  position:absolute;opacity:0;width:0;height:0;
}
.lg-method__opt:has(input:checked){
  border-color:var(--gold,#c9a24a);
  background:color-mix(in srgb, var(--gold,#c9a24a) 8%, transparent);
}
.lg-method__name{font-weight:600;font-size:14px;}
.lg-method__sub{font-size:12px;color:var(--muted,#8b93ad);}
.lg-method__and{opacity:.75;}

@media (max-width:520px){
  .lg-method__opt{flex:1 1 100%;}
}

/* The ICoin figure on the overview is a link to the store. The site sets
   a{color:inherit;text-decoration:none} globally, so it needs its own mark to
   read as one at all; the hairline copies the treatment already used for gold
   links elsewhere (.startsteps a). */
.ledger .lg-figures dd a{border-bottom:1px solid rgba(231,201,121,.4);}
.ledger .lg-figures dd a:hover{border-bottom-color:rgba(231,201,121,.9);}

/* --- Shared navigation upgrade ----------------------------------------- */
.nav .brand,.foot .brand{
  flex-direction:column;align-items:flex-start;gap:2px;line-height:1;
  text-shadow:none;
}
.brand-name{
  color:#f1d68d;font-family:var(--serif);font-size:24px;font-weight:700;
  letter-spacing:.2em;line-height:.85;
}
.nav .brand small,.foot .brand small{
  color:#9ca9c5;font-size:9px;font-weight:700;letter-spacing:.25em;
  margin:0;text-transform:uppercase;
}
.nav-toggle{display:none}
.nav-logout{display:contents}
.menu button{font-family:var(--sans)}
.nav a:focus-visible,.nav button:focus-visible,.skip:focus-visible{
  outline:2px solid #f1d68d;outline-offset:4px;
}

@media (max-width:900px){
  .nav.nav-ready{overflow:visible}
  .nav.nav-ready .nav-toggle{
    display:inline-flex;align-items:center;gap:10px;margin-left:auto;padding:10px 0;
    color:#e8edf8;background:transparent;border:0;cursor:pointer;
    font:700 11px/1 var(--sans);letter-spacing:.18em;text-transform:uppercase;
  }
  .nav.nav-ready .nav-toggle i,
  .nav.nav-ready .nav-toggle i::before,
  .nav.nav-ready .nav-toggle i::after{
    display:block;width:20px;height:1px;background:currentColor;content:"";
    transition:transform .2s ease,opacity .2s ease;
  }
  .nav.nav-ready .nav-toggle i{position:relative}
  .nav.nav-ready .nav-toggle i::before{position:absolute;top:-6px;left:0}
  .nav.nav-ready .nav-toggle i::after{position:absolute;top:6px;left:0}
  .nav.nav-ready.menu-open .nav-toggle i{background:transparent}
  .nav.nav-ready.menu-open .nav-toggle i::before{top:0;transform:rotate(45deg)}
  .nav.nav-ready.menu-open .nav-toggle i::after{top:0;transform:rotate(-45deg)}

  .nav.nav-ready .menu{
    position:absolute;top:calc(100% + 1px);left:12px;right:12px;
    display:flex;flex-direction:column;align-items:stretch;justify-content:flex-start;
    gap:0;max-height:0;padding:0 18px;overflow:hidden;
    background:rgba(5,9,26,.985);border:1px solid transparent;
    box-shadow:0 24px 50px rgba(0,0,0,.45);opacity:0;visibility:hidden;
    pointer-events:none;transform:translateY(-8px);
    transition:max-height .28s ease,opacity .18s ease,transform .18s ease,
      visibility 0s linear .28s,padding .28s ease,border-color .2s ease;
  }
  .nav.nav-ready.menu-open{background:rgba(5,9,26,.985);border-bottom:1px solid #233253}
  .nav.nav-ready.menu-open .menu{
    max-height:calc(100vh - 92px);padding:10px 18px 16px;overflow-y:auto;
    border-color:#233253;opacity:1;visibility:visible;pointer-events:auto;
    transform:translateY(0);transition-delay:0s;
  }
  .nav.nav-ready .menu > *{width:100%;flex:0 0 auto}
  .nav.nav-ready .menu a,.nav.nav-ready .menu .btn{
    display:flex;align-items:center;justify-content:flex-start;min-height:45px;
    padding:10px 4px;font-size:12px;border:0;border-bottom:1px solid #1b2948;
    clip-path:none;background:transparent;box-shadow:none;color:#dce5f7;
  }
  .nav.nav-ready .menu a::after{display:none}
  .nav.nav-ready .menu .dclink svg{margin-right:8px}
  .nav.nav-ready .menu .dclink::after{display:inline;position:static;width:auto;height:auto;
    background:none;content:"Discord"}
  .nav.nav-ready .nav-logout{display:block;width:100%}
  .nav.nav-ready .nav-logout .btn{width:100%;color:#f1d68d}
  body.nav-open{overflow:hidden}
}

@media (prefers-reduced-motion:reduce){
  .nav.nav-ready .menu,.nav.nav-ready .nav-toggle i,
  .nav.nav-ready .nav-toggle i::before,.nav.nav-ready .nav-toggle i::after{transition:none}
}
