:root{
  --page:#eef1f3; --card:#ffffff; --panel:#f5f7f8;
  --line:#e4e7ea; --line-strong:#d2d7db;
  --tx:#1b2126; --tx2:#5b656d; --tx3:#97a0a8;
  --header:#1C4E4E; --header-tx:#eef4f3; --header-dim:#a7c4c2;
  --accent:#1C4E4E; --accent-bg:#e2edec; --accent-tx:#123f3f;
  --ok:#12923f; --ok-bg:#e7f4ea; --ok-tx:#1f7a34;
  --warn:#c07d00; --warn-bg:#fbf1da; --warn-tx:#875600;
  --bad:#d03b3b; --bad-bg:#fbe9e9; --bad-tx:#a32d2d;
  --pro:#8a2b52; --pro-bg:#f7e9f0;
  /* sign-in brand palette, sampled from tracxion-teal.png and bg.jpg */
  --brand-dark:#18443c; --brand-mark:#64c6b7;
  --brand-teal:#38817a; --brand-teal-h:#2f746d;
  --brand-sub:#8a6d3b; --auth-fallback:#1f7872;
}
*{box-sizing:border-box}
body{margin:0;font:13px/1.45 "Segoe UI",Roboto,Arial,sans-serif;color:var(--tx);background:var(--page)}

/* top bar */
.topbar{display:flex;align-items:center;gap:16px;background:var(--header);
  padding:0 18px;height:52px;position:sticky;top:0;z-index:5}
