/* The shared interaction layer (Reference: "UI interaction and loading standard").
   panel.css is the prototype's look; this file adds what every screen needs on top:
   the request bar, busy buttons, skeletons, toasts, the connection banner, entrances. */

/* The hidden attribute always wins, even over a class that sets display. */
[hidden]{display:none!important}

/* ---------- top progress bar: on while any request runs (progress.js) ---------- */
.topprog{position:fixed;top:0;left:0;right:0;height:2px;z-index:90;pointer-events:none;
  opacity:0;transition:opacity .2s ease-out;overflow:hidden}
.topprog.on{opacity:1}
.topprog i{display:block;height:100%;width:38%;background:var(--accent);
  animation:topprog 1.1s cubic-bezier(.4,0,.2,1) infinite}
@keyframes topprog{from{transform:translateX(-100%)}to{transform:translateX(265%)}}

/* ---------- busy buttons (busy.js keeps the width, so nothing beside it moves) ---------- */
.btn.busy{pointer-events:none}
.btn.busy .ico{color:var(--accent)}
.btn.pri.busy,.btn.dan.busy{color:#fff;opacity:.85}
.btn.pri.busy .ico,.btn.dan.busy .ico{color:#fff}
.btn[aria-disabled="true"]{cursor:not-allowed;opacity:.5}

/* a row being acted on dims slightly; its state badge carries the spinner */
[data-row].acting{opacity:.62;transition:opacity .15s ease-out}

/* ---------- skeletons: first load only; refreshes keep the real content ---------- */
.skel{border-radius:3px;background:linear-gradient(90deg,var(--panel2) 0%,var(--line) 45%,var(--panel2) 90%);
  background-size:300% 100%;animation:shimmer 1.3s ease-in-out infinite}
.skel-line{height:10px;margin:4px 0}
.skel-line.tall{height:22px;margin-top:10px}
.w40{width:40%}.w55{width:55%}.w70{width:70%}.w90{width:90%}
@keyframes shimmer{from{background-position:100% 0}to{background-position:-50% 0}}

/* content that replaces a skeleton fades in */
.enter{animation:enter .15s ease-out both}
@keyframes enter{from{opacity:0;transform:translateY(3px)}}

/* ---------- toasts: bottom-right, stacked (toast.js) ---------- */
.toasts{position:fixed;right:18px;bottom:calc(18px + env(safe-area-inset-bottom,0px));z-index:80;
  display:flex;flex-direction:column;align-items:flex-end;gap:8px;max-width:min(420px,calc(100vw - 32px));pointer-events:none}
.toastx{pointer-events:auto;display:flex;align-items:flex-start;gap:9px;padding:10px 12px 10px 13px;
  border:1px solid var(--line2);background:var(--fg);color:#fff;border-radius:5px;font-size:12px;line-height:1.45;
  box-shadow:0 8px 24px rgba(26,29,33,.18);animation:toastIn .18s cubic-bezier(.22,.61,.36,1) both}
.toastx .ico{font-size:17px;flex:0 0 auto;margin-top:-1px}
.toastx.success .ico{color:#7ee2a8}
.toastx.error{background:#fff;color:var(--fg);border-color:var(--red);box-shadow:0 8px 24px rgba(190,18,60,.14)}
.toastx.error .ico{color:var(--red)}
.toastx.info .ico{color:#b9c0ff}
.toastx .x{margin-left:6px;background:none;border:0;color:inherit;opacity:.6;cursor:pointer;padding:0;font-size:16px}
.toastx .x:hover{opacity:1}
.toastx.out{animation:toastOut .16s ease-in both}
@keyframes toastIn{from{opacity:0;transform:translateY(8px) scale(.98)}}
@keyframes toastOut{to{opacity:0;transform:translateY(6px)}}

/* ---------- connection banner (net.js) ---------- */
.netbanner{position:fixed;top:0;left:50%;transform:translateX(-50%);z-index:85;margin-top:8px;
  display:flex;align-items:center;gap:8px;padding:7px 13px;border-radius:4px;font-size:12px;
  background:var(--amberT2);color:var(--amber);border:1px solid rgba(180,83,9,.3);
  box-shadow:0 4px 14px rgba(26,29,33,.08);animation:toastIn .18s ease-out both}
.netbanner .ico{font-size:16px}
body.offline .btn:not([data-keep-online]),body.offline .ib{pointer-events:none;opacity:.5}

/* ---------- error feedback: one shake, then a red mark until the next refresh ---------- */
.shake{animation:shake .32s cubic-bezier(.36,.07,.19,.97) both}
@keyframes shake{20%,60%{transform:translateX(-3px)}40%,80%{transform:translateX(3px)}}
[data-row].failed{box-shadow:inset 3px 0 0 var(--red)}

/* ---------- step list for long actions (steps.js) ---------- */
.steplist{display:flex;flex-direction:column;gap:2px;padding:10px 16px}
.stepline{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:8px;align-items:center;
  padding:6px 0;font-size:12px;border-bottom:1px solid var(--line);transition:color .15s ease-out}
.stepline:last-child{border-bottom:0}
.stepline .ico{font-size:17px}
.stepline .why{font-size:11px;color:var(--fg3);text-align:right}
.stepline.pending{color:var(--fg3)}
.stepline.running .ico{color:var(--accent)}
.stepline.done .ico{color:var(--green)}
.stepline.failed .ico,.stepline.failed .why{color:var(--red)}

/* ---------- sidebar entries for screens not built yet ---------- */
.navitem.off{cursor:default;opacity:.55}
.navitem.off:hover{background:none}
a.navitem{text-decoration:none}
a.navitem:hover{text-decoration:none}

/* ---------- reduced motion: every end state, no movement ---------- */
@media (prefers-reduced-motion:reduce){
  .topprog i,.skel,.enter,.toastx,.toastx.out,.netbanner,.shake{animation:none}
  [data-row].acting{transition:none}
}

/* ---------- cards never push the page sideways ---------- */
/* Grid items default to min-width:auto, so one long nowrap value widens its column past the
   screen. Let cards shrink; long text belongs on the .note line, where it wraps. */
.cards>.card{min-width:0}
.card .figs{min-width:0;overflow:hidden}
.card .sub{min-width:0;overflow:hidden;text-overflow:ellipsis}
.card .note{overflow-wrap:anywhere}

/* ---------- sign-in pages (Views/Account, _AuthLayout) ---------- */
.authwrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px 16px}
.authcard{width:100%;max-width:400px;background:var(--panel);border:1px solid var(--line);border-radius:6px;
  padding:22px 24px 18px;box-shadow:0 8px 28px rgba(26,29,33,.06)}
.authbrand{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:18px;
  padding-bottom:12px;border-bottom:1px solid var(--line);font-size:12px}
.authbrand b{font-size:13px;font-weight:600}
.authcard h1{font-size:17px}
.authlead{margin:6px 0 16px;font-size:12.5px;line-height:1.55}
.authfield{display:flex;flex-direction:column;gap:5px;margin-bottom:13px;font-size:12px;color:var(--fg2)}
.authfield .in{width:100%;padding:8px 10px;font-size:13px}
.authsubmit{width:100%;justify-content:center;padding:9px 12px;margin-top:4px}
.autherr{display:flex;align-items:center;gap:8px;margin-bottom:14px;padding:9px 11px;border-radius:4px;
  background:var(--redT);color:var(--red);border:1px solid rgba(190,18,60,.22);font-size:12.5px}
.autherr .ico{font-size:17px}
.authuser{background:var(--panel2);color:var(--fg2)}
/* the demo panel's label next to "redis panel" (Panel:Label) */
.envtag{display:inline-block;margin-left:7px;padding:1px 7px;border:1px solid var(--amber);border-radius:3px;background:var(--amberT);
  color:var(--amber);font-size:10.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;vertical-align:1px}
.authbrand .envtag{margin-right:auto}

/* the eye inside a password field (ui/password-eye.js) */
.pwwrap{position:relative;display:block}
.authfield .pwwrap .in{padding-right:40px}
.pweye{position:absolute;right:4px;top:50%;transform:translateY(-50%);width:32px;height:30px;display:inline-flex;
  align-items:center;justify-content:center;border:0;border-radius:4px;background:transparent;color:var(--fg3);cursor:pointer}
.pweye:hover{color:var(--fg);background:var(--panel2)}
.pweye:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.pweye .ico{font-size:18px}
.input-validation-error{border-color:var(--red)!important}
.field-validation-valid{display:none}

/* the signed-in user in the top bar */
.top .who{margin-left:auto;display:flex;align-items:center;gap:10px;font-size:12px;color:var(--fg2)}
.top .who form{margin:0}
.top .who .btn{padding:4px 9px}

/* ---------- instances: badges, empty rows, the create page's links ---------- */
.badge.failed{background:var(--redT);color:var(--red);box-shadow:inset 0 0 0 1px rgba(190,18,60,.22)}
.badge.starting,.badge.stopping,.badge.unknown{background:var(--panel2);color:var(--fg3);box-shadow:inset 0 0 0 1px var(--line2)}
.emptyrow{padding:22px 14px;color:var(--fg2);font-size:12.5px}
.emptyrow a,.note a{color:var(--accent)}
a.ico.back{text-decoration:none;color:var(--fg2)}
.pcard:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* ---------- create: the live config preview (loading look while the server re-renders) ---------- */
.previewsec .hd{position:relative}
.previewsec .hd .upd{display:none;align-items:center;gap:5px;font-size:11px;font-weight:400;color:var(--accent)}
.previewsec .hd .upd .ico{font-size:14px}
.previewsec pre{transition:opacity .15s ease-out}
.previewsec pre .cl{display:block;margin:0 -13px;padding:0 13px;border-radius:2px}
.previewsec pre .cl.changed{animation:lineflash 1.8s ease-out}
@keyframes lineflash{0%,55%{background:var(--accentT);color:var(--fg)}100%{background:transparent}}
form.updating .previewsec .hd .upd{display:inline-flex}
form.updating .previewsec pre{opacity:.45}
form.updating .previewsec .hd::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;
  background:linear-gradient(90deg,transparent,var(--accent),transparent) no-repeat;background-size:35% 100%;
  animation:scanline 1s linear infinite}
@keyframes scanline{from{background-position:-50% 0}to{background-position:150% 0}}
#fPort,.guard .gnums{transition:opacity .15s ease-out}
form.updating #fPort,form.updating .guard .gnums{opacity:.45}
@media (prefers-reduced-motion: reduce){
  form.updating .previewsec .hd::after{animation:none;background-position:50% 0}
  .previewsec pre .cl.changed{animation:none}
}

/* ---------- live list (P5): CPU, ops, keys and clients join the P4 columns ---------- */
.tr.p5{min-width:1130px;grid-template-columns:minmax(0,1.5fr) 108px 150px 58px 64px 64px 58px 56px 112px 200px}
.tr.p5 .num,.tr.head.p5 .r{text-align:right}
.evict{color:var(--amber);font-family:'IBM Plex Sans',system-ui,sans-serif;margin-left:4px}
.warnico{font-size:16px;color:var(--amber);vertical-align:-3px;cursor:help}
.menu[hidden]{display:none}

/* ---------- the done part of a step dialog (create): the steps fold away, the result shows ---------- */
.stepdone{padding:2px 0 4px}
.steps-overlay .modal:has(.stepdone){width:600px;max-width:calc(100vw - 48px)}
.stepsfold{border:1px solid var(--line);border-radius:4px;margin-bottom:12px}
.stepsfold summary{display:flex;align-items:center;gap:7px;padding:8px 11px;font-size:12px;color:var(--fg2);cursor:pointer;list-style:none}
.stepsfold summary::-webkit-details-marker{display:none}
.stepsfold summary .ico{font-size:16px;color:var(--green)}
.stepsfold summary .more{margin-left:auto;color:var(--accent);font-size:11.5px}
.stepsfold summary .more::after{content:"Show steps"}
.stepsfold[open] summary .more::after{content:"Hide steps"}
.stepsfold[open] summary{border-bottom:1px solid var(--line)}
.stepsfold .stepline{padding-left:11px;padding-right:11px}
.donetags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:14px}
.donetags .tag{font-family:'JetBrains Mono',monospace;font-size:11px;padding:2px 8px;border-radius:3px;
  background:var(--panel2);color:var(--fg2);box-shadow:inset 0 0 0 1px var(--line2)}
.donesec + .donesec{margin-top:16px}
.donettl{font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--fg3);margin-bottom:4px}
.kv{display:grid;grid-template-columns:84px minmax(0,1fr);gap:12px;align-items:center;min-height:34px;
  padding:5px 0;border-top:1px solid var(--line)}
.kv .k{font-size:12px;color:var(--fg2)}
.kv .v{min-width:0;font-size:12.5px;color:var(--fg);overflow-wrap:anywhere}
.kvcode{display:flex;align-items:center;gap:6px;min-width:0}
.kvcode code{flex:1 1 auto;min-width:0;padding:5px 9px;border:1px solid var(--line);border-radius:3px;background:var(--panel2);
  font-family:'JetBrains Mono',monospace;font-size:11.5px;line-height:1.5;color:var(--fg);white-space:pre-wrap;overflow-wrap:break-word}
.kvcode code .w{white-space:nowrap}
.kvcode .ib{flex:0 0 auto}
.kvcode .ib.copied{color:var(--green);border-color:var(--green)}

/* ---------- config editor (P6) ---------- */
.tag.registry{background:var(--accentT);color:var(--accent)}
.frow{transition:background .2s ease-out}
.frow.chg{background:linear-gradient(90deg,var(--accentT),transparent 60%)}
.frow .hint{margin-top:4px}
.unitin{display:flex;gap:7px;align-items:center}
label.radio{display:inline-block}
.warnbox.calm{border-color:var(--line2);background:var(--panel2)}
.warnbox.calm .ico,.warnbox.calm b{color:var(--fg2)}
.stalebox{align-items:flex-start}
.stalebox .btn{flex:0 0 auto}
.stalediff{margin-top:8px}
.stalediff summary{cursor:pointer;color:var(--accent);font-size:12px}
.stalediff .diff{margin-top:6px;border:1px solid var(--line);background:var(--panel);max-height:320px;overflow:auto}
.previewsec .diff,.previewsec .cmds{transition:opacity .15s ease-out}
form.updating .previewsec .diff,form.updating .previewsec .cmds{opacity:.45}
.donesec .kv .tag{margin-left:6px}

/* ---------- credentials (P7): masked password, rotate, recent activity ---------- */
.secret code{transition:color .15s ease-out}
.secret code.masked{color:var(--fg3);letter-spacing:.08em;user-select:none}
.secret.shown code{color:var(--fg);background:var(--amberT)}
.secret .ib.busy{color:var(--fg3)}
.rotbox .radios{margin-top:6px}
.rotbox [data-typed]{margin-top:10px}
.rotbox [data-typed] .in{width:100%;font-family:'JetBrains Mono',monospace;font-size:12px}
.rotbox .warnbox,.stepdone .warnbox{margin-top:12px}
.actlist{display:flex;flex-direction:column}
.actrow{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:9px;align-items:start;padding:7px 0;
  border-top:1px solid var(--line);font-size:12px;color:var(--fg2)}
.actrow b{color:var(--fg);font-weight:500}
.actrow .ico{font-size:16px;color:var(--fg3);margin-top:1px}
.actrow.rot .ico{color:var(--accent)}
.actrow.bad .ico,.actrow.bad b{color:var(--red)}
.actrow .d{font-size:11px;color:var(--fg3);margin-top:2px;overflow-wrap:anywhere}
.actrow .when{font-size:11px;color:var(--fg3);white-space:nowrap;cursor:help}
.actempty{padding:8px 0;border-top:1px solid var(--line);font-size:12px;color:var(--fg3)}
/* Redis 8 modules on a list row: small icons under the port line, like RedisInsight's Capabilities */
.mods{display:flex;gap:7px;margin-top:5px;line-height:0}
.mods .mod{display:inline-flex;color:var(--fg2);cursor:help;transition:color .15s}
.mods .mod:hover{color:var(--accent)}
.mods .mod.dim{color:var(--fg3);opacity:.5}

/* Redis 8 modules: checkbox chips (create form, config editor) */
.modchips{display:flex;flex-wrap:wrap;gap:6px}
.modchip{display:inline-flex;align-items:center;gap:5px;padding:5px 10px 5px 7px;border:1px solid var(--line2);background:var(--panel2);
  border-radius:4px;cursor:pointer;font-size:12px;color:var(--fg2);user-select:none;transition:border-color .15s,background .15s,color .15s}
.modchip input{position:absolute;opacity:0;pointer-events:none}
.modchip .ico{font-size:16px;color:var(--fg3)}
.modchip.on{border-color:var(--accent);background:var(--accentT);color:var(--fg)}
.modchip.on .ico{color:var(--accent)}
.modchip:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:1px}
.modchip.fixed{cursor:default;opacity:.7}
.modchip .d{margin-left:4px;font-size:10.5px;color:var(--fg3)}
@media (prefers-reduced-motion:reduce){.modchip{transition:none}}

