/* hostpulse.
   Design direction from the ui-ux-pro-max skill: dark operations palette
   (slate ground, status green), dense dashboard spacing, glass only where it
   sits over content. Two adaptations the skill could not know about:

   - it paired Fira Sans with Fira Code, and Fira Sans has no Persian glyphs.
     Samim carries the text and Fira Code the numbers, which is the half of
     that pairing that actually matters on a metrics panel.
   - it suggested glassmorphism throughout and then flags its own contrast
     risk. Blur is used on the header and the dialog scrim only; cards stay
     opaque so 4.5:1 holds on every reading.
*/
@import url('/static/fonts.css');

:root{
  /* ground */
  --bg:#0F172A; --card:#1B2336; --muted:#272F42;
  --line:#2C3448; --line-strong:#475569;
  /* ink */
  --ink:#F8FAFC; --dim:#94A3B8;
  /* meaning */
  --ok:#22C55E; --warn:#F59E0B; --bad:#EF4444; --accent:#38BDF8;
  --rx:#38BDF8; --tx:#A78BFA;
  /* dense dashboard scale, 8-32px */
  --s1:8px; --s2:12px; --s3:16px; --s4:24px; --s5:32px;
  --r1:8px; --r2:12px; --r3:16px;
  --fast:160ms; --slow:260ms;
}
@media (prefers-color-scheme: light){
  :root{
    --bg:#F1F5F9; --card:#FFFFFF; --muted:#F8FAFC;
    --line:#E2E8F0; --line-strong:#CBD5E1;
    --ink:#0F172A; --dim:#475569;
  }
}

*{box-sizing:border-box}
/* `.modal{display:grid}` and the browser's own `[hidden]{display:none}` carry
   the same specificity, so the later rule - ours - was winning and a dialog
   stayed on screen after its close button set hidden. */
[hidden]{display:none!important}

html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:Samim,system-ui,-apple-system,"Segoe UI",Tahoma,sans-serif;
  font-size:16px;line-height:1.55;
}
body.centre{display:grid;place-items:center;min-height:100dvh;padding:var(--s3)}
/* Numbers read as data and line up in a column. Samim comes straight after
   Fira Code, which has no Persian glyphs: these fields are not purely numeric
   - a status word, a duration in words, the ٪ sign - and without the fallback
   named here those characters would be drawn by whatever the system offers. */
.num,.host,.val,.stats b,.traffic b,.rate{
  font-family:"Fira Code",Samim,ui-monospace,Menlo,Consolas,monospace;
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum";direction:ltr;
}
/* the two that are words far more often than numbers */
.stats b,.state{font-family:Samim,system-ui,sans-serif;direction:rtl}
.stats b .n{font-family:"Fira Code",Samim,monospace;direction:ltr}

h1{font-size:19px;margin:0;letter-spacing:-.01em}
h2{font-size:17px;margin:0}
h3{font-size:12px;margin:0 0 var(--s1);color:var(--dim);font-weight:600;
   text-transform:uppercase;letter-spacing:.05em}
a{color:var(--accent)}

/* ------------------------------------------------------------- chrome */
header{
  position:sticky;top:0;z-index:20;
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);
  padding:var(--s2) var(--s4);
  border-bottom:1px solid var(--line);
  background:color-mix(in srgb, var(--card) 82%, transparent);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
}
.brand{display:flex;align-items:center;gap:var(--s1)}
.brand svg{color:var(--ok)}
.actions{display:flex;gap:var(--s1);align-items:center}
main{padding:var(--s4);max-width:1440px;margin:0 auto}

