/* app.css — D2REKT control panel: design tokens, application shell, component library.
 *
 * One system, every page. Nothing here is page-specific; pages compose these classes.
 * The D2R identity lives in the palette, the display serif, the portrait frames and the logo —
 * NOT in ornamental stone borders around every panel and button.
 */

:root{
  /* surfaces */
  --bg-app:#090909;
  --bg-sidebar:#0d0c0b;
  --bg-topbar:#0b0c0c;
  --bg-panel:#111414;
  --bg-panel-raised:#151818;
  --bg-panel-hover:#1a1b19;
  --bg-input:#0b0c0c;

  /* lines */
  --border-subtle:#302b21;
  --border-gold:#69572d;
  --border-active:#8a7040;

  /* type */
  --text-primary:#ece7dc;
  --text-secondary:#aaa296;
  --text-muted:#716d66;

  /* accents */
  --gold:#c5a55d;
  --gold-bright:#e0c77f;

  /* status */
  --success:#69b96b;
  --warning:#d59a45;
  --danger:#c95b52;
  --info:#6097bd;

  /* metrics — the acceptance viewport is 1672x941 */
  --sidebar-w:252px;
  --topbar-h:58px;
  --pad:30px;
  --gap:14px;
  --radius:7px;

  /* Marcellus has real lowercase; Cinzel's lowercase is small caps, which turned every heading
     into uppercase and fought the "reduce uppercase text" rule. */
  --font-display:"Marcellus",Georgia,"Times New Roman",serif;
  --font-ui:"Inter",-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,Consolas,monospace;
}