/* RedisInsight login (P11) */
.pwrow{display:flex;gap:6px;align-items:center}
.pwrow .in{flex:1;min-width:0}
.pwrow .in[readonly]{color:var(--fg3);background:transparent}
.hint.stage{color:var(--accent)}
.confirmrow{display:flex;align-items:center;gap:7px;margin-right:auto;font-size:12px;color:var(--fg2);animation:enter .15s ease-out both}
.modal .mf .confirmrow .ico{color:var(--amber);font-size:17px}
@media (prefers-reduced-motion:reduce){.confirmrow{animation:none}}

/* ---------- logging, flush, bulk (P8) ---------- */
.tgl.wait{cursor:progress;opacity:.7}
.tgl.wait .knob{animation:pulse 1s ease-in-out infinite}
.logcell .logsz{white-space:nowrap}
.cards .card .cardfoot .autowrap{position:relative}
.cards .card .cardfoot .menu{left:0;right:auto;top:calc(100% + 4px)}
.retbtn.busy{color:var(--fg3);cursor:progress}
.retbtn{white-space:nowrap}
.cardfoot > span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media (prefers-reduced-motion:reduce){.tgl.wait .knob{animation:none}}

/* ---------- audit log (P8) ---------- */
.auditbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.auditbar .chk{margin:0;padding:6px 9px;align-items:center}
.auditbar .chk input{margin:0}
.arow{grid-template-columns:150px 90px 130px 150px minmax(0,1fr);align-items:baseline}
.arow .when{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--fg2);white-space:nowrap}
.arow .act{font-family:'JetBrains Mono',monospace;font-size:11.5px}
.arow .det{color:var(--fg2);overflow-wrap:anywhere}
.arow.bad .act,.arow.bad .det{color:var(--red)}
.arow .okdot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--green);margin-right:6px;vertical-align:1px}
.arow.bad .okdot{background:var(--red)}
.arow.enter{animation:enter .15s ease-out both}
.auditsec{overflow-x:auto}
.auditsec .arow{min-width:760px}
.cardfoot .menu .mi.on .mh{margin-left:auto}
.cardfoot .menu .mi .tick{margin-left:0}

