@font-face{font-family:"Oswald";src:url(/static/fonts/Oswald-Variable.ttf) format("truetype");font-weight:200 700;font-display:swap}
@font-face{font-family:"Poppins";src:url(/static/fonts/Poppins-Regular.ttf) format("truetype");font-weight:400;font-display:swap}
@font-face{font-family:"Poppins";src:url(/static/fonts/Poppins-Medium.ttf) format("truetype");font-weight:500;font-display:swap}
@font-face{font-family:"Poppins";src:url(/static/fonts/Poppins-SemiBold.ttf) format("truetype");font-weight:600;font-display:swap}
/* accent colours taken from www.resnav.com (purple #9C42F5, blue #1863DC) */
:root{--purple:#9C42F5;--purple-deep:#7A23D6;--blue:#1863DC;--mid-blue:#4285F4;--cyan:#E9FEFF;--sage:#E5E8DD;--cream:#FBFBF8;--paper:#FFFFFF;--ink:#212121;--body:#46474F;--muted:#73757F;--hair:#E7E5DC;--error:#D6162D;--success:#0E7C86;--warning:#F3722C}
*{box-sizing:border-box}
html,body{margin:0;background:var(--cream);color:var(--body);font-family:"Poppins",system-ui,sans-serif;font-size:15px;line-height:1.45}
h1,h2{font-family:"Oswald","Poppins",sans-serif;color:var(--ink);margin:0}
.brand{display:flex;flex-direction:column;gap:4px}
.logo{height:30px;width:auto;display:block}
header{background:linear-gradient(135deg,#F1E5FF,#E9FEFF);border-bottom:1px solid var(--hair);padding:16px 24px;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.eyebrow{font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.12em;color:var(--muted)}
.who{display:flex;align-items:center;gap:12px;font-size:13px}
.who b{color:var(--ink)}
main{max-width:1100px;margin:24px auto;padding:0 16px}
.card{background:var(--paper);border:1px solid var(--hair);border-radius:16px;padding:24px;box-shadow:0 1px 2px rgba(26,26,34,.04)}
button,.btn{font:inherit;font-weight:600;font-size:13px;border:0;border-radius:999px;padding:8px 16px;cursor:pointer;background:var(--purple);color:#fff;text-decoration:none;display:inline-block}
button:hover,.btn:hover{background:var(--purple-deep)}
button.ghost,.btn.ghost{background:transparent;color:var(--purple-deep);border:1px solid var(--purple)}
button.ghost:hover,.btn.ghost:hover{background:#F1E5FF}
button.danger{background:transparent;color:var(--error);border:1px solid var(--hair);padding:4px 10px;font-size:12px}
button.danger:hover{background:#FDECEE}
.toolbar{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap;margin-bottom:16px}
.crumbs{font-size:13px;color:var(--muted);display:flex;gap:4px;flex-wrap:wrap;align-items:center}
.crumbs a{color:var(--blue);text-decoration:none;font-weight:500}
.crumbs a:hover{text-decoration:underline}
.drop{border:2px dashed var(--purple);border-radius:12px;background:#FAF5FF;padding:32px;text-align:center;color:var(--body);margin:16px 0;transition:background .15s}
.drop.over{background:#F1E5FF;border-style:solid}
.drop h2{font-size:22px;font-weight:500;margin-bottom:8px}
.drop input{display:none}
.drop label{color:var(--purple-deep);font-weight:600;cursor:pointer;text-decoration:underline}
table{width:100%;border-collapse:collapse;font-size:14px}
th{text-align:left;font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-weight:600;padding:8px 12px;border-bottom:1px solid var(--hair)}
td{padding:10px 12px;border-bottom:1px solid var(--hair);vertical-align:middle}
tr:hover td{background:var(--cream)}
td.name a{color:var(--ink);text-decoration:none;font-weight:500}
td.name a:hover{color:var(--purple-deep)}
td.num{text-align:right;white-space:nowrap;color:var(--muted);font-variant-numeric:tabular-nums}
td.act{text-align:right;white-space:nowrap}
.empty{padding:24px;text-align:center;color:var(--muted)}
.queue{margin-top:16px;display:grid;gap:8px}
.q{font-size:13px;display:grid;grid-template-columns:1fr auto auto;gap:8px;align-items:center}
.q button.x{padding:0 8px;line-height:1.5;font-size:14px;min-width:0}
.q.fade{opacity:0;transition:opacity 1s}
.bar{grid-column:1/-1;height:6px;background:var(--sage);border-radius:999px;overflow:hidden}
.bar i{display:block;height:100%;background:linear-gradient(90deg,var(--purple),var(--blue));width:0}
.ok{color:var(--success);font-weight:600}.err{color:var(--error);font-weight:600}
.login{max-width:420px;margin:48px auto}
.login h1{font-size:46px;font-weight:600;line-height:1.1;margin-bottom:4px}
.login p{color:var(--muted);margin:0 0 24px}
.login p.hint{font-size:13px;margin:18px 0 0}
.login p.hint a{color:var(--blue)}
.field{display:grid;gap:6px;margin-bottom:16px}
.field label{font-size:13px;font-weight:600;color:var(--ink)}
.field input{font:inherit;padding:10px 12px;border:1px solid #CFC7E0;border-radius:12px;background:#F4F1FA;color:var(--ink)}
.field input:focus{outline:2px solid var(--mid-blue);border-color:transparent;background:#fff}
.alert{background:#FDECEE;color:var(--error);border-radius:12px;padding:10px 12px;font-size:13px;margin-bottom:16px;display:none}
.alert.show{display:block}
footer{text-align:center;color:var(--muted);font-size:12px;padding:24px}
.icon{display:inline-flex;align-items:center;vertical-align:middle;margin-right:10px;flex:0 0 auto}
.icon svg{width:24px;height:24px;display:block}
.icon.dir{color:var(--purple)}
.icon.file{color:var(--mid-blue)}
td.name{vertical-align:middle}   /* a real table cell again: display:flex broke the cell background/height */
.note{background:#FFF4EC;border:1px solid #F3722C;color:#7A3A12;border-radius:12px;padding:10px 12px;font-size:13px;margin-bottom:16px}
/* selection + batch actions */
th.selcol,td.selcol{width:34px;text-align:center;padding-left:14px}
td.selcol input,th.selcol input{width:16px;height:16px;accent-color:var(--purple);cursor:pointer}
tr.sel td{background:#F6EEFE}
.selbar{display:flex;align-items:center;gap:8px;background:#F1E5FF;border:1px solid var(--purple);border-radius:12px;padding:8px 12px;margin-bottom:12px}
.selbar .spacer{flex:1}
.selbar span:first-child{font-weight:600;color:var(--purple-deep)}
.movedlg{display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:var(--paper);border:1px solid var(--hair);border-radius:12px;padding:10px 12px;margin-bottom:12px}
.movedlg select{font:inherit;padding:6px 10px;border:1px solid var(--hair);border-radius:10px;background:#fff;color:var(--ink)}
/* upload queue header (tally + Cancel + Clear) - lives in the bottom dock, see .dock */
.queuehdr{display:flex;align-items:center;gap:10px}
/* auto-scrolled rows stop above the dock; --dock-h is set from the dock's measured height by app.js */
.q{scroll-margin-bottom:calc(var(--dock-h,0px) + 12px)}
.queuehdr .spacer{flex:1}
.queuehdr #queuetitle{font-size:13px;text-transform:uppercase;letter-spacing:.08em;color:var(--purple-deep);font-weight:600}
.logolink{display:inline-block;line-height:0}
/* the hidden attribute must beat the flex/display rules above, or Cancel/hide won't work */
.selbar[hidden],.movedlg[hidden],.queuehdr[hidden]{display:none}
/* the dock: a bar FIXED to the bottom of the window holding the move dialog, the selection bar and the upload queue
   header, stacked - all three stay reachable however far a long list or queue has scrolled. app.js hides the dock
   when all three are hidden and sets the page's bottom padding (and --dock-h) from its measured height. */
.dock{position:fixed;left:0;right:0;bottom:0;z-index:50;display:flex;flex-direction:column;box-shadow:0 -4px 14px rgba(26,26,34,.12)}
.dock[hidden]{display:none}
.dock>.selbar,.dock>.movedlg,.dock>.queuehdr{margin:0;border:0;border-radius:0;padding:10px 24px;border-top:2px solid var(--purple)}
/* three palette tints so stacked bars read apart from the page AND from each other (Chad, 2026-10-20):
   dialogs (move, Manage, New account) = cyan with the blue edge; selection = lavender with purple; uploads = sage */
.dock>.movedlg{background:var(--cyan);border-top-color:var(--blue)}
.dock>.selbar{background:#F1E5FF}
.dock>.queuehdr{background:var(--sage);border-top-color:var(--purple-deep)}
/* the ".." up-a-level row */
.icon.up{color:var(--purple)}
tr.dotdot{cursor:pointer}
tr.dotdot a{color:var(--blue);font-weight:600;text-decoration:none}
tr.dotdot:hover td{background:var(--cream)}
tr.dotdot td.num{color:var(--muted)}
/* the account filter (administrators' account list): a search box in the toolbar with a "n of m" count */
/* a grey chip so the filter stands out from the toolbar buttons (Chad, 2026-10-20) */
.filter{display:inline-flex;align-items:center;gap:8px;margin-right:8px;background:#E4E2DA;border:1px solid #CFCCC2;border-radius:999px;padding:4px 12px 4px 6px}
.filter[hidden]{display:none}
.filter input{font:inherit;padding:6px 12px;border:1px solid #CFCCC2;border-radius:999px;background:#fff;color:var(--ink);width:220px}
.filter input:focus{outline:2px solid var(--mid-blue);border-color:transparent;background:#fff}
#acctcount{font-size:12px;color:#4B4D55;white-space:nowrap}
/* admin dialogs: a full-width break between the rows of the Manage / New account panels; key rows */
.movedlg .brk{flex-basis:100%;height:0}
.movedlg input[type=text],.movedlg input[type=email]{font:inherit;padding:6px 10px;border:1px solid #CFC7E0;border-radius:10px;background:#fff;color:var(--ink)}
.movedlg textarea{font:inherit;font-size:12px;padding:6px 10px;border:1px solid #CFC7E0;border-radius:10px;background:#fff;color:var(--ink);width:min(520px,60vw);height:3.2em;vertical-align:middle}
.movedlg code{font-size:12px;color:var(--ink)}
.movedlg[hidden]{display:none}
.keyoff,.keyoff code{color:var(--muted)}
/* the account list reuses the folder table: its columns are Account / Access / Status, left-aligned */
table.accounts th,table.accounts td.acc{text-align:left}
td.acc{color:var(--muted);white-space:nowrap}
/* meters at the top of the administrators' account list: disks, load, memory (filled by app.js from /api/admin/system) */
.meters{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px 20px;margin-bottom:16px;padding:12px 16px;background:var(--paper);border:1px solid var(--hair);border-radius:12px}
.meter{font-size:13px;color:var(--body)}
.meter b{display:block;color:var(--ink);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.08em;margin-bottom:4px}
.meter .bar{height:8px;margin:4px 0}
.meter.warn .bar i{background:var(--warning)}
.meter.hot .bar i{background:var(--error)}
.meter small{color:var(--muted)}
/* the Manage panel's labelled groups: what a button acts on is what sits in its box */
.mtitle{font-weight:600;color:var(--ink);margin-right:4px}
.grp{display:inline-flex;align-items:center;flex-wrap:wrap;gap:6px 8px;border:1px solid var(--hair);border-radius:10px;padding:6px 10px;background:#fff;vertical-align:middle}
.grp>.lg{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-weight:600;margin-right:2px;flex-basis:100%}
.grp.danger{border-color:#F5C2C7;background:#FFF8F8}
.grp.danger>.lg{color:var(--error)}
.movedlg small.rules{flex-basis:100%;color:var(--muted);font-size:12px;line-height:1.4}
table.accounts th.sortable{cursor:pointer;user-select:none}
table.accounts th.sortable:hover{color:var(--purple-deep)}
/* copy-move status rows in the dock (cyan, like the dialogs) */
.mv{flex-basis:100%;display:grid;grid-template-columns:1fr auto auto;gap:4px 12px;align-items:center;font-size:13px}
.mv .mvbtns{display:inline-flex;gap:6px}
.mv .mvbtns button{padding:3px 12px;font-size:12px}
.chip.paused{background:var(--sage);color:var(--body);border-style:dashed}
.mv .bar{grid-column:1/-1;height:6px}
.mv small.cur{grid-column:1/-1;color:var(--muted);font-size:12px}
/* chips on items a copy move is taking out (amber) or bringing in (blue) */
.chip{display:inline-block;margin-left:10px;padding:1px 9px;border-radius:999px;font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;vertical-align:middle;white-space:nowrap}
.chip.out{background:#FFF4EC;color:#7A3A12;border:1px solid var(--warning)}
.chip.in{background:var(--cyan);color:var(--blue);border:1px solid var(--mid-blue)}
button:disabled,button:disabled:hover{opacity:.45;cursor:not-allowed;background:transparent}
button:disabled:not(.ghost):not(.danger){background:var(--purple)}
/* blocked addresses, under the meters on the account list */
.bans{margin-bottom:16px;padding:10px 16px;background:var(--paper);border:1px solid var(--hair);border-radius:12px;display:grid;gap:6px}
.banshead{display:flex;gap:12px;align-items:baseline}
.banshead b{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--ink)}
.bcount{font-size:12px;color:var(--muted)}
.ban{display:grid;grid-template-columns:150px 1fr auto auto;gap:4px 12px;align-items:center;font-size:13px;padding:4px 0;border-top:1px solid var(--hair)}
.ban code{font-size:12px;color:var(--ink)}
.ban .bwhere{color:var(--muted);font-size:12px}
.ban .bnames{display:flex;flex-wrap:wrap;gap:4px}
.ban .chip{margin-left:0;text-transform:none;letter-spacing:0}
.chip.acct{background:#F1E5FF;color:var(--purple-deep);border:1px solid var(--purple)}
.chip.tried{background:var(--sage);color:var(--body);border:1px solid var(--hair)}
.ban.known{background:#FAF5FF}
.bnone{color:var(--muted);font-size:12px}
button.linkish{justify-self:start;padding:2px 10px;font-size:12px}
/* LAST on purpose: the hidden attribute always wins. `button{display:inline-block}` and the flex rules above would
   otherwise override the browser's [hidden]{display:none} and leave "hidden" buttons (New folder at the account list,
   Cancel, New account) on screen. !important for browsers; last in source order for jsdom's simpler cascade. */
[hidden]{display:none !important}