.brand{font-weight:500;font-size:16px;letter-spacing:.2px;color:var(--header-tx)}
.topbar nav{display:flex;gap:2px;flex:1}
.topbar nav a{color:var(--header-dim);text-decoration:none;padding:6px 12px;border-radius:8px;font-size:13px}
.topbar nav a:hover{background:rgba(255,255,255,.12);color:#fff}
.topbar nav a.on{background:rgba(255,255,255,.16);color:#fff;font-weight:500}
.status{display:flex;align-items:center;gap:10px;font-size:12px;color:var(--header-dim)}
.clock{font-variant-numeric:tabular-nums;font-weight:500;color:var(--header-tx)}
.dot{width:8px;height:8px;border-radius:50%;display:inline-block;background:var(--bad)}
.dot.on{background:var(--ok)} .dot.off{background:var(--bad)}
.dot.sl-ok{background:var(--ok)} .dot.sl-warn{background:var(--warn)}
.dot.sl-bad{background:var(--bad)} .dot.sl-na{background:#b7c0c8}
.datastatus{font-size:12px}
main{padding:16px 18px 72px}

/* footer pinned to the bottom of the window */
.sitefooter{position:fixed;left:0;right:0;bottom:0;z-index:5;
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  background:var(--header);color:var(--header-tx);padding:12px 18px;font-size:12px}
.footer-left{line-height:1.5}
.footer-sub{color:var(--header-dim)}
.footer-right{display:flex;align-items:center;gap:10px;color:var(--header-dim)}
.footer-logo{height:22px;display:block}

/* settings modal */
.modal-overlay{position:fixed;inset:0;background:rgba(20,30,30,.45);display:flex;
  align-items:center;justify-content:center;z-index:20}
.modal{background:var(--card);border-radius:12px;border:1px solid var(--line);
  padding:20px 22px;width:420px;max-width:92vw}
.modal h3{margin:0 0 4px;font-size:16px;font-weight:500}
.modal h4{margin:14px 0 4px;font-size:14px;font-weight:500}
.modal code{background:var(--panel);padding:1px 6px;border-radius:6px;font-family:Consolas,monospace}
.modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}
.btn-ghost{background:transparent;color:var(--tx2);border:1px solid var(--line-strong)}
.btn-ghost:hover{background:var(--panel);color:var(--tx)}
.btn-danger{background:var(--bad);color:#fff;border-color:var(--bad)}
.btn-danger:hover{background:#b23434}
.btn-danger:disabled{background:#e2b6b6;border-color:#e2b6b6;cursor:not-allowed}
.viewtitle{font-size:13px;font-weight:400;margin:18px 2px 8px;color:var(--tx2)}
.hint{color:var(--tx2);margin:4px 2px}

/* tables */
.gridwrap{overflow:auto;background:var(--card);border:1px solid var(--line);border-radius:12px}
table.grid{border-collapse:collapse;width:100%;font-size:13px}
table.grid th{color:var(--header-tx);font-weight:500;text-align:left;padding:9px 12px;white-space:nowrap;
  position:sticky;top:0;background:var(--header)}
table.grid td{padding:8px 12px;border-top:1px solid var(--line);white-space:nowrap;font-variant-numeric:tabular-nums}
table.grid th.sortable{cursor:pointer;user-select:none}
table.grid th.sortable:hover{color:#fff}
table.grid th.sorted{color:#fff}
table.grid tbody tr:hover td{background:var(--panel)}
.mono{font-family:Consolas,monospace}
.num{text-align:right}
table.grid tr.loggedout td{color:var(--tx3)}
table.grid tr.loggedout .chip{opacity:.7}

/* calm conditional formatting: coloured value + leading dot, never a filled cell */
.c-green{color:var(--ok);font-weight:500}
.c-amber{color:var(--warn);font-weight:500}
.c-red{color:var(--bad);font-weight:500}
.c-green::before,.c-amber::before,.c-red::before{content:"";display:inline-block;width:7px;height:7px;
  border-radius:50%;background:currentColor;margin-right:6px;vertical-align:1px}

/* state chips (soft tints) */
.chip{display:inline-block;padding:2px 9px;border-radius:8px;font-size:12px;font-weight:500}
.s-Available,.s-Talk{background:var(--ok-bg);color:var(--ok-tx)}
.s-AUX,.s-Ringing{background:var(--warn-bg);color:var(--warn-tx)}
.s-ACW,.s-Webchat{background:var(--accent-bg);color:var(--accent-tx)}
.s-Hold{background:var(--pro-bg);color:var(--pro)}
.s-Logout{background:var(--panel);color:var(--tx3)}
.s-Idle{background:var(--panel);color:var(--tx2)}

/* wallboard */
.wallboard{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px}
.qcard{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px;position:relative}
/* pinned strip + hover controls */
.pinnedwrap{margin:0 0 8px}
.pinnedlabel{font-size:12px;color:var(--tx2);font-weight:500;margin:2px 2px 6px;display:flex;align-items:center;gap:6px}
.pinnedlabel .pinstar{color:var(--warn)}
.qcard.pinned{border-color:var(--accent)}
.qctrls{position:absolute;top:8px;right:8px;display:flex;gap:4px;align-items:center;opacity:0;transition:opacity .12s}
.qcard:hover .qctrls{opacity:1}
.qstar{background:transparent;border:none;padding:2px;cursor:pointer;color:var(--tx3);line-height:0}
.qstar svg{display:block;fill:currentColor}
.qstar:hover{color:var(--warn);background:transparent}
.qcard.pinned .qstar{color:var(--warn)}
.qdrag{color:var(--tx3);cursor:grab;line-height:0;display:none;padding:2px}
.qcard.pinned .qdrag{display:inline-block}
.qdrag:active{cursor:grabbing}
.sortable-ghost{opacity:.35}
.sortable-chosen{box-shadow:0 6px 18px rgba(0,0,0,.18)}
.qhead{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.qname{font-weight:500;font-size:14px}
.qdot{width:9px;height:9px;border-radius:50%;display:inline-block}
.pill{margin-left:auto;font-size:12px;padding:2px 9px;border-radius:8px;font-weight:500}
.pill.ok{background:var(--ok-bg);color:var(--ok-tx)}
.pill.warn{background:var(--warn-bg);color:var(--warn-tx)}
.pill.bad{background:var(--bad-bg);color:var(--bad-tx)}
.pill.na{background:var(--panel);color:var(--tx3)}
.qhero{display:flex;align-items:baseline;gap:6px}
.qhero .big{font-size:38px;font-weight:600;font-variant-numeric:tabular-nums;line-height:1}
.qhero .lbl{font-size:13px;color:var(--tx2)}
.qmeter{height:6px;border-radius:6px;background:var(--panel);margin:9px 0 12px;overflow:hidden}
.qmeter div{height:100%;border-radius:6px}
.qmetrics{display:grid;grid-template-columns:1fr 1fr;gap:9px 12px}
.qmetrics .k{font-size:12px;color:var(--tx3)}
.qmetrics .v{font-size:16px;font-weight:500;font-variant-numeric:tabular-nums}
.qmetrics .v.muted{color:var(--tx3)}
.emptynote{background:var(--card);border:1px solid var(--line);border-radius:12px;
  padding:16px;color:var(--tx2);max-width:560px;line-height:1.6}

/* editor */
.editcols{display:flex;gap:14px;flex-wrap:wrap;align-items:flex-start}
.card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px;min-width:320px;flex:1}
.card h3{margin:0 0 4px;font-size:15px;font-weight:500}
.card h4{margin:14px 0 6px;color:var(--tx2);font-weight:500;font-size:13px}
/* editor tables must fit inside their (now narrower) card, not overflow onto the
   next card -- allow cells to wrap and keep the whole card clipped as a safety net */
.editcols .card{min-width:0;overflow:hidden}
.editcols table.grid{table-layout:auto}
.editcols table.grid th,.editcols table.grid td{white-space:normal}
.editcols .mono{word-break:break-all;font-size:12px}
.editcols select{max-width:100%}
form.inline{margin:0;max-width:100%} form.stack{display:flex;gap:6px;flex-wrap:wrap;margin-top:6px}
select,input,button{font:inherit;padding:5px 8px;border:1px solid var(--line-strong);
  border-radius:8px;background:var(--card);color:var(--tx)}
select:hover{border-color:var(--tx3)}
button{background:var(--accent);color:#fff;border-color:var(--accent);cursor:pointer;font-weight:500}
button:hover{background:#163e3e}
.tbtn{background:transparent;color:var(--tx2);border:1px solid var(--line-strong);border-radius:8px;
  padding:3px 8px;font-size:12px;font-weight:400;cursor:pointer}
.tbtn:hover{background:var(--panel);color:var(--tx)}
.tbtn.danger:hover{background:var(--bad-bg);color:var(--bad-tx);border-color:var(--bad)}
table.grid tr.hiddenq td{color:var(--tx3)}

/* icon buttons (inline SVG, no icon font) */
.iconbtn{background:transparent;border:1px solid var(--line-strong);border-radius:8px;padding:4px 7px;
  color:var(--tx2);cursor:pointer;display:inline-flex;align-items:center;line-height:0}
.iconbtn:hover{background:var(--panel);color:var(--tx)}
.iconbtn.danger:hover{background:var(--bad-bg);color:var(--bad-tx);border-color:var(--bad)}
.iconbtn svg{display:block}
.slinput{width:64px}
.qnameinput{width:100%;min-width:120px}

/* editor tabs */
.tabs{display:flex;gap:2px;border-bottom:1px solid var(--line);margin:6px 0 16px}
.tab{background:transparent;border:none;border-radius:0;color:var(--tx2);padding:9px 16px;font-size:14px;
  font-weight:500;cursor:pointer;border-bottom:2px solid transparent}
.tab:hover{background:transparent;color:var(--tx)}
.tab.on{color:var(--accent-tx);border-bottom-color:var(--accent)}
.hidden{display:none}

/* export / import */
.dlrow{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.dlbtn{display:inline-block;background:var(--accent);color:#fff;border:1px solid var(--accent);
  border-radius:8px;padding:6px 12px;text-decoration:none;font-weight:500}
.dlbtn:hover{background:#163e3e}
.importrow{display:flex;align-items:center;gap:10px;margin:8px 0;flex-wrap:wrap}
.importlabel{min-width:110px;font-weight:500}
.impprogress{display:none;flex:1;min-width:120px;max-width:240px;height:8px;background:var(--panel);
  border:1px solid var(--line);border-radius:6px;overflow:hidden}
.impbar{height:100%;width:0;background:var(--accent);transition:width .2s}
.impstatus{font-size:12px;color:var(--tx2);min-width:120px}

/* editor per-tab reset (danger zone) */
.dangerzone{display:flex;align-items:center;gap:10px;margin-top:16px;padding-top:12px;
  border-top:1px solid var(--line)}
.dangerlabel{font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--tx3)}
.dangerzone form{margin:0}

/* editor server-side pager */
.editpager{display:flex;align-items:center;gap:10px;margin:12px 2px 2px;font-size:12px;
  color:var(--tx2);flex-wrap:wrap}
.editpager .pagesizewrap{display:flex;align-items:center;gap:6px}
.editpager select{padding:3px 6px}
.editpager .pagerinfo{color:var(--tx3)}
.tbtn.dis{opacity:.45;cursor:default}
a.tbtn{text-decoration:none;display:inline-block}

/* by-team title row with filter */
.titlerow{display:flex;align-items:center;gap:12px;margin:18px 2px 8px}
.titlerow .viewtitle{margin:0}
.titlerow .spacer{flex:1}
.teamfilter{min-width:150px}
.pagesize{min-width:70px}
.pager{display:flex;justify-content:flex-end;margin:8px 2px 0}
.pagerinner{display:flex;align-items:center;gap:10px;font-size:12px;color:var(--tx2)}
.pagernum{font-variant-numeric:tabular-nums}
.tbtn:disabled{opacity:.45;cursor:default}

/* ---- settings modal: Claude section ---- */
.settings-section{margin:4px 0 0}
.settings-div{border:none;border-top:1px solid var(--line);margin:16px 0}
.btn-primary{background:var(--accent);color:#fff;border-color:var(--accent)}
.btn-primary:hover{background:#163e3e}
.ai-check{display:flex;align-items:center;gap:8px;font-size:14px;margin:2px 0 2px;cursor:pointer}
.ai-check input{width:auto;margin:0}
/* toggle switch (replaces plain checkboxes in the settings modal) */
.toggle{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:14px;margin:2px 0}
.toggle input{position:absolute;opacity:0;width:0;height:0}
.toggle-slider{position:relative;flex:none;width:38px;height:22px;background:var(--line-strong);
  border-radius:11px;transition:background .15s}
.toggle-slider::before{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;
  background:#fff;border-radius:50%;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s}
.toggle input:checked + .toggle-slider{background:var(--accent)}
.toggle input:checked + .toggle-slider::before{transform:translateX(16px)}
.toggle input:focus-visible + .toggle-slider{outline:2px solid var(--accent);outline-offset:2px}
.toggle-label{color:var(--tx)}
.ai-field{display:block;margin-top:8px;font-size:12px;color:var(--tx2)}
.ai-field select{display:block;width:100%;margin-top:4px;color:var(--tx)}

/* ---- Claude assistant: launcher + chat panel ---- */
.ai-launcher{position:fixed;right:20px;bottom:120px;z-index:60;width:48px;height:48px;border-radius:50%;
  padding:0;display:none;align-items:center;justify-content:center;background:var(--accent);color:#fff;
  border:none;box-shadow:0 4px 14px rgba(0,0,0,.22);cursor:pointer}
.ai-launcher:hover{background:#163e3e}
.ai-launcher svg{display:block}
.ai-panel{position:fixed;right:20px;bottom:120px;z-index:61;width:590px;max-width:calc(100vw - 40px);
  height:min(70vh,580px);display:none;flex-direction:column;background:var(--card);border:1px solid var(--line);
  border-radius:14px;box-shadow:0 10px 34px rgba(0,0,0,.24);overflow:hidden}
.ai-head{display:flex;align-items:center;gap:10px;padding:11px 14px;background:var(--header);color:var(--header-tx)}
.ai-titlewrap{display:flex;flex-direction:column;line-height:1.2}
.ai-title{font-weight:500;font-size:14px}
.ai-sub{font-size:11px;color:var(--header-dim)}
.ai-head .spacer{flex:1}
.ai-iconbtn{background:transparent;border:1px solid var(--header-dim);color:var(--header-tx);border-radius:7px;
  padding:3px 9px;font-size:12px;font-weight:400;cursor:pointer}
.ai-iconbtn:hover{background:rgba(255,255,255,.12)}
.ai-messages{flex:1;overflow-y:auto;padding:14px;display:flex;flex-direction:column;gap:10px;background:var(--page)}
.ai-msg{max-width:90%;padding:9px 12px;border-radius:12px;font-size:13px;line-height:1.5;word-wrap:break-word}
.ai-user{align-self:flex-end;background:var(--accent);color:#fff;border-bottom-right-radius:4px;white-space:pre-wrap}
.ai-assistant{align-self:flex-start;background:var(--card);border:1px solid var(--line);color:var(--tx);
  border-bottom-left-radius:4px}
.ai-empty{color:var(--tx2);font-size:13px;line-height:1.6}
.ai-empty ul{margin:6px 0;padding-left:0;list-style:none;display:flex;flex-direction:column;gap:6px}
.ai-suggest{background:var(--accent-bg);color:var(--accent-tx);border-radius:8px;padding:7px 10px;cursor:pointer}
.ai-suggest:hover{background:#d3e6e4}
.ai-fine{color:var(--tx3);font-size:12px;margin-top:8px}
/* markdown + tables inside an assistant bubble */
.ai-md{font-size:13px}
.ai-md p{margin:0 0 8px} .ai-md p:last-child{margin-bottom:0}
.ai-md ul,.ai-md ol{margin:0 0 8px;padding-left:20px}
.ai-md code{background:var(--panel);border-radius:4px;padding:1px 4px;font-size:12px}
.ai-md pre{background:var(--panel);border-radius:8px;padding:8px;overflow:auto;font-size:12px}
.ai-md table{border-collapse:collapse;width:100%;margin:4px 0 8px;font-size:12px}
.ai-md th,.ai-md td{border:1px solid var(--line);padding:4px 8px;text-align:left;white-space:nowrap;
  font-variant-numeric:tabular-nums}
.ai-md th{background:var(--panel);font-weight:500}
.ai-chart{position:relative;height:230px;margin:6px 0 4px}
.ai-inputrow{display:flex;gap:8px;padding:10px;border-top:1px solid var(--line);align-items:flex-end}
.ai-input{flex:1;resize:none;max-height:120px;border:1px solid var(--line-strong);border-radius:9px;
  padding:8px 10px;font-size:13px;color:var(--tx);background:var(--card)}
.ai-send{padding:8px 14px;border-radius:9px}
.ai-send:disabled{opacity:.55;cursor:default}
.ai-note{padding:0 12px 8px;font-size:11px;color:var(--warn-tx);min-height:0}
.ai-thinking{padding:12px 14px}
.ai-dots{display:inline-flex;gap:4px}
.ai-dots i{width:6px;height:6px;border-radius:50%;background:var(--tx3);display:inline-block;
  animation:aiblink 1.2s infinite both}
.ai-dots i:nth-child(2){animation-delay:.2s}
.ai-dots i:nth-child(3){animation-delay:.4s}
@keyframes aiblink{0%,80%,100%{opacity:.25}40%{opacity:1}}

/* ============================================================
   authentication screens (sign-in, SSO, MFA, setup, maintenance)

   Styled to the tracxion sign-in card: full-bleed brand wallpaper, no top bar, no nav,
   one centred white card carrying the wordmark. Nothing is reachable until you are signed
   in, so the usual chrome would only be furniture.

   Restyling is scoped under .authbody. The shared .field / .fieldlabel / .btn-primary
   rules below are used by the admin and dashboard forms too, so they keep their existing
   values and the sign-in look is layered on top rather than baked into them.
   ============================================================ */
.authbody{min-height:100vh;
  /* Relative URL, so it resolves against app.css and survives a reverse-proxy sub-path.
     The flat colour shows if the image is missing -- text stays legible either way. */
  background:var(--auth-fallback) url("bg.jpg") center center / cover no-repeat}
.authbody main.authwrap{display:flex;flex-direction:column;align-items:center;
  justify-content:center;min-height:100vh;padding:32px 18px;gap:18px}
.authcard{background:var(--card);border:0;border-radius:10px;
  padding:30px 30px 32px;width:400px;max-width:94vw;box-shadow:0 18px 50px rgba(0,0,0,.3)}
.authcard-wide{width:470px}      /* QR codes and recovery-code grids need the room */

.authlogo{display:block;width:215px;max-width:72%;height:auto;margin:0 auto 16px}
.authtitle{margin:0 0 4px;font-size:17px;font-weight:600;line-height:1.35;
  color:var(--brand-dark);text-align:center}
.authsub{margin:0 0 20px;color:var(--brand-sub);font-size:13px;line-height:1.5;
  text-align:center;text-wrap:pretty}
/* Anything longer than a line or two reads badly centred, so those opt out. */
.authsub-long{text-align:left;color:var(--tx2)}
.authfoot{margin:0;font-size:12px;color:rgba(255,255,255,.72);text-align:center;
  text-shadow:0 1px 2px rgba(0,0,0,.35)}

.authform{display:block;margin:0}
.field{display:block;margin:0 0 14px}
.fieldlabel{display:block;font-size:12px;font-weight:500;color:var(--tx2);margin:0 0 5px}
.field input{width:100%;padding:8px 10px;font-size:14px}
.field input:focus{outline:2px solid var(--accent);outline-offset:-1px;border-color:var(--accent)}
.fieldhint{display:block;margin:5px 1px 0;font-size:12px;color:var(--tx3);line-height:1.45}

/* Roomier fields and a full-width teal action, as on the tracxion card. */
.authbody .field{margin:0 0 16px}
.authbody .fieldlabel{font-size:13px;font-weight:400;color:var(--brand-dark);margin:0 0 6px}
.authbody .field input{padding:9px 11px;border-radius:6px}
.authbody .field input:focus{outline:2px solid var(--brand-teal);outline-offset:-1px;
  border-color:var(--brand-teal)}
.authsubmit{width:100%;margin-top:6px;padding:10px 12px;font-size:14px;border-radius:6px}
.authbody .btn-primary{background:var(--brand-teal);border-color:var(--brand-teal);color:#fff}
.authbody .btn-primary:hover{background:var(--brand-teal-h);border-color:var(--brand-teal-h)}
.authbody .btn-primary:disabled{background:var(--brand-mark);border-color:var(--brand-mark)}

.autherr{background:var(--bad-bg);color:var(--bad-tx);border:1px solid #f0d0d0;
  border-radius:8px;padding:9px 11px;margin:0 0 16px;font-size:13px}
.authmsg{border-radius:8px;padding:9px 11px;margin:0 0 16px;font-size:13px}
.authinfo{background:var(--accent-bg);color:var(--accent-tx);border:1px solid #cfe0df}
.authwarn{background:var(--warn-bg);color:var(--warn-tx);border:1px solid #efdcb4}
.authnote{margin:16px 0 0;font-size:12px;color:var(--tx2);text-align:center;line-height:1.5}
.authnote a{color:var(--brand-teal-h);text-decoration:none}
.authnote a:hover{text-decoration:underline}

/* "or continue with your organisation account" -- the Microsoft / OIDC button. Kept as a
   quieter outline so the local sign-in stays the primary action. */
.authsep{display:flex;align-items:center;gap:10px;margin:20px 0 16px;color:var(--tx3);font-size:12px}
.authsep::before,.authsep::after{content:"";flex:1;height:1px;background:var(--line)}
.authsso{display:block;text-align:center;padding:10px 12px;border-radius:6px;font-size:14px;
  font-weight:500;text-decoration:none;color:var(--brand-dark);background:#fff;
  border:1px solid var(--line-strong)}
.authsso:hover{background:var(--panel);border-color:var(--brand-teal)}

/* MFA enrolment */
.qrbox{display:flex;justify-content:center;background:#fff;border:1px solid var(--line);
  border-radius:10px;padding:12px;margin:0 0 14px}
.qrbox svg{width:196px;height:196px;display:block}
.qrmanual{margin:0 0 18px;font-size:12px}
.qrmanual summary{cursor:pointer;color:var(--accent);user-select:none}
.qrmanual summary:hover{text-decoration:underline}
.secretkey{display:block;font-family:Consolas,monospace;font-size:13px;letter-spacing:.6px;
  background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:8px 10px;
  margin:6px 0;word-break:break-all}
.codeinput{font-family:Consolas,monospace;font-size:20px;letter-spacing:5px;text-align:center}

/* recovery codes */
.codes{list-style:none;display:grid;grid-template-columns:1fr 1fr;gap:6px 12px;
  margin:0 0 16px;padding:14px;background:var(--panel);border:1px solid var(--line);
  border-radius:10px;font-family:Consolas,monospace;font-size:14px;letter-spacing:.5px}
.codeactions{display:flex;gap:8px;margin:0 0 18px}
.codeactions button{flex:1}
.confirmtoggle{margin:0 0 14px}

.deniedcard{max-width:560px;margin:24px auto}
.btn-linkish{display:inline-block;margin-top:6px;padding:6px 12px;border-radius:8px;
  background:var(--accent);color:#fff;text-decoration:none;font-weight:500;font-size:13px}
.btn-linkish:hover{background:#163e3e}

/* top-bar account menu: identity, role and every account action behind one avatar */
.usermenu-wrap{position:relative}
.avatar{width:30px;height:30px;border-radius:50%;border:1px solid rgba(255,255,255,.28);
  background:rgba(255,255,255,.14);color:var(--header-tx);font-size:12px;font-weight:600;
  letter-spacing:.3px;cursor:pointer;display:flex;align-items:center;justify-content:center;
  padding:0}
.avatar:hover{background:rgba(255,255,255,.26)}
.avatar:focus-visible{outline:2px solid #fff;outline-offset:2px}
.usermenu{position:absolute;right:0;top:38px;min-width:210px;background:var(--card);
  border:1px solid var(--line);border-radius:10px;box-shadow:0 10px 26px rgba(0,0,0,.20);
  padding:6px;z-index:30}
.usermenu-head{padding:8px 10px 10px;border-bottom:1px solid var(--line);margin-bottom:5px}
.usermenu-head strong{display:block;font-weight:500;font-size:13px;color:var(--tx)}
.usermenu-head span{display:block;font-size:11px;color:var(--tx3);margin-top:2px}
.usermenu a{display:block;padding:7px 10px;border-radius:7px;font-size:13px;
  color:var(--tx);text-decoration:none}
.usermenu a:hover{background:var(--panel)}
.usermenu a.usermenu-danger{color:var(--bad-tx)}
.usermenu a.usermenu-danger:hover{background:var(--bad-bg)}
.maintbanner{background:var(--warn-bg);color:var(--warn-tx);border-bottom:1px solid #efdcb4;
  padding:7px 18px;font-size:13px;font-weight:500;text-align:center}

@media print{
  .topbar,.sitefooter,.codeactions,.authform,.authnote,.qrmanual,
  .authfoot,.authlogo{display:none!important}
  .authbody{background:none}
  .authbody main.authwrap{min-height:0;padding:0;display:block}
  .authcard{border:none;padding:0;box-shadow:none;width:auto}
}

/* ============================================================
   /admin section + profile
   Reuses the dashboard card/grid/chip vocabulary throughout.
   ============================================================ */
.adminhead{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin:4px 2px 14px}
.admintitle{margin:0;font-size:17px;font-weight:500;color:var(--tx)}
.adminnav{display:flex;gap:2px;flex-wrap:wrap}
.adminnav a{color:var(--tx2);text-decoration:none;padding:5px 11px;border-radius:8px;font-size:13px}
.adminnav a:hover{background:var(--panel);color:var(--tx)}
.adminnav a.on{background:var(--accent-bg);color:var(--accent-tx);font-weight:500}
.adminmsg{border-radius:8px;padding:10px 12px;margin:0 2px 14px;font-size:13px;line-height:1.5}
.admininfo{background:var(--accent-bg);color:var(--accent-tx);border:1px solid #cfe0df}
.adminwarn{background:var(--warn-bg);color:var(--warn-tx);border:1px solid #efdcb4}
/* Flashes fade out after five seconds rather than waiting for a navigation. */
.flash-out{opacity:0;transition:opacity .3s ease}
@media (prefers-reduced-motion:reduce){.flash-out{transition:none}}

.cardrow{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-start;margin:0 0 6px}
.statgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:10px;margin:8px 0 4px}
.statgrid .k{font-size:11px;color:var(--tx3);text-transform:uppercase;letter-spacing:.4px}
.statgrid .v{font-size:20px;font-weight:600;font-variant-numeric:tabular-nums}

.usertoolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin:14px 2px 8px}
.usertoolbar form{display:flex;gap:6px;align-items:center}
.rowactions{display:flex;gap:5px;align-items:center;flex-wrap:wrap}
.rowactions form{margin:0}
table.grid td.rowactions{white-space:normal}
.tbtn.danger{background:var(--bad);border-color:var(--bad);color:#fff}
.tbtn.danger:hover{background:#b23434}
.tbtn.disabled{pointer-events:none;opacity:.45}
a.tbtn{text-decoration:none;display:inline-block}

.dashrow td{background:var(--panel)}
.dashform{display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin:0}
.dashchk{display:flex;align-items:center;gap:5px;font-size:13px;white-space:nowrap}
.dashchk input{width:auto}

.pager{display:flex;align-items:center;justify-content:center;gap:10px;margin:12px 0}
.muted{color:var(--tx3)}

/* the top-bar identity chip is a link now */

/* per-user API key drawer inside the assistant panel */
.ai-settings{padding:10px 12px;border-bottom:1px solid var(--line);background:var(--panel)}
.ai-settings .hint{margin:0 0 8px;font-size:12px}
.ai-settings .modal-actions{margin-top:10px}

/* auth-source config: connection test + claim diagnostics */
.testresult{width:100%}
.testresult table.grid{margin-top:6px}
.claimlist{list-style:none;margin:6px 0;padding:8px 10px;background:var(--panel);
  border:1px solid var(--line);border-radius:8px;font-size:12px;max-height:180px;overflow:auto}
.claimlist li{padding:1px 0}
.card .field{margin-bottom:12px}
.card .field input,.card .field select{width:100%}

/* ============================================================
   Custom dashboards + widgets
   Hand-rolled CSS grid: no library, so it works on an isolated network.
   ============================================================ */
.dashbar{justify-content:space-between}
.dashswitch{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
/* Fixed width, not max-width: the old one resized itself to whichever dashboard was
   selected, so the whole title row shifted every time you switched. */
.dashswitcher{width:200px;flex:0 0 200px;text-overflow:ellipsis}
.dashactions{display:flex;gap:6px;align-items:center}
/* Edit mode is destructive-ish and easy to forget you're in, so it says so. */
.editflag{font-size:12px;font-weight:500;color:var(--accent-tx);background:var(--accent-bg);
  border:1px solid #cfe0df;border-radius:8px;padding:3px 10px;margin-right:2px}
/* The tick is a POST now, so it needs a form -- which must not break the flex row. */
.dashactions .editend{display:contents}
.dashcard{display:block;text-decoration:none;color:inherit;min-width:240px;max-width:340px}
.dashcard:hover{border-color:var(--accent)}
.dashcard h3{margin:0 0 4px}
.dashmeta{display:flex;gap:8px;align-items:center;margin-top:10px}
.dashempty{margin:24px 2px}

.dashgrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));
  grid-auto-rows:64px;gap:16px;margin-top:4px}
.dashgrid.editing{background-image:
  linear-gradient(to right,rgba(28,78,78,.07) 1px,transparent 1px),
  linear-gradient(to bottom,rgba(28,78,78,.07) 1px,transparent 1px);
  background-size:calc((100% - 176px)/12 + 16px) 80px}
.widget-wrap{position:relative;min-width:0;min-height:0}
.widget-wrap .widget{height:100%;overflow:hidden;background:var(--card);
  border:1px solid var(--line);border-radius:12px;display:flex;flex-direction:column}
/* One title bar, drawn by the frame, so no renderer can forget it. */
.widget-head{flex:none;padding:9px 14px 0;font-size:13px;font-weight:500;color:var(--tx);
  display:flex;align-items:center;gap:7px;min-width:0}
.widget-head span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.widget-head .bi{flex:none;font-size:14px;color:var(--accent);line-height:1}
.widget-head + .widget-body{padding-top:7px}
.dashgrid.editing .widget{outline:1px dashed var(--accent)}
.dashgrid.editing .widget-body{pointer-events:none;user-select:none}
.widget-wrap.dragging{z-index:3;box-shadow:0 8px 22px rgba(0,0,0,.18)}
.widget-body{flex:1;min-height:0;overflow:auto;padding:12px 14px}

.edit-tools{position:absolute;top:6px;right:6px;display:flex;gap:4px;opacity:0;
  transition:opacity .12s;z-index:2}
.widget-wrap:hover .edit-tools{opacity:1}
.drag-handle{cursor:grab;background:var(--panel);color:var(--tx2);
  border:1px solid var(--line-strong);border-radius:8px;padding:2px 7px;line-height:1.2}
.drag-handle:active{cursor:grabbing}
.resize-handle{position:absolute;right:2px;bottom:2px;width:16px;height:16px;
  cursor:nwse-resize;background:transparent;border:none;opacity:0;z-index:2}
.resize-handle::after{content:"";position:absolute;right:3px;bottom:3px;width:8px;height:8px;
  border-right:2px solid var(--tx3);border-bottom:2px solid var(--tx3)}
.widget-wrap:hover .resize-handle{opacity:1}

/* widget internals */
.w-empty{color:var(--tx3);font-size:13px;display:flex;align-items:center;
  justify-content:center;height:100%;text-align:center}
.w-error{color:var(--bad-tx)}
.w-tablewrap{height:100%;overflow:auto;margin:-12px -14px;padding:0}
.widget-head + .widget-body .w-tablewrap{margin-top:-7px}
.w-tablewrap table.grid th{font-size:12px;padding:7px 10px}
.w-tablewrap table.grid td{padding:6px 10px}
.w-sub{display:block;font-size:11px;color:var(--tx3)}
.w-rank{color:var(--tx3);width:26px;text-align:right}

.w-kpi{display:flex;flex-direction:column;justify-content:center;height:100%;gap:2px}
.w-kpi-label{font-size:12px;color:var(--tx2);text-transform:uppercase;letter-spacing:.4px}
.w-kpi-value{font-size:38px;font-weight:600;line-height:1.05;font-variant-numeric:tabular-nums}
.w-kpi-sub{font-size:12px;color:var(--tx3)}
.w-kpi-note{font-size:13px;color:var(--tx3)}
/* Threshold colours for the big number. Colour and nothing else -- no dot, no
   weight change, no background: the figure is already 38px and 600. */
.w-kpi-green{color:var(--ok)}
.w-kpi-amber{color:var(--warn)}
.w-kpi-red{color:var(--bad)}

.w-clock{display:flex;flex-direction:column;align-items:center;justify-content:center;
  height:100%;gap:4px}
.w-clock-time{font-size:34px;font-weight:600;font-variant-numeric:tabular-nums;line-height:1}
.w-clock-date{font-size:13px;color:var(--tx2)}
.w-note{white-space:pre-wrap;font-size:13px;line-height:1.5}
.w-titledesc{display:flex;flex-direction:column;justify-content:center;height:100%;gap:4px}
.w-td-title{font-size:17px;font-weight:500}
.w-td-desc{font-size:13px;color:var(--tx2)}

.w-link{display:flex;align-items:center;gap:11px;height:100%;text-decoration:none;color:inherit}
.w-link-icon{width:34px;height:34px;flex:none;border-radius:9px;background:var(--accent-bg);
  color:var(--accent-tx);display:flex;align-items:center;justify-content:center;
  font-weight:600;overflow:hidden}
.w-link-icon img{width:100%;height:100%;object-fit:contain}
.w-link-meta{flex:1;min-width:0}
.w-link-meta strong{display:block;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.w-link-meta span{font-size:12px;color:var(--tx3)}
.w-link b{color:var(--tx3)}
/* The frame goes full-bleed inside the widget, with a thin footer under it. Most sites
   refuse to be embedded, so there is always a way to reach the real page. */
.w-framewrap{display:flex;flex-direction:column;margin:-12px -14px;
  width:calc(100% + 28px);height:calc(100% + 24px)}
.widget-head + .widget-body .w-framewrap{margin-top:-7px;height:calc(100% + 19px)}
.w-frame{border:0;display:block;width:100%;flex:1;min-height:0}
.w-framefoot{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:4px 10px;font-size:11px;color:var(--tx3);background:var(--panel);
  border-top:1px solid var(--line)}
.w-framefoot span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.w-framefoot a{color:var(--accent);text-decoration:none;white-space:nowrap}
.w-framefoot a:hover{text-decoration:underline}

/* ---- shared charts ------------------------------------------------
   Bars and pie slices animate between polls: the renderer updates the same nodes
   rather than rewriting them, so these transitions actually get to run. */
.w-chart{height:100%;display:flex;flex-direction:column;justify-content:center;gap:6px}
.w-bars{gap:7px}
.w-bar-row{display:grid;grid-template-columns:minmax(54px,26%) 1fr auto;align-items:center;
  gap:9px;font-size:12px}
.w-bar-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--tx2)}
.w-bar-track{background:var(--panel);border-radius:5px;height:10px;overflow:hidden}
.w-bar-track i{display:block;height:100%;border-radius:5px;width:0;
  transition:width .5s cubic-bezier(.4,0,.2,1)}
.w-bar-value{text-align:right;font-variant-numeric:tabular-nums;font-weight:500;
  min-width:38px}

.w-piewrap{flex-direction:row;align-items:center;gap:14px}
.w-pie{width:118px;height:118px;flex:none;transform:rotate(-90deg)}
.w-pie-seg{transition:stroke-dasharray .5s cubic-bezier(.4,0,.2,1),
  stroke-dashoffset .5s cubic-bezier(.4,0,.2,1)}
.w-pie-total{transform:rotate(90deg);transform-origin:21px 21px;font-size:7px;
  font-weight:600;fill:var(--tx)}
.w-pie-legend{list-style:none;margin:0;padding:0;font-size:12px;flex:1;min-width:0;
  max-height:100%;overflow:auto}
.w-pie-legend li{display:flex;align-items:center;gap:6px;padding:1px 0}
.w-pie-legend i{width:9px;height:9px;border-radius:2px;flex:none}
.w-pie-legend span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.w-pie-legend b{margin-left:auto;font-variant-numeric:tabular-nums;padding-left:6px}

@media (prefers-reduced-motion:reduce){
  .w-bar-track i,.w-pie-seg{transition:none}
}

.w-allclear{display:flex;flex-direction:column;align-items:center;justify-content:center;
  height:100%;gap:6px;color:var(--ok-tx);text-align:center;font-size:13px}
.w-allclear b{font-size:28px}
.w-health{display:flex;flex-direction:column;justify-content:center;height:100%;gap:5px}
.w-health-top{display:flex;align-items:center;gap:8px;font-size:15px}
.w-health-msg{font-size:12px}
.w-health-counts{font-size:12px;color:var(--tx3)}
.w-qcard{border:0;padding:0}

/* widget picker + config */
.modal-wide{width:720px;max-height:84vh;overflow:auto}
/* ---- the add-widget picker ------------------------------------------------
   Two panes: a searchable list, and the widget's own renderer fed real data. Grid
   rather than flex so the list can scroll on its own without the pane moving. */
.pickerwrap{display:grid;grid-template-columns:minmax(0,200px) minmax(0,1fr);gap:14px;
  margin:10px 0 0}
.pickerlist{border-right:1px solid var(--line);padding-right:12px;
  max-height:52vh;overflow:auto}
.pickerlist input[type=search]{width:100%;margin:0 0 10px}
.pickergroup{font-size:11px;text-transform:uppercase;letter-spacing:.4px;
  color:var(--tx3);margin:10px 2px 4px}
.pickergroup:first-child{margin-top:0}
.pickerlist .pickeritem{display:block;width:100%;text-align:left;padding:7px 9px;
  border:none;background:transparent;border-radius:7px;font-size:13px;color:var(--tx)}
.pickerlist .pickeritem:hover{background:var(--panel)}
.pickerlist .pickeritem.on{background:var(--accent);color:#fff;font-weight:500}

.pickerpanehead{display:flex;align-items:center;justify-content:space-between;margin:0 0 8px}
.pickerpanelabel{font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--tx3)}
.previewsource{font-size:11px;color:var(--tx3)}
.previewsource.live{color:var(--ok-tx)}
.previewsource.live::before{content:"";display:inline-block;width:7px;height:7px;
  border-radius:50%;background:var(--ok);margin-right:5px;vertical-align:1px}
/* The frame mimics a real tile, at the widget's default proportions. */
.previewframe{background:var(--page);border-radius:12px;padding:10px;
  aspect-ratio:3/2;max-height:44vh}
.previewframe .widget{height:100%;background:var(--card);border:1px solid var(--line);
  border-radius:12px;overflow:hidden;display:flex;flex-direction:column}
.previewframe .widget-body{flex:1;min-height:0;overflow:hidden;padding:12px 14px}
.pickermeta{display:flex;align-items:center;gap:8px;margin:12px 0 4px}
.pickername{font-size:14px;font-weight:500}

.pickergrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:8px;margin:6px 0 14px}
.pickeritem{display:flex;flex-direction:column;gap:3px;text-align:left;padding:9px 11px;
  background:var(--panel);color:var(--tx);border:1px solid var(--line);border-radius:9px;cursor:pointer}
.pickeritem:hover{border-color:var(--accent);background:var(--accent-bg)}
.pickeritem strong{font-weight:500;font-size:13px}
.pickeritem span{font-size:11px;color:var(--tx3);line-height:1.35}
.field .req{font-style:normal;font-size:10px;color:var(--tx3);text-transform:uppercase;margin-left:5px}
.sharelist{max-height:190px;overflow:auto;border:1px solid var(--line);border-radius:8px;padding:8px}
.modal textarea{width:100%;font:inherit;padding:6px 8px;border:1px solid var(--line-strong);
  border-radius:8px;resize:vertical}

@media (max-width:900px){
  .dashgrid{grid-template-columns:repeat(8,minmax(0,1fr))}
  .dashgrid.editing{background-size:calc((100% - 112px)/8 + 16px) 80px}
}
@media (max-width:600px){
  .dashgrid{grid-template-columns:repeat(4,minmax(0,1fr))}
  .dashgrid.editing{background-size:calc((100% - 48px)/4 + 16px) 80px}
}

/* ---- icon buttons + dashboard chrome ------------------------------------ */
.iconbtn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;
  padding:0;border-radius:8px;background:var(--card);color:var(--tx2);
  border:1px solid var(--line-strong);cursor:pointer;text-decoration:none;line-height:0}
.iconbtn:hover{background:var(--panel);color:var(--tx);border-color:var(--tx3)}
.iconbtn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.iconbtn-on{background:var(--accent);border-color:var(--accent);color:#fff}
.iconbtn-on:hover{background:#163e3e;color:#fff;border-color:#163e3e}

/* Add-widget sits bottom-right of the viewport, clear of the grid it adds to. */
.dashfab{position:fixed;right:22px;bottom:64px;z-index:12;width:48px;height:48px;
  border-radius:50%;background:var(--accent);color:#fff;border:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 6px 18px rgba(0,0,0,.24)}
.dashfab:hover{background:#163e3e}
.dashfab:focus-visible{outline:2px solid #fff;outline-offset:3px}

/* Card is a container now, so the pencil isn't nested inside the card's link. */
.dashcard{position:relative;padding-right:112px}
.dashcard-link{display:block;text-decoration:none;color:inherit}
.dashcard-actions{position:absolute;top:12px;right:12px;display:flex;gap:5px}

/* The actions stay out of the way until the card is hovered. The card keeps its
   padding-right either way, so nothing reflows as they appear. Only where hover is a real
   input -- on touch there is no hover state to enter, so they stay visible.

   Hidden with opacity rather than visibility: a visibility:hidden button can't take focus,
   so :focus-within could never fire and keyboard users would lose the actions entirely.
   pointer-events keeps them from being invisible click targets in the meantime. */
@media (hover:hover){
  .dashcard-actions{opacity:0;pointer-events:none;transition:opacity .15s ease}
  .dashcard:hover .dashcard-actions,
  .dashcard:focus-within .dashcard-actions{opacity:1;pointer-events:auto}
}
@media (prefers-reduced-motion:reduce){
  .dashcard-actions{transition:none}
}

/* Destructive icon button: red outline, filling on hover so the intent is unmistakable. */
.iconbtn-danger{color:var(--bad);border-color:#e6c4c4}
.iconbtn-danger:hover{background:var(--bad);border-color:var(--bad);color:#fff}
.iconbtn-danger:focus-visible{outline-color:var(--bad)}
#cardDelete .modal code{background:var(--panel);padding:1px 6px;border-radius:6px;
  font-family:Consolas,monospace}

/* ---- icons -------------------------------------------------------------- */
.dashicon{color:var(--accent);margin-right:6px}
.dashcard-icon{color:var(--accent);margin-right:6px}
.w-td-icon{font-size:24px;color:var(--accent);line-height:1;margin-bottom:6px}
.w-link-icon .bi{font-size:18px}

/* icon picker: preview button, then a searchable grid */
.iconpick{position:relative;display:flex;align-items:center;gap:8px}
.iconpick-btn{display:flex;align-items:center;gap:8px;flex:1;min-width:0;
  background:var(--card);color:var(--tx);border:1px solid var(--line-strong);
  border-radius:8px;padding:6px 10px;cursor:pointer;font:inherit;text-align:left}
.iconpick-btn:hover{border-color:var(--tx3);background:var(--panel)}
.iconpick-btn .bi{font-size:17px;color:var(--accent);flex:none}
.iconpick-btn span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:13px;color:var(--tx2)}
.iconpick-clear{background:transparent;color:var(--tx2);border:1px solid var(--line-strong);
  border-radius:8px;padding:6px 10px;font-size:12px;cursor:pointer;flex:none}
.iconpick-clear:hover{background:var(--panel);color:var(--tx)}
/* Fixed and parented to <body>, so a scrolling config dialog can't clip it. Position
   is set by the picker at open time. */
.iconpick-panel{position:fixed;z-index:60;display:flex;flex-direction:column;
  background:var(--card);border:1px solid var(--line);border-radius:10px;padding:10px;
  box-shadow:0 12px 30px rgba(0,0,0,.24)}
.iconpick-search{width:100%;padding:6px 9px;border:1px solid var(--line-strong);
  border-radius:8px;font:inherit;margin-bottom:8px;flex:none}
.iconpick-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(34px,1fr));
  gap:4px;overflow:auto;flex:1;min-height:0}
.iconpick-item{display:flex;align-items:center;justify-content:center;height:34px;
  background:transparent;border:1px solid transparent;border-radius:7px;cursor:pointer;
  color:var(--tx2);font-size:17px;padding:0}
.iconpick-item:hover{background:var(--accent-bg);border-color:var(--accent);
  color:var(--accent-tx)}
.iconpick-more{grid-column:1/-1;margin:6px 2px 0;font-size:11px}

/* ---- tabs (profile) ----------------------------------------------------- */
.tabs{display:flex;gap:2px;border-bottom:1px solid var(--line);margin:4px 2px 16px}
.tab{background:transparent;border:0;border-bottom:2px solid transparent;color:var(--tx2);
  padding:8px 14px;font:inherit;font-size:13px;cursor:pointer;border-radius:0;margin-bottom:-1px}
.tab:hover{color:var(--tx);background:var(--panel)}
.tab.on{color:var(--accent-tx);border-bottom-color:var(--accent);font-weight:500;
  background:transparent}
.tab:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.tabpanel{margin-bottom:6px}

.profilecard{max-width:none;width:100%}
.profilecard .statgrid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  margin:2px 0 4px}
.profilecard .statgrid .v{font-size:15px;font-weight:500}
.cardactions{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px}

/* Dashboards list: title on the left, actions on the right. */
.dashlisthead{justify-content:space-between}
.dashlistactions{display:flex;gap:6px;align-items:center}

/* The queue card reuses the wallboard body wholesale, which brings the pin/drag
   controls with it. Pinning is a wallboard idea -- on a dashboard the queue is
   already chosen -- so they are dropped rather than left to do nothing. */
.w-qcard .qctrls{display:none}

/* ---- admin polish -------------------------------------------------------- */
/* Stat tiles, borrowed from the dashboard KPI vocabulary: one fact per box, the number
   doing the talking. Auto-fit so a row of six reflows rather than squashing. */
.statboxes{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:12px;margin:0 0 18px}
.statbox{background:var(--card);border:1px solid var(--line);border-radius:12px;
  padding:14px 16px}
.statbox .k{font-size:12px;color:var(--tx3);text-transform:uppercase;letter-spacing:.4px;
  margin:0 0 6px}
.statbox .v{font-size:30px;font-weight:600;line-height:1.05;font-variant-numeric:tabular-nums}
/* Text-valued boxes (Authentication) need to fit words, not three digits. */
.statbox .v.vtext{font-size:19px;font-weight:500;line-height:1.3}
.statbox .sub{font-size:12px;color:var(--tx3);margin:6px 0 0}
.statbox .v.c-amber,.statbox .v.c-red,.statbox .v.c-green{font-weight:600}
.statbox .v.c-amber::before,.statbox .v.c-red::before,.statbox .v.c-green::before{
  display:none}          /* the table dot again -- wrong at this size */

/* Page header with an action on the right. */
.adminhead.spread{justify-content:space-between}
.headactions{display:flex;gap:6px;align-items:center;margin-left:auto}
/* An icon button that carries a label too. */
.iconbtn.labelled{width:auto;gap:6px;padding:0 12px}

/* First / prev / page / next / last. */
.pagerbtns{display:flex;align-items:center;gap:4px}
.pagerbtns .tbtn{min-width:34px;text-align:center}
.usertitle{margin:0;font-size:16px;font-weight:500}
.dangerzone{flex-wrap:wrap}

/* Close affordance for the widget modal. Positioned against the dialog, not the body, so
   it stays put while the body scrolls. */
.modal-wide{position:relative}
.modalclose{position:absolute;top:10px;right:12px;width:28px;height:28px;padding:0;
  display:flex;align-items:center;justify-content:center;border-radius:8px;
  background:transparent;border:1px solid transparent;color:var(--tx3);cursor:pointer}
.modalclose:hover{background:var(--panel);color:var(--tx);border-color:var(--line)}
.modalclose svg{display:block}

/* ---- enhanced dashboard menu -------------------------------------------- */
/* Reuses the account menu's panel, hung off a nav item instead of the avatar, so it
   opens leftwards and sits under the top bar rather than over the page edge. */
.navmenu-wrap{position:relative;display:flex}
.navmenu-btn{display:flex;align-items:center;gap:5px;background:transparent;border:none;
  color:var(--header-dim);padding:6px 12px;border-radius:8px;font-size:13px;cursor:pointer}
.navmenu-btn:hover{background:rgba(255,255,255,.12);color:#fff}
.navmenu-btn.on{background:rgba(255,255,255,.16);color:#fff;font-weight:500}
.navmenu-btn svg{display:block;opacity:.75}
.navmenu{left:0;right:auto;max-height:min(70vh,520px);overflow:auto}
/* The panel sits inside .topbar nav, whose links are pale-on-dark. Left alone they came
   out barely legible on the white panel, and white-on-white on hover. */
.topbar nav .navmenu a{color:var(--tx);text-decoration:none}
.topbar nav .navmenu a:hover{background:var(--panel);color:var(--tx)}
/* Menu items include a button (Add Dashboard), which needs the same shape as the links. */
.navmenu button[role="menuitem"]{display:flex;align-items:center;gap:8px;width:100%;
  padding:7px 10px;border-radius:7px;font-size:13px;background:transparent;border:none;
  color:var(--tx);text-align:left;cursor:pointer}
.navmenu button[role="menuitem"]:hover{background:var(--panel)}
.navmenu a{display:flex;align-items:center;gap:8px}
.navmenu a i{color:var(--accent)}
.usermenu-sep{height:1px;background:var(--line);margin:5px 0}
.usermenu-empty{display:block;padding:7px 10px;font-size:12px;color:var(--tx3)}

/* ---- hierarchy editor ---------------------------------------------------- */
/* Card header carrying the + and reset buttons, right-aligned above the table. */
.editcardhead{display:flex;justify-content:flex-end;margin:0 0 10px}
.editheadactions{display:flex;gap:6px;align-items:center}
.editsearch{display:flex;gap:6px;align-items:center;margin:0 0 10px}
.editsearch input{min-width:240px}
/* Every modal here needs room for the corner X. */
.modal-overlay .modal{position:relative}
/* Export/import buttons carry an icon beside their label. */
.dlbtn{display:inline-flex;align-items:center;gap:7px}
.impbtn.iconbtn{flex:0 0 auto}

/* ---- password dialogs ----------------------------------------------------- */
/* A pick-one control. Deliberately NOT .toggle: that class hides its input and relies
   on a .toggle-slider sibling, so a radio wearing it renders as bare text with nothing
   to click. Here the radio stays visible and the whole row is the target. */
.choicegroup{display:flex;flex-direction:column;gap:8px;margin:6px 0 12px}
.choice{display:flex;align-items:flex-start;gap:10px;cursor:pointer;
  border:1px solid var(--line-strong);border-radius:8px;padding:10px 12px;
  background:var(--card)}
.choice:hover{border-color:var(--accent);background:var(--panel)}
.choice input{width:auto;margin:2px 0 0;flex:none;accent-color:var(--accent)}
.choice:has(input:checked){border-color:var(--accent);background:var(--accent-bg)}
.choice:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:2px}
.choicebody{display:flex;flex-direction:column;gap:2px;min-width:0}
.choicetitle{font-size:13px;font-weight:500;color:var(--tx)}
.choicehint{font-size:12px;color:var(--tx2);line-height:1.4}
.pwreveal{display:flex;gap:6px;align-items:center;margin:10px 0 0}
.pwreveal input{flex:1;font-family:Consolas,monospace;font-size:15px;letter-spacing:1px;
  padding:9px 11px;border-radius:6px;background:var(--panel)}