/* ---------- instance detail (P9): charts, band, hover card ---------- */
.dsec{margin:22px 0 0;font-size:13px;font-weight:600}
.chartskel{height:104px;margin-top:12px}
.plot{position:relative}
.band .gridl{stroke:var(--line);stroke-width:1;vector-effect:non-scaling-stroke;opacity:.7}
.band .bandfill{fill:var(--fg3);opacity:.16}
.band .areafill{fill:var(--accent);opacity:.1}
.band .avgl{stroke-width:1.7;vector-effect:non-scaling-stroke;stroke-linejoin:round}
.band .maxl{stroke-width:1;vector-effect:non-scaling-stroke;opacity:.35;stroke-dasharray:3 2}
.band .limitl{stroke:var(--red);stroke-width:1;stroke-dasharray:4 3;vector-effect:non-scaling-stroke}
.sw.maxsw{opacity:.4}
.sw.limsw{background:none;border-top:1px dashed var(--red);height:0;border-radius:0}
.band.draw{animation:chartdraw .6s cubic-bezier(.22,.61,.36,1) both}
@keyframes chartdraw{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 0 0 0)}}
.plot .guide{position:absolute;top:0;height:104px;width:0;border-left:1px dashed var(--fg3);pointer-events:none}
.plot .dot{position:absolute;width:7px;height:7px;border-radius:50%;margin:-3.5px 0 0 -3.5px;box-shadow:0 0 0 2px var(--panel);pointer-events:none}
.plot .tip{position:absolute;top:4px;z-index:5;padding:6px 9px;border:1px solid var(--line2);border-radius:4px;background:var(--panel);
  box-shadow:0 4px 14px rgba(0,0,0,.12);font-size:11.5px;color:var(--fg2);white-space:nowrap;pointer-events:none}
