  /* Pre-paint auth gating: hide whichever view doesn't match the saved token,
     set synchronously in <head> so there's no login-page flash on refresh.
     The main script still calls showApp()/logout to keep these in sync. */
  html[data-auth="in"] #login { display:none !important; }
  html[data-auth="out"] #app { display:none !important; }
  /* No-flash i18n: keep the page invisible until the i18n module has filled in
     the static text in the resolved language, so the user never sees a flash of
     the source language before it's translated. Revealed by setting
     data-i18n-ready (see js/i18n.js), which runs before first meaningful paint. */
  html:not([data-i18n-ready]) body { visibility:hidden; }
  /* ---- Theme tokens: dark (default) ---- */
  :root {
    --bg:#070b14; --panel:rgba(18,26,42,0.72); --panel-solid:#0e1626; --panel2:rgba(8,13,24,0.85);
    --line:rgba(90,120,180,0.18); --line2:rgba(90,120,180,0.30); --fg:#dbe6f5; --mut:#8294b0;
    --cy:#22d3ee; --br:#3b82f6; --vio:#8b5cf6; --ok:#34d399; --err:#fb7185; --warn:#fbbf24;
    --glow:0 0 24px rgba(34,211,238,0.18); --shadow:0 10px 40px rgba(0,0,0,0.4);
    --hov:rgba(60,80,120,0.14); --acc-soft:rgba(59,130,246,0.14);
    --app-bg:
      radial-gradient(1200px 700px at 85% -10%, rgba(59,130,246,0.16), transparent 60%),
      radial-gradient(900px 600px at -10% 110%, rgba(139,92,246,0.14), transparent 55%),
      var(--bg);
  }
  /* ---- Light theme overrides ---- */
  html[data-theme="light"] {
    --bg:#eef2f8; --panel:rgba(255,255,255,0.82); --panel-solid:#ffffff; --panel2:rgba(255,255,255,0.92);
    --line:rgba(40,70,120,0.14); --line2:rgba(40,70,120,0.24); --fg:#1b2536; --mut:#5d6b85;
    --cy:#0891b2; --br:#2563eb; --vio:#7c3aed; --ok:#059669; --err:#e11d48; --warn:#d97706;
    --glow:0 0 24px rgba(37,99,235,0.10); --shadow:0 10px 30px rgba(30,50,90,0.12);
    --hov:rgba(40,70,120,0.07); --acc-soft:rgba(37,99,235,0.10);
    --app-bg:
      radial-gradient(1100px 650px at 88% -12%, rgba(37,99,235,0.10), transparent 60%),
      radial-gradient(820px 560px at -8% 112%, rgba(124,58,237,0.08), transparent 55%),
      var(--bg);
  }
  * { box-sizing:border-box; }
  html,body { height:100%; overscroll-behavior:none; }
  body {
    margin:0; color:var(--fg); font:14px/1.55 -apple-system,Segoe UI,Roboto,"PingFang SC",sans-serif;
    background:var(--app-bg); background-attachment:fixed; transition:background .25s,color .25s;
  }
  a { color:var(--cy); }
  .hidden { display:none !important; }
  .mono { font-family:ui-monospace,Menlo,Consolas,monospace; }
  .mut { color:var(--mut); }
  input,select,textarea,button { font:inherit; color:var(--fg); }
  .field { width:100%; padding:10px 12px; background:var(--panel2); border:1px solid var(--line); border-radius:10px; outline:none; transition:border-color .15s,box-shadow .15s; }
  .field:focus { border-color:var(--cy); box-shadow:0 0 0 3px var(--acc-soft); }
  /* The console is mouse-driven. Tabbing must never paint the browser's default
     focus ring (it looked broken on buttons, links, cells and scroll regions).
     Deliberate focus affordances (inputs, terminal) use border/box-shadow, not
     outline, so they are unaffected. */
  :focus { outline:none !important; }
  :focus-visible { outline:none !important; }
  /* Password field with an inline show/hide eye button. */
  .pwf { position:relative; }
  .pwf .field { padding-right:38px; }
  .pwf-eye { position:absolute; right:6px; top:50%; transform:translateY(-50%); width:28px; height:28px; display:flex; align-items:center; justify-content:center;
    background:none; border:none; color:var(--mut); cursor:pointer; border-radius:7px; }
  .pwf-eye:hover { color:var(--fg); background:var(--hov); }
  select.field { appearance:none; -webkit-appearance:none; cursor:pointer; padding-right:32px;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238294b0' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat:no-repeat; background-position:right 11px center; }
  /* Custom select popup: replaces the native OS dropdown list so options match
     the app theme. The real <select> stays as the source of truth (value /
     change / dynamic options); we only intercept its dropdown and render this. */
  .selx-pop { position:fixed; z-index:120; max-height:260px; overflow-y:auto;
    background:var(--panel-solid); border:1px solid var(--line2); border-radius:10px; box-shadow:var(--shadow); padding:4px; }
  .selx-search { width:100%; box-sizing:border-box; margin-bottom:4px; padding:7px 10px; font-size:13px; border:1px solid var(--line2); border-radius:8px; background:var(--panel2); color:var(--fg); outline:none; position:sticky; top:0; }
  .selx-opt.selx-hide { display:none; }
  .selx-opt { padding:9px 11px; font-size:13px; cursor:pointer; border-radius:7px; display:flex; align-items:center; gap:8px; }
  .selx-opt:hover, .selx-opt.active { background:var(--hov); }
  .selx-opt.sel { color:var(--cy); }
  .selx-opt.sel::after { content:'✓'; margin-left:auto; font-size:12px; }
  .selx-opt.dis { color:var(--mut); cursor:default; opacity:.55; }
  .selx-opt.dis:hover { background:none; }
  /* Rich two-line option (main title + subtitle left, hint right). */
  .selx-opt.selx-rich { flex-direction:column; align-items:stretch; gap:3px; padding:8px 11px; }
  .selx-opt.selx-rich::after { content:none; }
  .selx-opt.selx-rich .selx-main { display:flex; align-items:baseline; gap:8px; }
  .selx-opt.selx-rich .selx-t { font-size:13px; font-weight:550; }
  .selx-opt.selx-rich .selx-r { margin-left:auto; font-size:11px; color:var(--mut); white-space:nowrap; }
  .selx-opt.selx-rich .selx-sub { font-size:11.5px; color:var(--mut); }
  .selx-opt.selx-rich.sel { background:var(--acc-soft); }
  .selx-opt.selx-rich.sel .selx-t { color:var(--cy); }
  /* Language switcher: small flag glyph before each language (globe for English). */
  .lang-opt .flag { margin-right:2px; }
  .flag { display:inline-flex; align-items:center; justify-content:center; width:21px; height:15px; flex:0 0 auto;
    border-radius:3px; overflow:hidden; box-shadow:0 0 0 1px rgba(0,0,0,0.14); }
  .flag svg { width:100%; height:100%; display:block; }
  .flag.globe { width:18px; height:18px; border-radius:0; box-shadow:none; color:var(--mut); }
  .btn { background:linear-gradient(135deg,var(--br),var(--vio)); color:#fff; border:none; padding:10px 16px; border-radius:10px; cursor:pointer; font-weight:500; letter-spacing:.3px; transition:transform .08s,opacity .15s; }
  .btn:hover { opacity:.92; } .btn:active { transform:translateY(1px); }
  .btn.sec { background:var(--hov); border:1px solid var(--line); color:var(--fg); }
  .btn.sm { padding:6px 11px; border-radius:8px; font-size:12.5px; }
  .btn.danger { background:linear-gradient(135deg,#e11d48,#fb7185); }
  .btn[disabled] { opacity:.5; cursor:not-allowed; }
  select.field:disabled { opacity:.65; cursor:not-allowed; color:var(--mut); }
  .err { color:var(--err); font-size:13px; min-height:18px; }
  .ok { color:var(--ok); }
  .chip { display:inline-flex; align-items:center; gap:5px; padding:0 8px; height:18px; line-height:1; border-radius:99px; font-size:11.5px; border:1px solid var(--line2); color:var(--mut); }
  .chip.on { color:var(--ok); border-color:rgba(52,211,153,.4); background:rgba(52,211,153,.10); }
  .chip.off { color:var(--mut); }
  .chip.warn { color:var(--warn); border-color:rgba(251,191,36,.4); background:rgba(251,191,36,.10); }
  .chip.amber { color:var(--warn); border-color:rgba(251,191,36,.4); background:rgba(251,191,36,.10); }
  .dot-s { width:7px; height:7px; border-radius:99px; background:var(--mut); display:inline-block; }
  .dot-s.on { background:var(--ok); box-shadow:0 0 8px rgba(52,211,153,.7); }
  .dot-s.warn { background:var(--warn); }
  .dot-s.amber { background:var(--warn); }
  .dot-s.init { background:var(--warn); animation:dotpulse 1.1s ease-in-out infinite; }
  @keyframes dotpulse { 0%,100%{ opacity:1; } 50%{ opacity:.35; } }
  /* Role labels (user management) — uniform box, colour-only variation. */
  .role-chip { display:inline-block; padding:2px 10px; border-radius:99px; font-size:11.5px; line-height:1.5; border:1px solid var(--line2); color:var(--mut); }
  .role-chip.owner { color:var(--ok); border-color:rgba(52,211,153,.4); }
  .role-chip.admin { color:var(--warn); border-color:rgba(251,191,36,.4); }
  .role-chip.user { color:var(--mut); }

  /* ---- Login ---- */
  #login { position:relative; min-height:100vh; display:flex; align-items:center; justify-content:center; padding:24px; overflow:hidden; }
  /* Decorative tech background: a faint grid + slowly drifting gradient orbs. */
  .login-bg { position:absolute; inset:0; z-index:0; pointer-events:none; overflow:hidden;
    background-image:
      linear-gradient(rgba(90,120,180,0.06) 1px, transparent 1px),
      linear-gradient(90deg, rgba(90,120,180,0.06) 1px, transparent 1px);
    background-size:42px 42px; background-position:center;
    -webkit-mask-image:radial-gradient(circle at 50% 45%, #000 0%, transparent 78%);
    mask-image:radial-gradient(circle at 50% 45%, #000 0%, transparent 78%); }
  .login-bg .orb { position:absolute; border-radius:50%; filter:blur(60px); opacity:.55; }
  .login-bg .o1 { width:420px; height:420px; left:-80px; top:-90px; background:radial-gradient(circle, rgba(34,211,238,0.55), transparent 70%); animation:orbf1 18s ease-in-out infinite; }
  .login-bg .o2 { width:480px; height:480px; right:-110px; bottom:-120px; background:radial-gradient(circle, rgba(139,92,246,0.50), transparent 70%); animation:orbf2 22s ease-in-out infinite; }
  .login-bg .o3 { width:360px; height:360px; left:50%; top:55%; background:radial-gradient(circle, rgba(59,130,246,0.40), transparent 70%); animation:orbf3 26s ease-in-out infinite; }
  @keyframes orbf1 { 0%,100%{transform:translate(0,0);} 50%{transform:translate(40px,30px);} }
  @keyframes orbf2 { 0%,100%{transform:translate(0,0);} 50%{transform:translate(-50px,-30px);} }
  @keyframes orbf3 { 0%,100%{transform:translate(-50%,0);} 50%{transform:translate(-46%,-26px);} }
  @media (prefers-reduced-motion: reduce){ .login-bg .orb { animation:none; } }
  /* Brand pinned to the top-left of the page. */
  .login-brand { position:absolute; z-index:2; top:24px; left:26px; display:flex; align-items:center; gap:11px; }
  .login-brand .cup { width:34px; height:34px; border-radius:10px; background:linear-gradient(135deg,var(--cy),var(--vio)); box-shadow:var(--glow); flex-shrink:0; display:flex; align-items:center; justify-content:center; }
  .login-brand .cup svg { width:21px; height:21px; }
  .login-brand h1 { font-size:18px; margin:0; letter-spacing:.5px; font-weight:650; }
  .login-card { position:relative; z-index:1; width:380px; max-width:100%; padding:34px 30px; background:var(--panel); backdrop-filter:blur(16px);
    border:1px solid var(--line2); border-radius:18px; box-shadow:var(--shadow), inset 0 1px 0 rgba(255,255,255,0.05); }
  .login-card .login-title { font-size:24px; font-weight:680; letter-spacing:.4px; }
  .login-card .sub { color:var(--mut); font-size:13px; margin:7px 0 22px; }
  .seg { display:flex; gap:6px; background:var(--panel2); border:1px solid var(--line); border-radius:10px; padding:4px; margin-bottom:18px; }
  .seg button { flex:1; background:none; border:none; color:var(--mut); padding:8px; border-radius:7px; cursor:pointer; }
  .seg button.on { background:linear-gradient(135deg,rgba(59,130,246,.32),rgba(139,92,246,.32)); color:#fff; }
  label.lbl { display:block; font-size:12px; color:var(--mut); margin:0 0 6px; }
  /* Keep both auth panes the same height so switching tabs doesn't jump. */
  .login-panes { min-height:212px; display:flex; flex-direction:column; }
  .login-panes > div { flex:1; }
  .qrwrap { text-align:center; padding:8px 0 4px; display:flex; flex-direction:column; align-items:center; justify-content:center; height:100%; }
  .qrwrap svg, .qrwrap img { background:#fff; padding:12px; border-radius:14px; width:180px; height:180px; }
  .qrwrap .tip { color:var(--mut); font-size:12px; margin-top:12px; }
  .qrstate { font-size:12px; margin-top:8px; color:var(--cy); }

  /* ---- App shell ---- */
  #app { display:flex; min-height:100vh; }
  aside { width:228px; flex-shrink:0; background:linear-gradient(180deg,var(--panel),var(--panel));
    border-right:1px solid var(--line); display:flex; flex-direction:column; padding:18px 14px; position:sticky; top:0; height:100vh; }
  aside .logo { padding:4px 8px 18px; display:flex; align-items:center; gap:11px; }
  aside .logo .cup { width:32px; height:32px; border-radius:9px; background:linear-gradient(135deg,var(--cy),var(--vio)); box-shadow:var(--glow); flex-shrink:0; display:flex; align-items:center; justify-content:center; }
  aside .logo .cup svg { width:20px; height:20px; }
  aside .logo h1 { font-size:18px; margin:0; letter-spacing:.5px; }
  nav { display:flex; flex-direction:column; gap:4px; flex:1; overflow-y:auto; }
  nav button { display:flex; align-items:center; gap:11px; background:none; border:none; color:var(--mut); padding:10px 13px;
    border-radius:10px; cursor:pointer; text-align:left; font-size:14px; transition:background .15s,color .15s; }
  nav button:hover { color:var(--fg); background:var(--hov); }
  nav button.active { color:#fff; background:linear-gradient(135deg,rgba(59,130,246,.30),rgba(139,92,246,.24)); box-shadow:inset 0 0 0 1px var(--line2); }
  html[data-theme="light"] nav button.active { color:#fff; }
  nav button .ic { width:18px; text-align:center; opacity:.95; font-size:15px; }
  aside .foot { border-top:1px solid var(--line); padding-top:12px; }
  aside .ver { font-size:11.5px; color:var(--mut); padding:0 8px; display:flex; align-items:center; justify-content:center; gap:7px; }
  aside .ver b { color:var(--fg); font-weight:600; }
  .updot { width:7px; height:7px; border-radius:99px; background:var(--cy); box-shadow:0 0 8px var(--cy); display:inline-block; margin-left:2px; }

  .content { flex:1; min-width:0; display:flex; flex-direction:column; min-height:100vh; }
  /* One-screen tabs (dashboard/terminal): cap content to the viewport so the
     body never scrolls; inner regions scroll instead. */
  .content.fillmode { height:100vh; min-height:0; overflow:hidden; }
  .topbar { display:flex; align-items:center; gap:14px; padding:13px 22px; border-bottom:1px solid var(--line);
    background:var(--panel2); backdrop-filter:blur(8px); position:sticky; top:0; z-index:5; }
  .topbar h2 { margin:0; font-size:16px; font-weight:600; letter-spacing:.4px; }
  .topbar .sp { flex:1; }
  .iconbtn { width:34px; height:34px; border-radius:9px; border:1px solid var(--line); background:var(--hov); color:var(--fg);
    cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:16px; transition:border-color .15s,background .15s; }
  .iconbtn:hover { border-color:var(--line2); }
  .userbox { display:flex; align-items:center; gap:9px; padding:5px 12px 5px 12px; border:1px solid var(--line); border-radius:99px; background:var(--hov); cursor:pointer; transition:border-color .15s; }
  .userbox:hover { border-color:var(--line2); }
  .userbox .av { width:24px; height:24px; border-radius:99px; background:linear-gradient(135deg,var(--cy),var(--vio)); display:flex; align-items:center; justify-content:center; font-size:12px; color:#fff; font-weight:600; overflow:hidden; flex:0 0 auto; }
  .userbox .av img, .av img { width:100%; height:100%; object-fit:cover; }
  .userbox .caret { color:var(--mut); font-size:10px; }
  .userbox b { font-size:13px; font-weight:600; }
  /* Big avatar (profile dialog). */
  .av-lg { width:56px; height:56px; border-radius:14px; background:linear-gradient(135deg,var(--cy),var(--vio)); display:inline-flex; align-items:center; justify-content:center; font-size:22px; color:#fff; font-weight:650; overflow:hidden; flex:0 0 auto; }
  /* Account dropdown menu. */
  .acct-pop { position:fixed; z-index:120; min-width:188px; padding:6px; background:var(--panel-solid); border:1px solid var(--line2); border-radius:12px; box-shadow:var(--shadow); }
  .acct-item { display:block; width:100%; text-align:left; background:none; border:none; color:var(--fg); padding:9px 12px; border-radius:8px; cursor:pointer; font-size:13px; }
  .acct-item:hover { background:var(--hov); }
  .acct-item.danger { color:var(--err); }
  .acct-item.danger:hover { background:rgba(251,113,133,.12); }
  .acct-sep { height:1px; background:var(--line); margin:6px 4px; }
  /* 2FA enrollment. */
  .tfa-qr { display:flex; justify-content:center; padding:8px; background:#fff; border-radius:12px; margin:0 auto 14px; width:max-content; }
  .tfa-qr svg { width:200px; height:200px; display:block; }
  .tfa-secret { background:var(--panel2); border:1px solid var(--line); border-radius:9px; padding:9px 12px; font-size:13px; letter-spacing:1px; word-break:break-all; }
  main { padding:22px 24px; }
  main.fill { padding:0; overflow:hidden; flex:1 1 auto; min-height:0; display:flex; }

  .grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:14px; }
  .card { background:var(--panel); backdrop-filter:blur(10px); border:1px solid var(--line); border-radius:14px; padding:18px; }
  .card h3 { margin:0 0 10px; font-size:12px; color:var(--mut); font-weight:500; letter-spacing:.5px; text-transform:uppercase; }
  .card .big { font-size:27px; font-weight:650; background:linear-gradient(135deg,var(--fg),var(--br)); -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; }
  .card .sub { color:var(--mut); font-size:12px; margin-top:5px; }
  .bar { height:6px; border-radius:99px; background:var(--hov); margin-top:12px; overflow:hidden; }
  .bar > i { display:block; height:100%; border-radius:99px; background:linear-gradient(90deg,var(--cy),var(--vio)); transition:width .4s; }

  /* ---- Dashboard one-screen layout ---- */
  .dash { display:flex; flex-direction:column; gap:14px; flex:1 1 auto; min-height:0; width:100%; padding:18px 24px; box-sizing:border-box; overflow:hidden; }
  /* 4 equal stat cards in one row (CPU / mem / disk / network). */
  .statrow { display:grid; grid-template-columns:repeat(4,1fr); gap:14px; flex:0 0 auto; }
  @media (max-width:860px){ .statrow { grid-template-columns:repeat(2,1fr); } }
  .dash .card { padding:15px 18px; }
  .dash .statrow .card { display:flex; flex-direction:column; min-height:128px; }
  .dash .card .big { font-size:24px; }
  /* History chart card: header (metric tabs left, range tabs right) + canvas. */
  .dash .histcard { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; padding:14px 16px; }
  .dash .histcard .hist-head { display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap; margin-bottom:10px; }
  .dash .histcard .subtabs { margin:0; }
  .dash .histcard .hist-body { position:relative; flex:1 1 auto; min-height:200px; }
  .dash .histcard .hist-body canvas { position:absolute; inset:0; display:block; width:100%; height:100%; }
  .dash .histcard .hist-empty { position:absolute; inset:0; align-items:center; justify-content:center; }
  /* Network stat card: left/right split (上行 amber, 下行 blue). */
  .netcard .netsplit { display:flex; gap:10px; margin-top:2px; }
  .netcard .netcell { flex:1; min-width:0; }
  .netcard .nethdr { display:flex; align-items:center; gap:5px; font-size:11.5px; font-weight:600; }
  .netcard .netic { width:15px; height:15px; display:inline-flex; }
  .netcard .netic svg { width:15px; height:15px; }
  .netcard .netval { font-size:16px; font-weight:650; margin-top:1px; font-variant-numeric:tabular-nums; white-space:nowrap; }
  .netcard .netval s { font-size:10.5px; color:var(--mut); text-decoration:none; margin-left:1px; }
  .netcard .netcell.up .nethdr, .netcard .netcell.up .netic { color:#f59e0b; }
  .netcard .netcell.dn .nethdr, .netcard .netcell.dn .netic { color:#38bdf8; }
  .netcard .netchart { margin:6px -2px -15px; height:34px; }
  .sechead { display:flex; align-items:center; gap:10px; margin:22px 0 12px; }
  .sechead h3 { margin:0; font-size:14px; font-weight:600; } .sechead .sp { flex:1; }
  table { width:100%; border-collapse:collapse; font-size:13px; }
  th,td { text-align:left; padding:9px 10px; border-bottom:1px solid var(--line); vertical-align:middle; }
  th { color:var(--mut); font-weight:500; font-size:12px; }
  tr:hover td { background:var(--hov); }
  th.num,td.num { text-align:right; font-variant-numeric:tabular-nums; }
  /* Operation tables (containers/images/networks): keep the action buttons on
     one line and let the whole table scroll horizontally if space is tight. */
  table.optable td.act, table.optable th.act { white-space:nowrap; width:1%; text-align:right; }
  table.optable td.act .actions { flex-wrap:nowrap; justify-content:flex-end; }
  .tablewrap { overflow-x:auto; scrollbar-width:thin; scrollbar-color:var(--line2) transparent; }
  .tablewrap::-webkit-scrollbar { height:8px; }
  .tablewrap::-webkit-scrollbar-track { background:transparent; }
  .tablewrap::-webkit-scrollbar-thumb { background:var(--line2); border-radius:99px; border:2px solid transparent; background-clip:content-box; }
  .tablewrap::-webkit-scrollbar-thumb:hover { background:var(--mut); background-clip:content-box; }
  /* Fixed-layout process tables (header + body share identical columns). */
  .row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
  .actions { display:flex; gap:6px; flex-wrap:wrap; }
  .subtabs { display:flex; gap:4px; background:var(--panel2); border:1px solid var(--line); border-radius:10px; padding:4px; margin-bottom:16px; width:fit-content; }
  .subtabs button { background:none; border:none; color:var(--mut); padding:7px 15px; border-radius:7px; cursor:pointer; font-size:13px; }
  .subtabs button.on { background:var(--acc-soft); color:var(--fg); }
  pre.out { background:var(--panel2); border:1px solid var(--line); border-radius:10px; padding:13px; max-height:50vh; overflow:auto; white-space:pre-wrap; word-break:break-all; font-size:12.5px; }
  .warn { background:rgba(251,191,36,0.08); border:1px solid rgba(251,191,36,0.3); color:var(--warn); padding:11px 13px; border-radius:11px; font-size:12.5px; margin-bottom:16px; }
  .empty { color:var(--mut); text-align:center; padding:30px; font-size:13px; }
  /* Loading skeleton — friendlier than a bare spinner/"加载中…" string. */
  .loading { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:12px; padding:36px; color:var(--mut); font-size:12.5px; }
  .spin { width:26px; height:26px; border-radius:50%; border:2.5px solid var(--line2); border-top-color:var(--cy); animation:spin360 .8s linear infinite; }
  @keyframes spin360 { to { transform:rotate(360deg); } }
  .skel { background:linear-gradient(90deg,var(--hov) 25%,var(--line2) 37%,var(--hov) 63%); background-size:400% 100%; animation:shimmer 1.3s ease-in-out infinite; border-radius:7px; }
  @keyframes shimmer { 0%{background-position:100% 0;} 100%{background-position:0 0;} }
  .skel-row { height:38px; margin:8px 0; }
  /* A list of shimmer rows used as the default loading state. */
  .skel-list { padding:14px 4px; }
  .skel-list .skel { height:16px; margin:11px 0; }
  .skel-list .skel:nth-child(3n+1){ width:42%; } .skel-list .skel:nth-child(3n+2){ width:88%; } .skel-list .skel:nth-child(3n){ width:64%; }
  .skel-cap { text-align:center; color:var(--mut); font-size:12px; padding:4px 0 2px; }
  .formgrid { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
  .formgrid .full { grid-column:1 / -1; }
  .formgrid.res3 { grid-template-columns:1fr 1fr 1fr; }
  @media (max-width:680px){ .formgrid{grid-template-columns:1fr;} .formgrid.res3{grid-template-columns:1fr;} }
  /* Dynamic key/value row lists (ports / env / volumes) — miniapp-like. */
  .kvlist { display:flex; flex-direction:column; gap:8px; }
  .kvrow { display:flex; align-items:center; gap:8px; }
  .kvrow .field { padding:8px 10px; }
  .kvrow .sep { color:var(--mut); flex:0 0 auto; font-size:13px; }
  .kvrow .rm { flex:0 0 auto; width:30px; height:30px; border-radius:8px; border:1px solid var(--line); background:var(--hov); color:var(--err); cursor:pointer; font-size:16px; line-height:1; }
  .kvrow .ro { flex:0 0 auto; display:flex; align-items:center; gap:5px; font-size:12px; color:var(--mut); white-space:nowrap; }
  .kvadd { display:block; margin:12px auto 0; font-size:12.5px; color:var(--mut); cursor:pointer; background:var(--hov); border:1px dashed var(--line2); border-radius:9px; padding:8px 18px; transition:border-color .14s,color .14s; }
  .kvadd:hover { border-color:var(--cy); color:var(--cy); }
  /* In-field icon button (MAC / IPv4 random generators sit inside the input). */
  .ifield { position:relative; display:flex; flex:1; min-width:0; }
  .ifield > input { flex:1; min-width:0; padding-right:34px; }
  .ifield-btn { position:absolute; right:5px; top:50%; transform:translateY(-50%); display:flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; border:none; background:none; color:var(--mut); cursor:pointer; border-radius:6px; }
  .ifield-btn:hover { color:var(--cy); background:var(--hov); }
  /* Field with a trailing unit (CPU 核 static / memory MB-GB toggle). */
  .field-suffix { display:flex; align-items:stretch; }
  .field-suffix > input.field { flex:1; min-width:0; border-top-right-radius:0; border-bottom-right-radius:0; }
  .field-suffix .suffix-tag, .field-suffix .suffix-btn { flex:0 0 auto; display:flex; align-items:center; justify-content:center; min-width:48px; padding:0 12px; border:1px solid var(--line2); border-left:none; border-top-right-radius:10px; border-bottom-right-radius:10px; background:var(--panel2); color:var(--mut); font-size:13px; }
  .field-suffix .suffix-btn { cursor:pointer; border-left:1px solid var(--line2); margin-left:-1px; position:relative; transition:color .12s,border-color .12s; }
  .field-suffix .suffix-btn:hover { color:var(--cy); border-color:var(--cy); z-index:1; }
  /* Volume row: source-type select + host path / volume select + container path. */
  .volrow .vr-type { flex:0 0 116px; }
  .volrow .vr-host, .volrow .vr-vol, .volrow .vr-ctn { flex:1 1 auto; min-width:0; }
  /* Host-path autocomplete dropdown (volumes-tab vr-host inputs). */
  .pathsug { position:fixed; z-index:320; max-height:240px; overflow-y:auto; background:var(--panel-solid,var(--panel2)); border:1px solid var(--line2); border-radius:9px; box-shadow:0 8px 28px rgba(0,0,0,.35); padding:4px; }
  .pathsug-it { padding:6px 10px; font-size:12.5px; color:var(--fg); border-radius:6px; cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .pathsug-it:hover { background:var(--hov); color:var(--cy); }
  .netrow .ifield { flex:1; }
  /* Network attachment row (create/edit container — a container can join many). */
  .netrow { display:flex; gap:8px; align-items:center; margin-bottom:8px; }
  .netrow .nr-net { flex:0 0 32%; }
  .netrow .nr-mac, .netrow .nr-ip { flex:1; min-width:0; }
  .netrow .nr-g { flex:0 0 auto; }
  .netrow .rm { flex:0 0 auto; width:30px; height:30px; border-radius:8px; border:1px solid var(--line); background:var(--hov); color:var(--err); cursor:pointer; font-size:16px; line-height:1; }
  /* Toggle switch (single on/off control) — used for site options. */
  .switch { display:flex; align-items:center; gap:11px; padding:11px 0; }
  .switch .swbox { position:relative; width:40px; height:22px; flex:0 0 auto; border-radius:99px; background:var(--hov); border:1px solid var(--line2); transition:background .18s; cursor:pointer; }
  .switch .swbox::after { content:''; position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:50%; background:var(--mut); transition:transform .18s, background .18s; }
  .switch input { position:absolute; opacity:0; width:0; height:0; }
  .switch input:checked + .swbox { background:linear-gradient(135deg,rgba(34,211,238,.6),rgba(139,92,246,.6)); border-color:transparent; }
  .switch input:checked + .swbox::after { transform:translateX(18px); background:#fff; }
  .switch .swtxt { display:flex; flex-direction:column; gap:1px; }
  .switch .swtxt b { font-size:13px; font-weight:550; }
  .switch .swtxt span { font-size:11.5px; color:var(--mut); }
  /* Row of inline toggles (e.g. -i / -t / start-after on the basic tab). */
  .switchrow { display:flex; flex-wrap:wrap; gap:2px 20px; }
  .switchrow .switch { flex:1 1 200px; min-width:200px; align-items:flex-start; }
  .switchrow .switch .swbox { margin-top:2px; }
  /* Compact inline toggle (used inside dynamic rows, e.g. port IPv6 / volume
     read-only). A modern switch wrapped in a card that stretches to the row
     height so it lines up cleanly with the inputs/buttons beside it. */
  .tgl { display:inline-flex; align-items:center; gap:9px; flex:0 0 auto; align-self:stretch; cursor:pointer; font-size:12.5px; color:var(--mut); white-space:nowrap; user-select:none; padding:0 13px; border:1px solid var(--line2); border-radius:10px; background:var(--panel2); transition:border-color .14s; }
  .tgl:hover { border-color:var(--cy); }
  .tgl input { position:absolute; opacity:0; width:0; height:0; }
  .tgl .tglbox { position:relative; width:38px; height:21px; flex:0 0 auto; border-radius:99px; background:var(--hov); border:1px solid var(--line2); transition:background .18s,border-color .18s; }
  .tgl .tglbox::after { content:''; position:absolute; top:2px; left:2px; width:15px; height:15px; border-radius:50%; background:var(--mut); transition:transform .18s,background .18s; }
  .tgl input:checked + .tglbox { background:linear-gradient(135deg,rgba(34,211,238,.65),rgba(139,92,246,.65)); border-color:transparent; }
  .tgl input:checked + .tglbox::after { transform:translateX(17px); background:#fff; }
  .tgl input:checked ~ .tgltxt { color:var(--fg); }
  /* Form tabs (segmented control inside a modal). */
  .ftabs { display:flex; gap:4px; background:var(--panel2); border:1px solid var(--line); border-radius:10px; padding:4px; margin-bottom:16px; }
  .ftabs button { flex:1; background:none; border:none; color:var(--mut); padding:8px; border-radius:7px; cursor:pointer; font-size:13px; transition:background .14s,color .14s; }
  .ftabs button:hover:not(.on) { background:var(--hov); color:var(--fg); }
  .ftabs button.on { background:linear-gradient(135deg,rgba(59,130,246,.3),rgba(139,92,246,.3)); color:#fff; }
  .ftab-pane { display:none; } .ftab-pane.on { display:block; }
  /* Path-rule cards (NPM-style custom locations). */
  .locrule { border:1px solid var(--line); border-radius:11px; padding:12px; margin-bottom:10px; background:var(--panel2); }
  .locrule .lr-head { display:flex; align-items:center; gap:8px; margin-bottom:9px; }
  .locrule .lr-head .field { flex:1; }
  .locrule .lr-row { display:flex; align-items:center; gap:8px; }
  .locrule .lr-row .field.proto { flex:0 0 116px; }
  .locrule .lr-row .lr-target, .locrule .lr-row .lr-ctn { flex:1; min-width:0; }
  .locrule .lr-row .lr-ctnport { flex:0 0 96px; }
  /* Delete-rule button: subtle icon button that turns red on hover. */
  .locrule .lr-del { flex:0 0 auto; width:32px; height:32px; display:inline-flex; align-items:center; justify-content:center;
    border-radius:8px; border:1px solid var(--line); background:var(--hov); color:var(--mut); cursor:pointer; transition:color .14s,border-color .14s,background .14s; }
  .locrule .lr-del:hover { color:var(--err); border-color:rgba(251,113,133,.45); background:rgba(251,113,133,.12); }
  /* "Add path rule": centered secondary button. */
  .locadd { display:block; margin:4px auto 0; font-size:12.5px; color:var(--fg); cursor:pointer;
    background:var(--hov); border:1px solid var(--line); border-radius:9px; padding:9px 18px; transition:border-color .14s,background .14s; }
  .locadd:hover { border-color:var(--line2); background:var(--acc-soft); }
  /* Custom nginx config textarea. */
  .confbox { width:100%; resize:vertical; min-height:240px; line-height:1.55; font-size:12.5px; tab-size:2; white-space:pre; overflow-wrap:normal; overflow-x:auto; }
  /* Static-upload dropzone. */
  .dropz { border:1.5px dashed var(--line2); border-radius:12px; padding:22px; text-align:center; color:var(--mut); font-size:13px; cursor:pointer; transition:border-color .15s,background .15s; }
  .dropz:hover, .dropz.drag { border-color:var(--cy); background:var(--hov); }
  .dropz b { color:var(--cy); }
  .uplist { margin-top:10px; font-size:12px; color:var(--mut); max-height:130px; overflow-y:auto; }
  /* Searchable image picker (create-container form). */
  .imgpick { position:relative; }
  .imgpop { position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:20; max-height:240px; overflow-y:auto;
    background:var(--panel-solid); border:1px solid var(--line2); border-radius:10px; box-shadow:var(--shadow); }
  .imgopt { padding:9px 12px; font-size:13px; cursor:pointer; display:flex; align-items:center; gap:8px; font-family:ui-monospace,Menlo,Consolas,monospace; }
  .imgopt:hover { background:var(--hov); }
  .imgtag { font-size:10.5px; color:var(--mut); border:1px solid var(--line2); border-radius:99px; padding:1px 7px; }

  /* ---- Modal ---- */
  /* Anchor modals near the top so the dialog doesn't jump vertically when its
     content grows/shrinks (e.g. toggling SSL options). max-height keeps it in
     view; the inner body scrolls. */
  .mask { position:fixed; inset:0; background:rgba(4,7,13,0.62); backdrop-filter:blur(3px); z-index:50; display:flex; align-items:flex-start; justify-content:center; padding:6vh 20px 20px; }
  .filepick { display:flex; align-items:center; gap:10px; margin-top:6px; }
  .filepick .fp-name { font-size:12px; color:var(--mut); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .modal { background:var(--panel-solid); border:1px solid var(--line2); border-radius:16px; box-shadow:var(--shadow); width:760px; max-width:100%; max-height:88vh; display:flex; flex-direction:column; overflow:hidden; }
  .modal.big { width:1000px; max-height:88vh; }
  .modal-h { display:flex; align-items:center; gap:12px; padding:15px 18px; border-bottom:1px solid var(--line); }
  .modal-h h3 { margin:0; font-size:15px; flex:1; }
  .modal-b { padding:18px; overflow:auto; flex:1; }
  .x { cursor:pointer; color:var(--mut); font-size:20px; line-height:1; background:none; border:none; }

  /* ---- Toast notification (per-type accent + icon) ---- */
  .toast-wrap { position:fixed; left:50%; top:22px; transform:translateX(-50%); z-index:99; display:flex; flex-direction:column; align-items:center; gap:10px; pointer-events:none; }
  .toast { display:flex; align-items:center; gap:10px; pointer-events:auto;
    max-width:min(460px,92vw); padding:11px 16px; border-radius:12px; font-size:13px; line-height:1.45;
    background:var(--panel-solid); border:1px solid var(--line2); color:var(--fg); box-shadow:var(--shadow); animation:toastIn .2s ease; }
  .toast .ti { width:18px; height:18px; flex:0 0 auto; }
  .toast .tx { min-width:0; word-break:break-word; }
  .toast.ok { border-color:rgba(52,211,153,.5); } .toast.ok .ti { color:var(--ok); }
  .toast.err { border-color:rgba(251,113,133,.5); } .toast.err .ti { color:var(--err); }
  .toast.warn { border-color:rgba(251,191,36,.5); } .toast.warn .ti { color:var(--warn); }
  .toast.info { border-color:rgba(59,130,246,.5); } .toast.info .ti { color:var(--br); }
  @keyframes toastIn { from { opacity:0; transform:translateY(-8px); } to { opacity:1; transform:translateY(0); } }

  /* ---- Terminal ---- */
  .term-page { display:flex; flex-direction:column; flex:1 1 auto; min-height:0; width:100%; padding:18px 24px; box-sizing:border-box; }
  .term-wrap { background:#05080f; border:1px solid var(--line2); border-radius:12px; overflow:hidden; display:flex; flex-direction:column; }
  .term-bar { display:flex; align-items:center; gap:10px; padding:8px 12px; background:rgba(255,255,255,0.03); border-bottom:1px solid var(--line); font-size:12px; color:var(--mut); }
  .term-bar .sp { flex:1; }
  .term-bar .term-x { background:none; border:none; color:var(--mut); font-size:20px; line-height:1; cursor:pointer; padding:0 4px; transition:color .15s; }
  .term-bar .term-x:hover { color:var(--err); }
  /* Container-terminal modal: a centered panel over a dark backdrop (reuses the
     .mask for the dimmed/blurred background). Sized to a comfortable terminal,
     not full-viewport. */
  .term-mask { z-index:60; align-items:center; padding:20px; }
  .term-overlay { position:relative; width:min(900px,94vw); height:min(560px,82vh); box-shadow:var(--shadow); border-radius:12px; }
  .term-overlay .term-wrap { height:100%; }
  @media (max-width:720px){ .term-overlay { width:96vw; height:86vh; } }
  .vterm { font-family:ui-monospace,Menlo,Consolas,monospace; font-size:13px; line-height:1.3; padding:10px 12px; color:#cfe3ff; background:#05080f;
    white-space:pre; overflow-y:auto; overflow-x:hidden; outline:none; cursor:text; flex:1; min-height:200px; }
  .vterm .cur { background:#cfe3ff; color:#05080f; }
  .vterm:focus { box-shadow:inset 0 0 0 1px rgba(34,211,238,0.4); }
  /* ---- File browser ---- */
  .files-page { display:flex; flex-direction:column; flex:1 1 auto; min-height:0; width:100%; padding:18px 24px; box-sizing:border-box; }
  .files-page .fb-scroll { flex:1 1 auto; min-height:0; overflow-y:auto; }
  /* Sticky toolbar: bordered breadcrumb path bar + action buttons. */
  .fb-toolbar { display:flex; align-items:center; gap:10px; margin-bottom:12px; flex:0 0 auto; }
  /* Container file-manager modal: give the browser its own internal scroll so
     the toolbar is a fixed flex item (the list scrolls beneath it) — relying on
     the modal body's own scroll left a gap above a sticky toolbar where rows
     showed through. */
  .modal-b > #fbModal { display:flex; flex-direction:column; height:72vh; min-height:0; }
  .modal-b > #fbModal .fb-toolbar { position:static; }
  .modal-b > #fbModal .fb-scroll { flex:1 1 auto; min-height:0; overflow-y:auto; }
  .fb-pathbar { flex:1; min-width:0; display:flex; align-items:center; gap:4px; flex-wrap:nowrap; overflow-x:auto; white-space:nowrap;
    font-size:12.5px; padding:7px 12px; background:var(--panel2); border:1px solid var(--line); border-radius:10px; }
  .fb-pathbar .seg2 { cursor:pointer; color:var(--cy); padding:1px 2px; border-radius:5px; }
  .fb-pathbar .seg2:hover { background:var(--hov); }
  .fb-pathbar .sepc { color:var(--mut); opacity:.6; }
  /* Borderless, lightly-zebra list (no outer box). */
  .fb-list { border-radius:10px; }
  .fb-row { display:flex; align-items:center; gap:11px; padding:10px 12px; border-radius:8px; cursor:default; }
  .fb-row:hover { background:var(--hov); }
  .fb-row .fbic { width:18px; flex:0 0 auto; text-align:center; opacity:.9; }
  .fb-row .nm { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .fb-row .nm.dir { color:var(--cy); cursor:pointer; }
  .fb-row .sz { color:var(--mut); font-size:12px; font-variant-numeric:tabular-nums; }
  /* ---- Progress job ---- */
  .prog { height:9px; border-radius:99px; background:var(--hov); overflow:hidden; position:relative; }
  .prog > i { display:block; height:100%; border-radius:99px; background:linear-gradient(90deg,var(--cy),var(--vio)); width:0; transition:width .4s; }
  .prog.indet > i { width:38%; animation:indet 1.25s ease-in-out infinite; }
  @keyframes indet { 0%{margin-left:-40%;} 100%{margin-left:100%;} }
  .prog.done > i { width:100%!important; animation:none; }
  .prog.err > i { width:100%!important; animation:none; background:var(--err); }
  .job-line { font-size:13px; margin:12px 0 4px; min-height:18px; }
  .job-log { margin-top:8px; }
  .job-log summary { cursor:pointer; font-size:12px; color:var(--mut); list-style:none; }
  .job-log summary::-webkit-details-marker { display:none; }
  .job-log summary::before { content:'▸ '; }
  .job-log[open] summary::before { content:'▾ '; }

/* ---- Software-update modal (macOS/iOS "Software Update" aesthetic) ---- */
.upd { display:flex; flex-direction:column; }
.upd-hero { text-align:center; padding:4px 0 2px; }
.upd-appicon { width:64px; height:64px; border-radius:17px; margin:0 auto; display:flex; align-items:center; justify-content:center;
  background:linear-gradient(135deg,var(--cy),var(--vio)); box-shadow:var(--glow), inset 0 1px 0 rgba(255,255,255,0.25); }
.upd-appicon svg { width:33px; height:33px; }
.upd-ver { font-size:22px; font-weight:680; letter-spacing:.3px; margin-top:15px; }
.upd-state { font-size:13.5px; color:var(--mut); margin-top:6px; min-height:19px; display:flex; align-items:center; justify-content:center; gap:6px; }
.upd-state svg { width:16px; height:16px; }
.upd-state.avail { color:var(--fg); font-weight:550; }
.upd-state.ok { color:var(--ok); }
.upd-state.err { color:var(--err); }
.upd-cta { margin-top:17px; }
.upd-cta:empty { margin-top:0; }
.upd-cta .btn { padding:10px 26px; border-radius:99px; font-size:14px; box-shadow:0 6px 18px rgba(59,130,246,0.3); }
.upd-recheck { margin-top:13px; background:none; border:none; color:var(--br); font-size:12.5px; cursor:pointer; padding:4px 8px; border-radius:7px; }
.upd-recheck:hover { background:var(--hov); }
.upd-prog { margin:20px auto 0; width:52%; min-width:300px; text-align:left; }

/* Inset grouped lists (sources / settings / changelog). */
.upd-sec { margin-top:22px; }
.upd-sec-h { font-size:11.5px; color:var(--mut); font-weight:600; letter-spacing:.5px; text-transform:uppercase; margin:0 0 8px 14px; }
.upd-group { background:var(--panel2); border:1px solid var(--line); border-radius:14px; overflow:hidden; }
.upd-row { display:flex; align-items:center; gap:12px; padding:13px 15px; }
.upd-row + .upd-row { border-top:1px solid var(--line); }
.upd-row-t { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.upd-row-t b { font-size:13.5px; font-weight:550; }
.upd-row-t > span { font-size:11.5px; color:var(--mut); line-height:1.5; }
.upd-row .field { width:auto; }

/* Changelog ("What's new") rendered inside an inset group. */
.upd-cl .cl-entry { padding:13px 15px; }
.upd-cl .cl-entry + .cl-entry, .upd-cl #uClMore .cl-entry { border-top:1px solid var(--line); }
.upd-cl #uClMore .cl-entry:first-child { border-top:1px solid var(--line); }
.upd-cl .cl-ver { display:flex; align-items:center; gap:8px; font-size:12.5px; font-weight:650; color:var(--cy); }
.upd-cl .cl-cur { font-size:10.5px; font-weight:600; color:var(--ok); border:1px solid rgba(52,211,153,.4); background:rgba(52,211,153,.10); border-radius:99px; padding:1px 8px; }
.upd-cl .cl-date { margin-left:auto; font-size:11px; font-weight:400; color:var(--mut); }
.upd-cl .cl-notes { margin:6px 0 0; padding-left:18px; }
.upd-cl .cl-notes li { font-size:12.5px; line-height:1.7; color:var(--mut); }
.upd-cl .cl-toggle { width:100%; text-align:center; background:none; border:none; border-top:1px solid var(--line); padding:11px; cursor:pointer; color:var(--br); font-size:12.5px; }
.upd-cl .cl-toggle:hover { background:var(--hov); }

/* ---- Spacing between action buttons in table action cells ---- */
.optable td.act { white-space: nowrap; }
.optable td.act .btn + .btn { margin-left: 8px; }
.optable td.act .actions { display: inline-flex; gap: 8px; flex-wrap: wrap; align-items: center; min-height: 30px; }
/* Inside a flex `.actions` the gap already spaces buttons — cancel the
   adjacent-button margin so it isn't doubled (matches Website/Files spacing). */
.optable td.act .actions .btn + .btn { margin-left: 0; }

/* ---- Audit log table: fixed column widths so columns don't jump per page ---- */
.optable.logtbl { table-layout: fixed; width: 100%; }
.optable.logtbl td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.optable.logtbl td.act { overflow: visible; }

/* ---- Inline note (e.g. SSL auto-renew hint) ---- */
.formnote { font-size: 12px; color: var(--mut); margin-top: 8px; line-height: 1.5; }

/* ---- Site SSL tab (cert method + toggles) ---- */
.segbtns { display:inline-flex; border:1px solid var(--line2); border-radius:9px; overflow:hidden; margin-top:6px; }
.segbtns button { appearance:none; border:0; background:transparent; color:var(--mut); padding:8px 18px; font-size:13px; cursor:pointer; border-right:1px solid var(--line); transition:background .12s,color .12s; }
.segbtns button:last-child { border-right:0; }
.segbtns button.on { background:var(--acc-soft); color:var(--fg); font-weight:600; }
.certlist { display:flex; flex-direction:column; gap:8px; }
.certopt { display:flex; align-items:flex-start; gap:11px; padding:10px 12px; border:1px solid var(--line); border-radius:9px; cursor:pointer; transition:border-color .12s, background .12s; }
.certopt:hover { border-color:var(--line2); }
.certopt.sel { border-color:var(--br); background:var(--acc-soft); }
.certopt .ck { flex:0 0 16px; width:16px; height:16px; margin-top:2px; border-radius:50%; border:2px solid var(--line2); position:relative; }
.certopt.sel .ck { border-color:var(--br); }
.certopt.sel .ck::after { content:''; position:absolute; inset:3px; border-radius:50%; background:var(--br); }
.certopt .ci { display:flex; flex-direction:column; gap:2px; min-width:0; }
.certopt .ci b { font-size:13px; }
.certopt .ci .mut { font-size:11.5px; }
.ssltoggles { display:grid; grid-template-columns:1fr 1fr; gap:0 20px; padding:4px 14px; border:1px solid var(--line); border-radius:10px; background:var(--panel2); }
.ssltoggles .switch { align-items:flex-start; }
@media (max-width:560px){ .ssltoggles { grid-template-columns:1fr; } }

/* MySQL database browser */
.linklike { background:none; border:none; padding:0; color:var(--acc); cursor:pointer; font:inherit; font-weight:550; }
.linklike:hover { text-decoration:underline; }
.mycrumb { display:flex; align-items:center; gap:8px; font-size:13px; margin:2px 0 4px; }
.mycrumb-sep { color:var(--mut); }
.mycrumb-link { background:none; border:none; padding:0; color:var(--acc); cursor:pointer; font:inherit; }
.mycrumb-link:hover { text-decoration:underline; }
.mycrumb-cur { color:var(--fg); font-weight:600; }
.tablescroll { max-height:460px; overflow:auto; border:1px solid var(--line); border-radius:10px; }
.tablescroll table.datatbl { margin:0; border:none; }
table.datatbl th { position:sticky; top:0; background:var(--panel2); z-index:1; white-space:nowrap; }
table.datatbl td { max-width:320px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:12.5px; }
table.kvtbl th { text-align:left; color:var(--mut); font-weight:500; }

/* In-field password generate button (sits left of the eye) */
.pwf.gen .field { padding-right:66px; }
.pwf-gen { position:absolute; right:34px; top:50%; transform:translateY(-50%); width:26px; height:28px; display:flex; align-items:center; justify-content:center; border:none; background:none; color:var(--mut); cursor:pointer; border-radius:6px; }
.pwf-gen:hover { color:var(--fg); background:var(--hov); }
/* Connection-info password row: inline reveal toggle aligned with the value */
.pwline { display:inline-flex; align-items:center; gap:8px; line-height:1; }
.kveye { display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; border:none; background:none; color:var(--mut); cursor:pointer; border-radius:6px; }
.kveye:hover { color:var(--fg); background:var(--hov); }

/* Host directory picker (static site "existing directory" source) */
.dpitem { display:block; width:100%; text-align:left; background:none; border:none; border-bottom:1px solid var(--line); color:var(--fg); padding:9px 10px; cursor:pointer; font-size:13px; }
.dpitem:hover { background:var(--hov); }

/* ---- Hover action menu (container status controls + Advanced menu) ----
   Body-anchored (position:fixed) so it isn't clipped by the scrollable table
   wrapper. Rendered as a clean dropdown menu (not a stack of buttons). */
.dk-pop { position: fixed; z-index: 200; display: none; flex-direction: column; gap: 1px;
  background: var(--panel-solid); border: 1px solid var(--line2); border-radius: 11px;
  padding: 5px; box-shadow: 0 14px 38px rgba(0,0,0,.42); min-width: 156px; }
.dk-pop .mi { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  background: none; border: none; color: var(--fg); font-size: 13px; line-height: 1;
  padding: 9px 12px; border-radius: 7px; cursor: pointer; transition: background .12s, color .12s; }
.dk-pop .mi:hover { background: var(--hov); color: var(--cy); }
.dk-pop .mi.danger { color: var(--err); }
.dk-pop .mi.danger:hover { background: rgba(248,113,113,.12); color: var(--err); }
.dk-pop .mi-sep { height: 1px; background: var(--line); margin: 5px 8px; }
.statuswrap { display: inline-flex; align-items: center; gap: 5px; }
.statuswrap .c-caret { font-size: 9px; color: var(--mut); transition: color .12s; }
.statuswrap:hover .c-caret { color: var(--cy); }

/* ---- Frozen-column tables (container + image lists): pinned first column
   (left) + Actions column (right); the middle scrolls horizontally; every cell
   clamps to 2 lines. Shared base; each table sets its own min-width. ---- */
.frztbl { border-collapse: separate; border-spacing: 0; table-layout: fixed; width: 100%; }
.frztbl th, .frztbl td { background: var(--bg); vertical-align: middle; }
.frztbl th:first-child, .frztbl td:first-child { position: sticky; left: 0; z-index: 2; }
.frztbl th.act, .frztbl td.act { position: sticky; right: 0; z-index: 2; }
.frztbl td.act .actions { flex-wrap: wrap; }
.frztbl tr:first-child th:first-child, .frztbl tr:first-child th.act { z-index: 3; }
table.ctntbl { min-width: 1480px; }
table.imgtbl { min-width: 1080px; }
table.voltbl { min-width: 980px; }
table.voltbl th.act, table.voltbl td.act { width: 160px; }
/* Fixed row heights so lists read as tidy uniform rows. */
table.ctntbl td, table.voltbl td { height: 65px; }
table.imgtbl td { height: 55px; }
table.nettbl td { height: 55px; }
table.nettbl td .clamp1 { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; word-break: break-all; }
/* Scroll-aware frozen-column shadows: a full-height ::after/::before per sticky
   cell (so the strip is continuous across rows, with no per-cell banding) shown
   only when there is scrolled-away content on that side. */
.tablewrap.scl .frztbl th:first-child::after, .tablewrap.scl .frztbl td:first-child::after {
  content: ''; position: absolute; top: 0; bottom: -1px; right: 0; width: 14px; transform: translateX(100%);
  background: linear-gradient(to right, rgba(0,0,0,.16), transparent); pointer-events: none; }
.tablewrap.scr .frztbl th.act::before, .tablewrap.scr .frztbl td.act::before {
  content: ''; position: absolute; top: 0; bottom: -1px; left: 0; width: 14px; transform: translateX(-100%);
  background: linear-gradient(to left, rgba(0,0,0,.16), transparent); pointer-events: none; }
/* Frozen columns must stay opaque on row hover — a translucent hover tint would
   let the horizontally-scrolled middle content bleed through. Layer the hover
   colour over the solid base so the highlight shows without any see-through. */
.frztbl tr:hover td:first-child, .frztbl tr:hover td.act {
  background: linear-gradient(var(--hov), var(--hov)), var(--bg); }
/* Clamp any cell content to 1 or 2 lines (ellipsis); full text on hover (title). */
.clamp1, .clamp2 { display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; word-break: break-all; }
.clamp1 { -webkit-line-clamp: 1; }
.clamp2 { -webkit-line-clamp: 2; }
.portlbl { display: inline-block; font-size: 11px; color: var(--mut); border: 1px solid var(--line2);
  border-radius: 6px; padding: 1px 7px; margin: 1px 4px 1px 0; white-space: nowrap; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
/* Image name shown as a label/chip (clamped to 2 lines by its wrapping cell). */
.imgtag { display: inline-block; max-width: 100%; font-size: 11.5px; color: var(--fg); background: var(--hov); border: 1px solid var(--line2);
  border-radius: 6px; padding: 2px 8px; margin: 0 5px 4px 0; white-space: normal; word-break: break-all; vertical-align: top; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
/* Tag-input (image tagging modal): chips + an inline text input in one field. */
.tagchips { display: flex; flex-wrap: wrap; gap: 6px; }
.taginput { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; min-height: 42px; padding: 7px 10px; background: var(--panel2); border: 1px solid var(--line); border-radius: 10px; cursor: text; }
.taginput:focus-within { border-color: var(--cy); box-shadow: 0 0 0 3px var(--acc-soft); }
.taginput input { flex: 1; min-width: 140px; border: none; background: none; color: var(--fg); outline: none; font: inherit; padding: 2px 0; }
.tagchip { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; background: var(--hov); border: 1px solid var(--line2); border-radius: 7px; padding: 3px 4px 3px 9px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.tagchip button { border: none; background: none; color: var(--mut); cursor: pointer; font-size: 14px; line-height: 1; padding: 0 3px; border-radius: 5px; }
.tagchip button:hover { color: var(--err); }
/* File drop / picker (image import modal). */
.filedrop { display: flex; align-items: center; gap: 14px; padding: 18px 16px; border: 1.5px dashed var(--line2); border-radius: 12px; background: var(--panel2); cursor: pointer; transition: border-color .15s, background .15s; }
.filedrop:hover { border-color: var(--cy); }
.filedrop.has { border-style: solid; border-color: var(--cy); }
.filedrop input[type=file] { display: none; }
.filedrop .fd-ic { width: 42px; height: 42px; flex: 0 0 auto; display: flex; align-items: center; justify-content: center; border-radius: 11px; background: var(--hov); color: var(--cy); }
.filedrop .fd-ic svg { width: 22px; height: 22px; }
.filedrop .fd-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.filedrop .fd-main b { font-size: 13px; word-break: break-all; }
.filedrop .fd-sub { font-size: 11.5px; color: var(--mut); }
/* Pull-tasks modal: a list of running/finished image pulls. */
.pt-row { padding: 11px 2px; border-bottom: 1px solid var(--line); }
.pt-row:last-child { border-bottom: none; }
.pt-top { display: flex; align-items: center; gap: 10px; }
.pt-top b { font-size: 12.5px; word-break: break-all; }
.pt-line { margin-top: 6px; word-break: break-all; }
.pt-x { width: 24px; height: 24px; flex: 0 0 auto; border: 1px solid var(--line); background: var(--hov); color: var(--mut); border-radius: 7px; cursor: pointer; font-size: 15px; line-height: 1; }
.pt-x:hover { color: var(--err); border-color: var(--err); }

/* ---- Container monitor modal: a clean 2×2 stat-card grid. ---- */
.mongrid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 560px) { .mongrid { grid-template-columns: 1fr; } }
.moncard { background: var(--panel2); border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px; }
.moncard .mon-k { font-size: 11.5px; color: var(--mut); letter-spacing: .05em; text-transform: uppercase; }
.moncard .mon-big { font-size: 28px; font-weight: 650; line-height: 1; margin: 10px 0 4px; }
.moncard .mon-unit { font-size: 14px; color: var(--mut); font-weight: 500; margin-left: 3px; }
.moncard .mon-pct { font-size: 14px; color: var(--mut); font-weight: 500; margin-left: 10px; }
.moncard .mon-sub { font-size: 12px; color: var(--mut); }
.mon-bar { height: 8px; border-radius: 6px; background: var(--line); overflow: hidden; margin-top: 12px; }
.mon-bar > i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--cy), var(--br)); transition: width .5s ease; }
.mon-bar.warn > i { background: linear-gradient(90deg, var(--warn), var(--err)); }
.mon-duo { display: flex; gap: 10px; margin-top: 14px; }
.mon-duo > div { flex: 1; background: var(--panel-solid); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; }
.mon-duo .mon-io-k { font-size: 11.5px; color: var(--mut); display: flex; align-items: center; gap: 5px; margin-bottom: 4px; }
.mon-duo .mon-io-v { font-size: 17px; font-weight: 600; }
.mon-arrow { font-weight: 700; }
.mon-arrow.dn { color: var(--ok); }
.mon-arrow.up { color: var(--cy); }

/* ---- Custom hover tooltip (clamped table cells: name/image/ports/desc). ---- */
.dk-tip { position: fixed; z-index: 300; display: none; max-width: 380px;
  background: var(--panel-solid); color: var(--fg); border: 1px solid var(--line2);
  border-radius: 9px; padding: 8px 11px; font-size: 12px; line-height: 1.5;
  box-shadow: 0 10px 30px rgba(0,0,0,.42); white-space: pre-wrap; word-break: break-all; pointer-events: none; }