/* ------------------------------------------------------------ controls */
button,.btn{
  font:inherit;font-size:14px;border-radius:var(--r1);
  padding:9px 14px;min-height:40px;cursor:pointer;
  border:1px solid var(--line-strong);background:transparent;color:var(--ink);
  text-decoration:none;display:inline-flex;align-items:center;gap:6px;
  transition:background var(--fast),border-color var(--fast),
             color var(--fast),transform var(--fast);
}
button:hover,.btn:hover{background:var(--muted);border-color:var(--accent)}
button:active{transform:translateY(1px)}
button.primary{background:var(--ok);border-color:var(--ok);color:#052e16;font-weight:600}
button.primary:hover{background:#16A34A;border-color:#16A34A}
button.danger{background:var(--bad);border-color:var(--bad);color:#fff}
button.danger:hover{filter:brightness(1.08)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r1)}

/* --------------------------------------------------------------- cards */
.cards{display:grid;gap:var(--s2);
  grid-template-columns:repeat(auto-fill,minmax(340px,1fr))}

/* a group is a band across the board, not a box - the cards stay the same
   size whichever group they are in, so moving one does not resize it */
.group{margin-bottom:var(--s4)}
.group-head{display:flex;align-items:center;justify-content:space-between;
  gap:var(--s2);margin-bottom:var(--s2);padding-bottom:7px;
  border-bottom:1px solid var(--line);flex-wrap:wrap}
.group-head .title{display:flex;align-items:baseline;gap:var(--s1)}
.group-head h2{font-size:15px}
.group-head .count{font-size:11px;color:var(--dim)}
.group-sums{display:flex;gap:var(--s3);font-size:11px;color:var(--dim);
  flex-wrap:wrap}
.group-sums b{color:var(--ink);font-weight:500}
.cards.drop-on{outline:2px dashed var(--accent);outline-offset:6px;
  border-radius:var(--r2);min-height:64px}
.cards.empty-slot{min-height:64px}
.card.dragging{opacity:.4}
.card[draggable="true"]{cursor:grab}
.card[draggable="true"]:active{cursor:grabbing}

.glist{margin-top:var(--s3);display:grid;gap:7px}
.grow-row{display:flex;align-items:center;gap:var(--s1);
  border:1px solid var(--line-strong);border-radius:var(--r1);padding:7px 11px}
.grow-row input{flex:1;margin:0;border:0;background:transparent;padding:4px 0;
  min-height:auto;color:var(--ink);font:inherit;font-size:14px}
.grow-row input:focus{outline:none}
.sheet select{width:100%;margin-top:5px;padding:10px 12px;min-height:42px;
  border-radius:var(--r1);border:1px solid var(--line-strong);
  background:var(--bg);color:var(--ink);font:inherit;font-size:14px}
.card{background:var(--card);border:1px solid var(--line);
  border-radius:var(--r3);padding:var(--s3)}
.card.clickable{cursor:pointer;transition:border-color var(--fast),
  transform var(--fast),box-shadow var(--fast)}
.card.clickable:hover{border-color:var(--accent);transform:translateY(-2px);
  box-shadow:0 8px 24px rgba(0,0,0,.28)}
.card-head{display:flex;align-items:center;justify-content:space-between;
  gap:var(--s1);margin-bottom:var(--s2)}
.card-head .left{display:flex;align-items:center;gap:7px;min-width:0}
.name{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.host{color:var(--dim);font-size:11px}
.head-right{display:flex;align-items:center;gap:6px}

/* status is never colour alone: the dot has a shape and a label beside it */
.dot{width:8px;height:8px;border-radius:50%;flex:none}
.dot.on{background:var(--ok);box-shadow:0 0 0 3px rgba(34,197,94,.16)}
.dot.off{background:var(--bad);box-shadow:0 0 0 3px rgba(239,68,68,.16)}
.state{font-size:11px;color:var(--dim)}

.icon{border:0;background:transparent;color:var(--dim);
  padding:6px;min-height:32px;border-radius:var(--r1)}
.icon:hover{background:var(--muted);color:var(--ink);border-color:transparent}

.bars{display:grid;gap:7px}
.bar-row{display:grid;grid-template-columns:46px 1fr 44px;align-items:center;
  gap:var(--s1);font-size:11px;color:var(--dim)}
.bar{height:6px;border-radius:3px;background:var(--muted);overflow:hidden}
.bar i{display:block;height:100%;border-radius:3px;background:var(--ok);
  transition:width var(--slow) ease-out}
.bar i.warn{background:var(--warn)} .bar i.bad{background:var(--bad)}
.val{text-align:left;color:var(--ink);font-size:11px}

.rate{margin-top:var(--s2);display:flex;gap:var(--s3);
  color:var(--dim);font-size:12px}
.rate b{color:var(--ink);font-weight:500}
.traffic{margin-top:var(--s2);padding-top:var(--s2);border-top:1px solid var(--line);
  display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s1);text-align:center}
.traffic span{display:block;color:var(--dim);font-size:10px;
  text-transform:uppercase;letter-spacing:.04em}
.traffic b{font-size:13px;display:block;margin-top:2px}
.err{margin-top:var(--s2);color:var(--bad);font-size:11px;
  background:rgba(239,68,68,.1);border-radius:var(--r1);padding:7px 9px;
  word-break:break-all}

/* ------------------------------------------------------------- dialogs */
.modal{position:fixed;inset:0;z-index:50;display:grid;place-items:center;
  padding:var(--s3);background:rgba(2,6,23,.62);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.sheet{background:var(--card);border:1px solid var(--line-strong);
  border-radius:var(--r3);padding:var(--s4);width:min(540px,100%);
  max-height:92dvh;overflow:auto;box-shadow:0 24px 64px rgba(0,0,0,.45)}
.sheet.wide{width:min(1120px,100%)}
.sheet-head{display:flex;align-items:center;justify-content:space-between;
  gap:var(--s2);margin-bottom:var(--s3);flex-wrap:wrap}
.sheet-foot{display:flex;gap:var(--s1);margin-top:var(--s4);flex-wrap:wrap}
.sheet label{display:block;margin-top:var(--s2);color:var(--dim);font-size:12px}
.sheet input,.sheet textarea{width:100%;margin-top:5px;padding:10px 12px;
  min-height:42px;border-radius:var(--r1);border:1px solid var(--line-strong);
  background:var(--bg);color:var(--ink);font:inherit;font-size:14px;
  transition:border-color var(--fast)}
.sheet input:focus,.sheet textarea:focus{border-color:var(--accent);outline:none}
.sheet textarea{font-family:"Fira Code",Samim,ui-monospace,monospace;
  font-size:12px;line-height:1.5}
.row{display:flex;gap:var(--s1);align-items:flex-end}
.grow{flex:1} .narrow{width:104px}
.hint{opacity:.75}

.tabs,.seg{display:inline-flex;border:1px solid var(--line-strong);
  border-radius:var(--r1);overflow:hidden;margin-top:var(--s3);flex-wrap:wrap}
.seg{margin-top:0}
.tabs button,.seg button{border:0;border-radius:0;min-height:38px;
  padding:8px 13px;background:transparent;font-size:13px}
.tabs button.on,.seg button.on{background:var(--accent);color:#052e3a;font-weight:600}

.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));
  gap:var(--s1);margin-bottom:var(--s3)}
.stats > div{background:var(--bg);border:1px solid var(--line);
  border-radius:var(--r2);padding:10px 12px}
.stats span{display:block;color:var(--dim);font-size:10px;
  text-transform:uppercase;letter-spacing:.04em}
.stats b{font-size:15px;display:block;margin-top:2px}

.charts{display:grid;gap:var(--s2)}
.chart{background:var(--bg);border:1px solid var(--line);
  border-radius:var(--r2);padding:var(--s2) var(--s3) var(--s3)}
.chart canvas{height:240px!important}

.msg{margin-top:var(--s2);padding:9px 12px;border-radius:var(--r1);font-size:13px;
  background:rgba(239,68,68,.12);color:#FCA5A5;word-break:break-word;
  border:1px solid rgba(239,68,68,.25)}
.msg.ok{background:rgba(34,197,94,.12);color:#86EFAC;border-color:rgba(34,197,94,.25)}
.thin{color:var(--dim);font-size:12px;margin:0 0 var(--s2);padding:9px 12px;
  border:1px dashed var(--line-strong);border-radius:var(--r1)}
.empty{color:var(--dim);text-align:center;padding:72px var(--s3)}
.boot-error{position:fixed;inset-inline:var(--s3);bottom:var(--s3);z-index:99;
  background:var(--bad);color:#fff;padding:12px var(--s3);border-radius:var(--r2);
  font-size:13px;box-shadow:0 8px 28px rgba(0,0,0,.4)}
.sub{color:var(--dim);margin:6px 0 var(--s3);font-size:14px}

body.centre .card{width:min(380px,100%)}
body.centre .card input{width:100%;margin-top:10px;padding:11px 13px;
  min-height:44px;border-radius:var(--r1);border:1px solid var(--line-strong);
  background:var(--bg);color:var(--ink);font:inherit}
body.centre .card button{width:100%;margin-top:var(--s2);justify-content:center}

@media (max-width:640px){
  main{padding:var(--s2)}
  header{padding:var(--s2)}
  .cards{grid-template-columns:1fr}
  .sheet{padding:var(--s3)}
  .chart canvas{height:200px!important}
}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  .card.clickable:hover{transform:none}
}