.plot .tip b{color:var(--fg);font-family:'JetBrains Mono',monospace;font-weight:500}
.plot .tip .tt{font-size:10.5px;color:var(--fg3);margin-bottom:2px}
.plot .tip .tn{font-size:10.5px;color:var(--fg3);margin-top:2px}
.plot svg{cursor:crosshair}
.plot .nodata{position:absolute;inset:0 0 18px;display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--fg3)}
body.updating #charts,body.updating #stats,body.updating #month{opacity:.5;transition:opacity .15s}
#charts,#stats,#month{transition:opacity .15s}
@media (prefers-reduced-motion:reduce){.band.draw{animation:none}}
#charts{grid-template-columns:repeat(2,minmax(0,1fr))}
@media (max-width:900px){#charts{grid-template-columns:minmax(0,1fr)}}

/* ---------- busy tip: what an icon button is doing ("Stopping…") ---------- */
.busytip{position:fixed;z-index:120;transform:translate(-50%,calc(-100% + 4px));opacity:0;pointer-events:none;
  display:inline-flex;align-items:center;gap:6px;padding:5px 9px;border-radius:4px;background:#1f2430;color:#fff;
  font-size:11.5px;font-weight:500;white-space:nowrap;box-shadow:0 4px 14px rgba(0,0,0,.22);
  transition:opacity .14s ease-out,transform .14s ease-out}
.busytip .ico{font-size:14px;color:#9fb0ff}
.busytip::after{content:"";position:absolute;left:50%;bottom:-4px;width:8px;height:8px;margin-left:-4px;background:#1f2430;transform:rotate(45deg)}
.busytip.in{opacity:1;transform:translate(-50%,-100%)}
.busytip.out{opacity:0;transform:translate(-50%,calc(-100% + 4px))}
.ib.busy{color:var(--accent);border-color:var(--accent);cursor:progress}
.ib.busy .ico.spin{font-size:16px}
@media (prefers-reduced-motion:reduce){.busytip{transition:none}}

/* ---------- capacity (P10) ---------- */
.slowrow.pvrow{min-width:0;grid-template-columns:minmax(0,140px) 64px 64px 78px minmax(0,1fr)}
.slowrow.pvrow .recwhy{line-height:1.4}