*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{
  background:var(--bg-app);
  color:var(--text-primary);
  font:14px/1.45 var(--font-ui);
  -webkit-font-smoothing:antialiased;
  overflow:hidden;
}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:#241f18;border-radius:5px}
::-webkit-scrollbar-thumb:hover{background:#332c21}

/* ══════════════════════════════ shell ══════════════════════════════ */
.shell{display:grid;grid-template-columns:var(--sidebar-w) 1fr;height:100vh}

.sidebar{
  background:var(--bg-sidebar);
  border-right:1px solid var(--border-subtle);
  display:flex;flex-direction:column;
  position:relative;overflow:hidden;
}
/* Wordmark: D2REKT set in the display serif, with the antique-gold gradient the D2R UI uses for
   its own titling, over a hairline rule. Text rather than an image so it stays sharp at any
   sidebar width and can shorten when the sidebar collapses. */
.sidebar .brand{
  height:calc(var(--topbar-h) + 26px);
  display:flex;align-items:center;justify-content:center;
  padding:0 22px;flex:none;position:relative;
}
.sidebar .brand .wordmark{
  font:600 27px/1 var(--font-display);
  letter-spacing:.17em;
  text-indent:.17em;                 /* re-centre: letter-spacing pads the right edge only */
  background:linear-gradient(180deg,var(--gold-bright) 6%,var(--gold) 52%,#8a6f33 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.55));
  white-space:nowrap;
}
.sidebar .brand .wordmark .short{display:none}
.sidebar .brand::after{
  content:"";position:absolute;left:22px;right:22px;bottom:16px;height:1px;
  background:linear-gradient(90deg,transparent,var(--border-gold) 22%,var(--border-gold) 78%,transparent);
  opacity:.55;
}

.nav{padding:10px 14px;display:flex;flex-direction:column;gap:2px;flex:none;z-index:2}
.nav a{
  display:flex;align-items:center;gap:12px;
  height:46px;padding:0 14px;border-radius:var(--radius);
  color:var(--text-secondary);font-size:14.5px;font-weight:500;
  border:1px solid transparent;transition:background .12s,color .12s;
}
.nav a:hover{background:var(--bg-panel-hover);color:var(--text-primary)}
.nav a.on{
  background:linear-gradient(90deg,rgba(197,165,93,.13),rgba(197,165,93,.04));
  border-color:var(--border-gold);color:var(--gold-bright);
}
.nav a .ic{width:19px;height:19px;flex:none;opacity:.9}
.nav a.on .ic{opacity:1}

/* The hooded-skull sigil from the project logo, cropped to the skull (the logo's own wordmark is
   left out — the brand here is D2REKT). Identity without wrapping every panel in stone. */
.sidebar .sigil{
  position:absolute;left:50%;bottom:8px;transform:translateX(-50%);
  width:224px;height:210px;
  background:url(/logo) no-repeat;
  background-size:770px auto;
  background-position:-282px -18px;      /* crops 1500x1024 down to the hood + skull */
  -webkit-mask:radial-gradient(60% 58% at 50% 42%,#000 42%,transparent 100%);
          mask:radial-gradient(60% 58% at 50% 42%,#000 42%,transparent 100%);
  opacity:.42;pointer-events:none;z-index:0;
}

.main{display:flex;flex-direction:column;min-width:0;height:100vh}

.topbar{
  height:var(--topbar-h);flex:none;
  background:var(--bg-topbar);border-bottom:1px solid var(--border-subtle);
  display:flex;align-items:center;gap:26px;padding:0 22px 0 26px;
}
.topbar .stat{display:flex;align-items:center;gap:9px;color:var(--text-secondary);font-size:13.5px}
.topbar .stat .ic{width:16px;height:16px;opacity:.75}
.topbar .spacer{flex:1}
.topbar .iconbtn{
  width:36px;height:36px;border-radius:var(--radius);
  display:grid;place-items:center;background:transparent;border:1px solid transparent;
  cursor:pointer;color:var(--text-secondary);position:relative;
}
.topbar .iconbtn:hover{background:var(--bg-panel-hover);color:var(--text-primary)}
.topbar .me{
  width:36px;height:36px;border-radius:50%;overflow:hidden;position:relative;
  border:1px solid var(--border-gold);background:#12100c;cursor:pointer;
}
.topbar .me img{width:100%;height:100%;object-fit:cover}
.topbar .me .dot{position:absolute;right:-1px;bottom:-1px;width:11px;height:11px;border-radius:50%;
  background:var(--success);border:2px solid var(--bg-topbar)}

.page{flex:1;overflow-y:auto;padding:26px var(--pad) 30px}
/* Pages whose content should fill the viewport and scroll INSIDE their panels (accounts, map,
   chat, logs) rather than growing the page. Without this a tall side panel runs off the bottom. */
.page.fill{display:flex;flex-direction:column;overflow:hidden}
.page.fill > .fill-rest{flex:1;min-height:0}
.page-head{margin:0 0 20px}
.page-head h1{
  font:600 40px/1.1 var(--font-display);
  margin:0 0 6px;color:var(--text-primary);letter-spacing:.4px;
}
.page-head p{margin:0;color:var(--text-muted);font-size:14px}
/* NOT .row — that class is the list-row component (min-height, padding, divider) and reusing it
   here silently put a divider and 56px of padding under every page title. */
.page-head .hdr{display:flex;align-items:flex-start;gap:20px;justify-content:space-between}

/* ══════════════════════════════ panels ══════════════════════════════ */
.grid{display:grid;gap:var(--gap)}
.g-4{grid-template-columns:repeat(4,1fr)}
.g-3{grid-template-columns:repeat(3,1fr)}
.g-2{grid-template-columns:repeat(2,1fr)}
.g-12{grid-template-columns:1fr 1fr}

.panel{
  background:var(--bg-panel);
  border:1px solid var(--border-subtle);
  border-radius:var(--radius);
  display:flex;flex-direction:column;min-width:0;
}
.panel > h2{
  margin:0;padding:13px 16px;flex:none;
  font:600 15px/1 var(--font-display);letter-spacing:.3px;color:var(--text-primary);
  border-bottom:1px solid var(--border-subtle);
  display:flex;align-items:center;gap:9px;
}
.panel > h2 .ic{width:17px;height:17px;opacity:.8}
.panel > h2 .right{margin-left:auto;display:flex;align-items:center;gap:8px}
.panel .body{padding:16px;flex:1;min-height:0}
.panel .body.tight{padding:0}
.panel .foot{border-top:1px solid var(--border-subtle);padding:11px 16px;flex:none}

/* Dashboard fits the 1672x941 viewport without scrolling — the rows are height-bounded and the
   lists scroll inside their panel instead of pushing the page taller. */
.dash-mid{height:356px}
.dash-bot{height:258px}
.dash-mid .panel,.dash-bot .panel{overflow:hidden}
.scroll-y{overflow-y:auto;min-height:0}

/* KPI tile */
.kpi{
  background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:var(--radius);
  padding:15px 17px;display:flex;flex-direction:column;gap:9px;min-width:0;
}
.kpi .lbl{display:flex;align-items:center;gap:9px;color:var(--text-secondary);font-size:13px}
.kpi .lbl .ic{width:17px;height:17px;opacity:.8}
.kpi .val{font:600 27px/1 var(--font-display);color:var(--text-primary);display:flex;align-items:baseline;gap:8px}
.kpi .val .sub{font:400 15px/1 var(--font-ui);color:var(--text-muted)}
.kpi .val .hl{color:var(--gold)}
.kpi .val .danger{color:var(--danger)}

/* ══════════════════════════════ atoms ══════════════════════════════ */
.dot{width:7px;height:7px;border-radius:50%;flex:none;display:inline-block}
.dot.online,.dot.connected,.dot.running{background:var(--success);box-shadow:0 0 6px rgba(105,185,107,.5)}
.dot.ingame{background:var(--success);box-shadow:0 0 6px rgba(105,185,107,.5)}
.dot.connecting{background:var(--warning);box-shadow:0 0 6px rgba(213,154,69,.5)}
.dot.disconnected,.dot.offline{background:#5d5852}
.dot.error,.dot.blocked{background:var(--danger);box-shadow:0 0 6px rgba(201,91,82,.5)}
.dot.idle{background:var(--warning)}

.st{display:inline-flex;align-items:center;gap:7px;font-size:13px;white-space:nowrap}
.st.online,.st.ingame,.st.connected,.st.running{color:var(--success)}
.st.connecting,.st.idle{color:var(--warning)}
.st.disconnected,.st.offline{color:var(--danger)}
.st.error,.st.blocked{color:var(--danger)}
.st.neutral{color:var(--text-muted)}

.badge{
  display:inline-flex;align-items:center;height:19px;padding:0 7px;border-radius:3px;
  font-size:10px;font-weight:600;letter-spacing:.5px;
  border:1px solid var(--border-subtle);color:var(--text-muted);background:#0e1010;
}
.badge.gold{border-color:var(--border-gold);color:var(--gold)}
.badge.role{border-color:var(--border-gold);color:var(--gold);letter-spacing:.6px}

/* Character facts, coloured by what they MEAN rather than uniformly grey. Ladder and Hardcore
   are the two that change how a character may be played, so they are the two that carry a
   colour; non-ladder and softcore stay neutral because "nothing special here" is the message.
   A faint tinted background lifts them off the card without competing with the gold chrome. */
.badge.ladder{border-color:#3f7a45;color:#7fcf84;background:rgba(63,122,69,.13)}
.badge.rotw{border-color:var(--border-gold);color:var(--gold-bright);background:rgba(105,87,45,.16)}
.badge.hardcore{border-color:#8f3a33;color:#e0736a;background:rgba(143,58,51,.15)}

.muted{color:var(--text-muted)}
.sec{color:var(--text-secondary)}
.gold{color:var(--gold)}
.mono{font-family:var(--font-mono);font-size:12.5px}
.danger-t{color:var(--danger)}
.ok-t{color:var(--success)}

/* Portrait: the real D2R class art inside the real D2R frame, both 120x120 in assets/.
   The art is inset proportionally and CONTAINed — the same treatment the current panel uses, so
   the frame's ornament is never cropped and the art never stretches. Every size is square,
   because portraitframe.png is square and forcing it to a rectangle warps the ornament. */
.port{position:relative;flex:none}
.port img.art{position:absolute;inset:11%;width:78%;height:78%;object-fit:contain;z-index:1}
.port .ring{position:absolute;inset:0;z-index:2;pointer-events:none;
  background:url(/assets/d2r/portraitframe.png) center/100% 100% no-repeat}
.port.sz-s{width:38px;height:38px}
.port.sz-m{width:46px;height:46px}
.port.sz-l{width:64px;height:64px}
.port.sz-xl{width:96px;height:96px}
.port.sz-hero{width:108px;height:108px}
.port .fallback{position:absolute;inset:0;display:grid;place-items:center;color:#4b463d;z-index:1}

/* ══════════════════════════════ controls ══════════════════════════════ */
.btn{
  height:40px;padding:0 16px;border-radius:6px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  background:var(--bg-panel-raised);border:1px solid var(--border-subtle);
  color:var(--text-primary);font-size:13.5px;font-weight:500;
  transition:background .12s,border-color .12s,color .12s;white-space:nowrap;
}
.btn:hover:not(:disabled){background:var(--bg-panel-hover);border-color:var(--border-gold)}
.btn:disabled{opacity:.42;cursor:not-allowed}
.btn .ic{width:16px;height:16px;opacity:.85}
.btn.primary{
  background:linear-gradient(180deg,#3a2f19,#241d10);
  border-color:var(--border-active);color:var(--gold-bright);
}
.btn.primary:hover:not(:disabled){background:linear-gradient(180deg,#453820,#2b2213)}
.btn.danger{background:rgba(201,91,82,.1);border-color:rgba(201,91,82,.42);color:var(--danger)}
.btn.danger:hover:not(:disabled){background:rgba(201,91,82,.18);border-color:var(--danger)}
.btn.ghost{background:transparent}
.btn.sm{height:32px;padding:0 11px;font-size:12.5px}
.btn.block{width:100%}

.field{display:flex;flex-direction:column;gap:6px}
.field > label{font-size:12.5px;color:var(--text-secondary)}
.input,select.input{
  height:42px;padding:0 12px;border-radius:6px;
  background:var(--bg-input);border:1px solid var(--border-subtle);color:var(--text-primary);
  outline:none;width:100%;
}
.input:focus{border-color:var(--border-active)}
.input::placeholder{color:#5b564f}

.seg{display:inline-flex;background:var(--bg-input);border:1px solid var(--border-subtle);
  border-radius:6px;overflow:hidden;height:42px}
.seg button{
  padding:0 20px;background:transparent;border:0;cursor:pointer;
  color:var(--text-secondary);font-size:13.5px;height:100%;
}
.seg button:hover{color:var(--text-primary)}
.seg button.on{background:var(--bg-panel-raised);color:var(--gold-bright);box-shadow:inset 0 0 0 1px var(--border-gold)}

/* dropdown menu (Quick Actions, row menus) */
.menu-wrap{position:relative}
.menu{
  position:absolute;top:calc(100% + 7px);right:0;min-width:214px;z-index:60;
  background:var(--bg-panel-raised);border:1px solid var(--border-gold);border-radius:var(--radius);
  padding:6px;box-shadow:0 18px 38px rgba(0,0,0,.62);
}
.menu button{
  width:100%;height:38px;padding:0 11px;border:0;border-radius:5px;background:transparent;
  display:flex;align-items:center;gap:11px;cursor:pointer;color:var(--text-primary);font-size:13.5px;
}
.menu button:hover:not(:disabled){background:var(--bg-panel-hover)}
.menu button:disabled{opacity:.4;cursor:not-allowed}
.menu button.danger{color:var(--danger)}
.menu .sep{height:1px;background:var(--border-subtle);margin:5px 4px}
/* Identity block at the top of the account menu. Not a button — it states who the SERVER
   authenticated, so it is deliberately inert. */
.menu .me-head{padding:9px 11px 10px;display:flex;flex-direction:column;gap:3px;align-items:flex-start}
.menu .me-head .n{font-size:13.5px;font-weight:600;color:var(--text-primary)}
.menu .me-head .e{font-size:11.5px;color:var(--text-muted);word-break:break-all}
.menu .me-head .badge{margin-top:4px}

/* ══════════════════════════════ lists & tables ══════════════════════════════ */
.rows{display:flex;flex-direction:column}
.row{
  display:flex;align-items:center;gap:12px;
  min-height:56px;padding:9px 16px;border-bottom:1px solid rgba(48,43,33,.55);
}
.rows .row:last-child{border-bottom:0}
.row:hover{background:rgba(26,27,25,.5)}
.row .who{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.row .who .n{font-size:13.5px;font-weight:500;color:var(--text-primary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.row .who .s{font-size:12px;color:var(--text-muted)}
.row .end{margin-left:auto;display:flex;align-items:center;gap:14px;flex:none}

.kv{display:grid;grid-template-columns:auto 1fr;gap:9px 22px;align-items:baseline}
.kv dt{color:var(--text-muted);font-size:13px}
.kv dd{margin:0;font-size:13.5px}

table.tbl{width:100%;border-collapse:collapse}
table.tbl th{
  text-align:left;font-size:12px;font-weight:500;color:var(--text-muted);
  padding:10px 14px;border-bottom:1px solid var(--border-subtle);white-space:nowrap;
}
table.tbl td{padding:11px 14px;border-bottom:1px solid rgba(48,43,33,.5);font-size:13.5px}
table.tbl tbody tr:last-child td{border-bottom:0}
table.tbl tbody tr:hover{background:rgba(26,27,25,.5)}

/* activity feed / recent events */
.feed{display:flex;flex-direction:column;gap:9px;font-size:13px}
.feed .ev{display:flex;gap:10px;align-items:baseline}
.feed .ev .t{font-family:var(--font-mono);font-size:11.5px;color:var(--text-muted);flex:none}
.feed .ev .who{color:var(--gold);flex:none}
.feed .ev .who.sys{color:var(--info)}
.feed .ev .who.err{color:var(--danger)}
.feed .ev .m{color:var(--text-secondary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* states */
.empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;
  padding:34px 20px;text-align:center;color:var(--text-muted);font-size:13px;height:100%;
}
.empty .ic{width:28px;height:28px;opacity:.4}
.skel{background:linear-gradient(90deg,#141514,#1b1c1a,#141514);background-size:200% 100%;
  animation:sk 1.2s ease-in-out infinite;border-radius:4px;height:12px}
@keyframes sk{0%{background-position:200% 0}100%{background-position:-200% 0}}

/* ══════════════════════════════ accounts ══════════════════════════════ */
.toolbar{display:flex;align-items:center;gap:10px;margin-bottom:var(--gap)}
/* standalone component — it is used outside .toolbar too (chat account list), and scoping it to
   the toolbar left the magnifier unpositioned there */
.search{position:relative}
.search .ic{position:absolute;right:12px;top:50%;transform:translateY(-50%);
  opacity:.5;pointer-events:none}
.search .input{padding-right:36px}
.toolbar .search{width:270px}
.toolbar select.input{width:auto;min-width:132px;cursor:pointer}
.toolbar .spacer{flex:1}

/* the account workspace: card/table area, plus the detail drawer as a real column so it
   never covers the list it was opened from */
.acc-work{display:grid;grid-template-columns:1fr;gap:var(--gap);min-height:0}
.acc-work.with-drawer{grid-template-columns:1fr 336px}
.acc-list{overflow-y:auto;min-height:0;padding-right:2px}
.acards{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--gap);align-content:start}
@media (max-width:1500px){.acc-work.with-drawer .acards{grid-template-columns:1fr}}

.acard{
  background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:var(--radius);
  display:flex;flex-direction:column;min-width:0;
}
.acard.sel{border-color:var(--border-gold)}
.acard .top{
  display:flex;align-items:center;gap:9px;padding:9px 14px;
  border-bottom:1px solid var(--border-subtle);font-size:12.5px;
  /* wraps because a rented account carries a third chip here and the card is only ~320px */
  flex-wrap:wrap;
}
.acard .top .id{margin-left:auto;color:var(--text-muted);font-size:12px}
.acard .mid{display:flex;gap:13px;padding:14px;min-width:0}
.acard .ident{display:flex;gap:12px;min-width:0;flex:1}
.acard .ident .nm{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.acard .ident .nm b{font:600 16px/1.2 var(--font-display);font-weight:400;letter-spacing:.2px}
.acard .ident .ch{color:var(--gold);font-size:13.5px;margin-top:5px}
.acard .ident .lv{color:var(--text-muted);font-size:12.5px;margin-top:1px}
.acard .badges{display:flex;gap:5px;flex-wrap:wrap;margin-top:8px}
.acard .kv{grid-template-columns:auto 1fr;gap:6px 14px;align-content:start;min-width:132px}
.acard .kv dt{font-size:12px}
.acard .kv dd{font-size:12.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:118px}
.acard .acts{
  display:flex;gap:6px;padding:10px 14px;border-top:1px solid var(--border-subtle);
}
.acard .acts .btn{flex:1}
.acard .acts .btn.icon{flex:none;width:38px;padding:0}

/* detail drawer */
.drawer{
  background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:var(--radius);
  display:flex;flex-direction:column;min-height:0;height:100%;
}
.drawer > h2{
  margin:0;padding:13px 15px;border-bottom:1px solid var(--border-subtle);
  font:400 16px/1 var(--font-display);display:flex;align-items:center;
}
.drawer > h2 .x{margin-left:auto;background:transparent;border:0;cursor:pointer;
  color:var(--text-muted);padding:2px;display:grid;place-items:center}
.drawer > h2 .x:hover{color:var(--text-primary)}
.drawer .who{display:flex;gap:11px;align-items:center;padding:10px 15px;
  border-bottom:1px solid var(--border-subtle)}
.drawer .who .n{font:400 16px/1.2 var(--font-display)}
.drawer .form{padding:13px 15px;display:flex;flex-direction:column;gap:10px;overflow-y:auto;min-height:0}
.drawer .form .field{gap:4px}
.drawer .form .field > label{font-size:11.5px}
.drawer .form .input{height:36px}
.drawer .form .pair{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.drawer .ro{display:flex;align-items:center;justify-content:space-between;gap:10px;
  font-size:13px;padding:2px 0}
.drawer .ro .k{color:var(--text-secondary);font-size:12.5px}
.drawer .ro .v{display:flex;align-items:center;gap:8px}
.drawer .acts{padding:13px 15px;border-top:1px solid var(--border-subtle);
  display:flex;flex-direction:column;gap:9px}

/* ══════════════════════════════ play ══════════════════════════════ */
/* selected-account card in the page header */
.selacc{
  display:flex;align-items:center;gap:14px;padding:10px 14px;min-width:390px;
  background:var(--bg-panel);border:1px solid var(--border-gold);border-radius:var(--radius);
}
.selacc .lbl{font-size:11.5px;color:var(--text-muted)}
.selacc .n{font:400 21px/1.15 var(--font-display);margin:1px 0 2px}
.selacc .sub{font-size:12.5px;color:var(--text-secondary)}
.selacc .meta{display:flex;align-items:center;gap:10px;margin-top:5px;font-size:12px;color:var(--text-muted)}
.selacc .pick{margin-left:auto;align-self:center}

.play-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap);min-height:0}
/* Each column scrolls on its own if its panels don't fit, so a short window never pushes the
   whole page into a scrollbar and never hides the action buttons at the bottom of a panel. */
.play-col{display:flex;flex-direction:column;gap:var(--gap);min-height:0;overflow-y:auto}
.play-col > .panel{flex:none}
/* The right column holds two list panels whose length is unbounded (accounts, public games), so
   they SHARE the height and each scrolls inside itself — otherwise a long game list pushes the
   Join buttons off the bottom. */
.play-col.split{overflow:hidden}
.play-col.split > .panel{flex:1 1 0;min-height:0}
/* the column is clipped, so each shared panel must scroll its own body or its tail is unreachable */
.play-col.split > .panel > .body{overflow-y:auto}
.play-col.split > .panel:first-child{flex-grow:1.15}
/* a panel that must show all of its content keeps its natural height; the sibling takes the rest */
.play-col.split > .panel.keep{flex:0 0 auto}
/* ONE panel filling the whole column: it takes the available height and scrolls its own body, so
   the header stays pinned and the tail of a long panel (Account & Security) stays reachable.
   Without this the column clips and the last section is simply unreachable. */
.play-col.solo{overflow:hidden}
.play-col.solo > .panel{flex:1 1 0;min-height:0}
.play-col.solo > .panel > .body{overflow-y:auto}
/* Slightly denser than the default card so both panels in a column fit 941px without scrolling. */
.play-col .panel .body{padding:14px}
.play-col .panel .foot{padding:10px 14px}
.play-col .input,.play-col .seg{height:40px}
.play-col .kv{gap:7px 20px}

.tabs{display:flex;gap:0;border-bottom:1px solid var(--border-subtle);padding:0 12px}
.tabs button{
  background:transparent;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;
  padding:11px 16px;cursor:pointer;color:var(--text-secondary);font-size:13.5px;
  display:inline-flex;align-items:center;gap:8px;white-space:nowrap;
}
.tabs button:hover{color:var(--text-primary)}
.tabs button.on{color:var(--gold-bright);border-bottom-color:var(--gold)}

.notice{
  border-radius:6px;padding:11px 13px;font-size:12.5px;display:flex;gap:10px;align-items:flex-start;
  background:rgba(105,185,107,.08);border:1px solid rgba(105,185,107,.32);
}
.notice.warn{background:rgba(213,154,69,.08);border-color:rgba(213,154,69,.35)}
.notice.info{background:rgba(96,151,189,.07);border-color:rgba(96,151,189,.3)}
.notice b{color:var(--text-primary);font-weight:500}
.notice .ic{flex:none;margin-top:1px;opacity:.85}

.pwwrap{position:relative}
.pwwrap .eye{
  position:absolute;right:6px;top:50%;transform:translateY(-50%);
  background:transparent;border:0;cursor:pointer;color:var(--text-muted);padding:6px;
}
.pwwrap .eye:hover{color:var(--text-primary)}

/* party pick list */
.pick-row{display:flex;align-items:center;gap:12px;min-height:52px;padding:6px 16px;
  border-bottom:1px solid rgba(48,43,33,.55);cursor:pointer}
.pick-row:last-child{border-bottom:0}
.pick-row:hover{background:rgba(26,27,25,.5)}
.pick-row.off{opacity:.55;cursor:not-allowed}
.pick-row .box{
  width:19px;height:19px;border-radius:4px;flex:none;display:grid;place-items:center;
  border:1px solid var(--border-subtle);background:var(--bg-input);color:transparent;font-size:12px;
}
.pick-row.on .box{background:var(--gold);border-color:var(--gold);color:#171410}
.pick-row.off .box{background:#0e0f0e}

.sess-emblem{
  width:88px;height:88px;flex:none;border-radius:6px;
  background:url(/logo) no-repeat;background-size:254px auto;background-position:-93px -7px;
  border:1px solid var(--border-gold);
}

/* ══════════════════════════════ bo barb ══════════════════════════════ */
.hero-bar{
  display:flex;align-items:center;gap:16px;padding:13px 16px;margin-bottom:var(--gap);
  background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:var(--radius);
}
.hero-bar .n{font:400 21px/1.15 var(--font-display)}
.hero-bar .lbl{font-size:11.5px;color:var(--text-muted)}
.hero-bar .facts{display:flex;gap:28px;margin-left:26px}
.hero-bar .facts .f{display:flex;flex-direction:column;gap:3px}
.hero-bar .facts .f .k{font-size:11.5px;color:var(--text-muted)}
.hero-bar .facts .f .v{font-size:13.5px}
.hero-bar .end{margin-left:auto;display:flex;align-items:center;gap:10px}

.skills{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.skill{
  display:flex;flex-direction:column;align-items:flex-start;gap:7px;padding:12px;
  background:var(--bg-panel-raised);border:1px solid var(--border-subtle);border-radius:6px;
  cursor:pointer;text-align:left;color:var(--text-primary);
}
.skill:hover:not(:disabled){border-color:var(--border-gold);background:var(--bg-panel-hover)}
.skill:disabled{opacity:.42;cursor:not-allowed}
.skill .nm{font-size:13px;line-height:1.3}
.skill .id{font-family:var(--font-mono);font-size:10.5px;color:var(--text-muted)}
.skill .ic{color:var(--gold);opacity:.9}

.bigbtn{
  width:100%;display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:13px;border-radius:6px;cursor:pointer;
  background:linear-gradient(180deg,#3a2f19,#241d10);border:1px solid var(--border-active);
  color:var(--gold-bright);
}
.bigbtn:hover:not(:disabled){background:linear-gradient(180deg,#453820,#2b2213)}
.bigbtn:disabled{opacity:.42;cursor:not-allowed}
.bigbtn .t{font-size:14px;display:flex;align-items:center;gap:8px}
.bigbtn .s{font-size:11.5px;color:var(--text-secondary);font-weight:400}
.bigbtn.plain{background:var(--bg-panel-raised);border-color:var(--border-subtle);color:var(--text-primary)}
.bigbtn.plain:hover:not(:disabled){background:var(--bg-panel-hover);border-color:var(--border-gold)}
.bigbtn.danger{background:rgba(201,91,82,.1);border-color:rgba(201,91,82,.42);color:var(--danger)}
.bigbtn.danger:hover:not(:disabled){background:rgba(201,91,82,.18)}

/* ══════════════════════════════ chat ══════════════════════════════ */
.chat-grid{display:grid;grid-template-columns:262px 1fr 288px;gap:var(--gap);min-height:0}
@media (max-width:1500px){ .chat-grid{grid-template-columns:220px 1fr 240px} }

.msgs{display:flex;flex-direction:column;gap:11px;padding:16px;overflow-y:auto;min-height:0;flex:1}
.msg{display:flex;gap:10px;align-items:flex-start;max-width:74%}
.msg .t{font-family:var(--font-mono);font-size:11px;color:var(--text-muted);flex:none;padding-top:9px}
.msg .bubble{
  background:var(--bg-panel-raised);border:1px solid var(--border-subtle);
  border-radius:8px;padding:7px 11px;min-width:0;
}
.msg .who{font-size:12px;color:var(--gold);margin-bottom:2px}
.msg .tx{font-size:13.5px;color:var(--text-primary);word-wrap:break-word;white-space:pre-wrap}
.msg.own{align-self:flex-end;flex-direction:row-reverse}
.msg.own .bubble{background:rgba(197,165,93,.1);border-color:var(--border-gold)}
.msg.own .who{color:var(--gold-bright);text-align:right}
.msg.sys{max-width:100%;align-self:center}
.msg.sys .bubble{background:rgba(96,151,189,.07);border-color:rgba(96,151,189,.28)}
.msg.sys .tx{color:var(--info);font-size:12.5px}
.daysep{display:flex;align-items:center;gap:12px;color:var(--text-muted);font-size:11.5px;margin:4px 0}
.daysep::before,.daysep::after{content:"";flex:1;height:1px;background:var(--border-subtle)}

.composer{display:flex;gap:9px;align-items:center;padding:12px 14px;border-top:1px solid var(--border-subtle)}
.composer .input{flex:1}
.composer .hint{font-size:11px;color:var(--text-muted);padding:0 14px 10px}

.chanrow{
  display:flex;align-items:center;gap:9px;width:100%;padding:8px 12px;border-radius:6px;
  background:transparent;border:1px solid transparent;cursor:pointer;color:var(--text-secondary);
  font-size:13px;text-align:left;
}
.chanrow:hover{background:var(--bg-panel-hover);color:var(--text-primary)}
.chanrow.on{background:rgba(197,165,93,.1);border-color:var(--border-gold);color:var(--gold-bright)}
.chanrow .hash{color:var(--text-muted)}
.chanrow .n{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chanrow .cnt{font-size:11px;color:var(--text-muted);font-family:var(--font-mono)}
.unread{
  min-width:19px;height:19px;padding:0 6px;border-radius:10px;display:grid;place-items:center;
  background:var(--gold);color:#171410;font-size:11px;font-weight:600;
}

/* ══════════════════════════════ logs ══════════════════════════════ */
.logs-grid{display:grid;grid-template-columns:1fr 336px;gap:var(--gap);min-height:0}
@media (max-width:1500px){ .logs-grid{grid-template-columns:1fr 288px} }

table.logtbl{width:100%;border-collapse:collapse;table-layout:fixed}
table.logtbl th{
  position:sticky;top:0;z-index:1;background:var(--bg-panel);
  text-align:left;font-size:11.5px;font-weight:500;color:var(--text-muted);
  padding:9px 12px;border-bottom:1px solid var(--border-subtle);white-space:nowrap;
}
table.logtbl td{padding:7px 12px;border-bottom:1px solid rgba(48,43,33,.42);font-size:12.5px;
  vertical-align:top}
table.logtbl tbody tr{cursor:pointer}
table.logtbl tbody tr:hover{background:rgba(26,27,25,.6)}
table.logtbl tbody tr.sel{background:rgba(197,165,93,.09)}
table.logtbl tbody tr.err td{background:rgba(201,91,82,.07)}
table.logtbl tbody tr.err.sel td{background:rgba(201,91,82,.13)}
table.logtbl td.msg{white-space:pre-wrap;word-break:break-word;color:var(--text-secondary)}
table.logtbl td.mono{font-family:var(--font-mono);font-size:11.5px;color:var(--text-muted)}

/* level chips — the point is that ok/warn/error are NOT all the same colour */
.lvl{
  display:inline-block;min-width:64px;text-align:center;padding:2px 7px;border-radius:4px;
  font-size:10px;font-weight:600;letter-spacing:.4px;border:1px solid;
}
.lvl.muted{color:#7b756c;border-color:#3a352c;background:#131413}
.lvl.info,.lvl.system{color:var(--info);border-color:rgba(96,151,189,.4);background:rgba(96,151,189,.09)}
.lvl.ok{color:var(--success);border-color:rgba(105,185,107,.4);background:rgba(105,185,107,.09)}
.lvl.warn{color:var(--warning);border-color:rgba(213,154,69,.42);background:rgba(213,154,69,.09)}
.lvl.error{color:var(--danger);border-color:rgba(201,91,82,.45);background:rgba(201,91,82,.1)}

.svc{font-size:11.5px;color:var(--text-secondary)}
.svc.none{color:#5c574f}

.sumgrid{display:grid;grid-template-columns:repeat(2,1fr);gap:9px}
.sumcell{
  border:1px solid var(--border-subtle);border-radius:6px;padding:9px 11px;background:var(--bg-panel-raised);
}
.sumcell .k{font-size:11.5px;color:var(--text-muted)}
.sumcell .v{font:600 20px/1.2 var(--font-display)}
.sumcell.error .v{color:var(--danger)}
.sumcell.warn .v{color:var(--warning)}
.sumcell.info .v{color:var(--info)}
.sumcell.muted .v{color:var(--text-muted)}

.toggle{
  display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:13px;
  color:var(--text-secondary);user-select:none;
  /* it is a <button>, so the UA's own background/border/padding must be cleared or the whole
     control sits on a light pill in a dark UI */
  background:transparent;border:0;padding:0;
}
.toggle .track{
  width:38px;height:21px;border-radius:11px;background:#211f1a;border:1px solid var(--border-subtle);
  position:relative;transition:background .14s;flex:none;
}
.toggle .track::after{
  content:"";position:absolute;left:2px;top:2px;width:15px;height:15px;border-radius:50%;
  background:#6b655c;transition:transform .14s,background .14s;
}
.toggle.on .track{background:rgba(197,165,93,.28);border-color:var(--border-gold)}
.toggle.on .track::after{transform:translateX(17px);background:var(--gold)}
.toggle.on{color:var(--text-primary)}

/* ══════════════════════════════ profile ══════════════════════════════ */
.avatars{display:grid;grid-template-columns:repeat(8,1fr);gap:10px}
.avatar-pick{
  background:transparent;border:0;padding:0;cursor:pointer;display:flex;
  flex-direction:column;align-items:center;gap:6px;border-radius:8px;
}
.avatar-pick .port{opacity:.55;transition:opacity .12s,transform .12s}
.avatar-pick:hover .port{opacity:.85}
.avatar-pick.on .port{opacity:1;transform:translateY(-2px)}
.avatar-pick .nm{font-size:10.5px;color:var(--text-muted);text-transform:capitalize}
.avatar-pick.on .nm{color:var(--gold-bright)}


/* toast */
.toasts{position:fixed;right:20px;bottom:20px;display:flex;flex-direction:column;gap:9px;z-index:200}
.toast{
  background:var(--bg-panel-raised);border:1px solid var(--border-gold);border-radius:var(--radius);
  padding:11px 15px;font-size:13px;box-shadow:0 14px 34px rgba(0,0,0,.55);max-width:380px;
  animation:tin .18s ease-out;
}
.toast.err{border-color:rgba(201,91,82,.6)}
@keyframes tin{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* Dashboard: the panels on the left, the user list as a full-height rail on the right. The rail
   is fixed-width because a member list has nothing to gain from being wider, and the panels do. */
.dash-wrap{display:grid;grid-template-columns:1fr 292px;gap:var(--gap);min-height:0}
.dash-main{display:flex;flex-direction:column;min-width:0;min-height:0}
.dash-wrap > .panel{min-height:0}
@media (max-width:1400px){
  .dash-wrap{grid-template-columns:1fr 250px}
}

/* ══════════════════════════ who else is here ══════════════════════════ */
/* A chat-style member list: a small grey group heading with a count, then a row per person with
   their portrait, handle and what they are doing. */
.mgroup{
  padding:14px 14px 6px;font-size:11px;font-weight:600;letter-spacing:.9px;
  text-transform:uppercase;color:var(--text-muted);
}
.mgroup:first-child{padding-top:10px}
.mrow{display:flex;align-items:center;gap:11px;padding:6px 14px;min-width:0}
.mrow .ava{position:relative;flex:none}
.mrow .ava .port{width:32px;height:32px}
.mrow .who{min-width:0;flex:1}
.mrow .who .n{
  font-size:13.5px;font-weight:500;color:var(--text-primary);
  display:flex;align-items:center;gap:6px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
/* The owner's handle is gold, the way a chat client colours a role. */
.mrow .who .n.admin{color:var(--gold-bright)}
.mrow .who .n .you{
  font-size:9.5px;letter-spacing:.4px;text-transform:uppercase;color:var(--text-muted);
  border:1px solid var(--border-subtle);border-radius:3px;padding:1px 4px;flex:none;
}
.mrow .who .s{font-size:11.5px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Offline is dimmed rather than hidden — knowing who exists is half the point of the list. */
.mrow.off{opacity:.42}

/* The presence light. Green and slowly breathing while online, flat grey when not. The pulse is
   ~2.6s and only touches opacity and the halo, so it costs nothing and never draws the eye away
   from the panel you are actually working in. */
.mrow .pip{
  position:absolute;right:-2px;bottom:-2px;width:11px;height:11px;border-radius:50%;
  background:#3a3730;border:2px solid var(--bg-panel);
}
.mrow .pip.live{background:var(--success);animation:pulse 2.6s ease-in-out infinite}
@keyframes pulse{
  0%,100%{opacity:1;box-shadow:0 0 0 0 rgba(105,185,107,.55)}
  50%    {opacity:.55;box-shadow:0 0 0 4px rgba(105,185,107,0)}
}
/* Someone who asked not to see motion should not have a light throbbing at them. */
@media (prefers-reduced-motion:reduce){
  .mrow .pip.live{animation:none}
}

/* ══════════════════════════════ renting ══════════════════════════════ */
/* Three states, three colours, and the label says which — the tint is a second signal, never the
   only one. Gold = out on loan, blue = borrowed, muted = offered but untaken. */
.badge.rent{border-color:var(--border-gold);color:var(--gold);letter-spacing:.2px}
.badge.rent.in{border-color:rgba(96,151,189,.55);color:var(--info)}
.badge.rent.off{border-color:var(--border-subtle);color:var(--text-muted)}

/* An account currently out on loan: still listed, visibly not yours to drive. The dimming is
   cosmetic — the server is what actually refuses the actions. */
.acard.lent{opacity:.72}
.acard.lent .ident{filter:grayscale(.5)}

.panel.offers{margin-bottom:var(--gap);border-color:var(--border-gold)}
.panel.offers .foot{font-size:11.5px;color:var(--text-muted);line-height:1.5}

.modal .hint{font-size:11.5px;line-height:1.5;margin-top:2px}
.modal .body p:last-child{margin-bottom:0}

/* Sub-heading inside a panel body — Account & Security stacks four of these, and they need to
   read as sections without each one becoming its own bordered panel. */
.sec-h{
  display:flex;align-items:center;gap:8px;margin-bottom:10px;
  font:600 13px/1 var(--font-display);letter-spacing:.3px;color:var(--text-primary);
}
.sec-h .ic{opacity:.8}
.sec-h .right{margin-left:auto;display:flex;align-items:center;gap:6px}
.panel .body .hint{font-size:11.5px;color:var(--text-muted);line-height:1.5}
.panel .body .hint.bad{color:var(--danger)}
.input:disabled{opacity:.55;cursor:not-allowed}

/* ══════════════════════════════ admin ══════════════════════════════ */
/* A code shown exactly once — a reset ticket or a registration code. Large, monospaced and
   letter-spaced because it gets read out of the screen and typed into a chat window. */
.onetime{
  font:600 22px/1.5 var(--font-mono);letter-spacing:.14em;text-align:center;
  color:var(--gold-bright);background:var(--bg-input);
  border:1px solid var(--border-gold);border-radius:var(--radius);
  padding:16px 12px;user-select:all;word-break:break-all;
}
.panel .foot.muted{font-size:11.5px;color:var(--text-muted);line-height:1.5}

/* modal / confirm */
.scrim{position:fixed;inset:0;background:rgba(4,4,4,.72);display:grid;place-items:center;z-index:150}
.modal{
  width:440px;max-width:calc(100vw - 40px);
  background:var(--bg-panel);border:1px solid var(--border-gold);border-radius:var(--radius);
  box-shadow:0 26px 60px rgba(0,0,0,.7);
}
.modal h3{margin:0;padding:15px 18px;border-bottom:1px solid var(--border-subtle);
  font:600 16px/1 var(--font-display)}
.modal .body{padding:18px}
.modal .foot{padding:13px 18px;border-top:1px solid var(--border-subtle);
  display:flex;gap:10px;justify-content:flex-end}

/* ══════════════════════════════ responsive ══════════════════════════════ */
@media (max-width:1500px){
  :root{--sidebar-w:224px;--pad:22px}
  .page-head h1{font-size:34px}
}
@media (max-width:1280px){
  :root{--sidebar-w:68px;--pad:18px}
  .sidebar .brand{padding:0 8px}
  .sidebar .brand .wordmark{font-size:19px;letter-spacing:.08em;text-indent:.08em}
  .sidebar .brand .wordmark .full{display:none}
  .sidebar .brand .wordmark .short{display:inline}
  .nav a{justify-content:center;padding:0}
  .nav a span.t{display:none}
  .sidebar .sigil{width:120px}
  .g-4{grid-template-columns:repeat(2,1fr)}
  .g-12,.g-3{grid-template-columns:1fr}
}
