
:root{
--bg:#ffffff;--surface:#f6f9f7;--text:#16211b;--k800:#17303a;--k900:#0e212a;
--p100:#eaf7ee;--p200:#cdebd6;--p300:#a3dab5;--p400:#6bc189;--p500:#3faa64;--p600:#2e9e4f;--p700:#227a3c;--p800:#1a5c2e;--p900:#123f20;
--g100:#e6f6f7;--g200:#c3e9ec;--g300:#8fd6dc;--g400:#4dbac4;--g500:#1e9aa6;--g600:#0e7c86;--g700:#0a616a;--g800:#084a51;--g900:#06343a;
--n100:#fafbfa;--n200:#f1f4f2;--n300:#e2e8e4;--n400:#c6d0c9;--n500:#9daaa2;--n600:#74827a;--n700:#55625b;--n800:#3a443e;--n900:#232a26;
--accent:var(--p600);--accent2:var(--g600);--div:#e2e8e4;
--sm:0 1px 2px rgba(18,63,32,.08);--md:0 4px 14px rgba(18,63,32,.10);--lg:0 16px 40px rgba(14,33,42,.14);
--fh:"Caprasimo",Georgia,serif;--fb:"Figtree",system-ui,-apple-system,sans-serif;
--r:16px;--rl:28px;
}
*{box-sizing:border-box}
body{margin:0;background:var(--n200);color:var(--text);font-family:var(--fb);font-size:15px;line-height:1.55;-webkit-font-smoothing:antialiased}
a{color:var(--p700)}
h1,h2,h3,h4{font-family:var(--fh);font-weight:400;letter-spacing:-.02em;margin:0 0 .5em;line-height:1.15}
h1{font-size:30px}h2{font-size:22px}h3{font-size:18px}
:focus{outline:none}:focus-visible{outline:2px solid var(--p500);outline-offset:2px}
.shell{display:grid;grid-template-columns:248px 1fr;min-height:100vh}
aside{background:linear-gradient(180deg,#0e212a,#123f20);color:var(--p200);padding:20px 0;position:sticky;top:0;height:100vh;overflow-y:auto}
aside .lg{display:flex;align-items:center;gap:10px;padding:0 20px 20px;font-family:var(--fh);font-size:20px;color:#fff;text-decoration:none}
aside .lg i{width:32px;height:32px;border-radius:10px;background:rgba(255,255,255,.16);display:grid;place-items:center}
aside h6{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--p400);padding:16px 20px 6px;margin:0}
aside a.nv{display:flex;align-items:center;gap:10px;padding:9px 20px;color:var(--p200);text-decoration:none;font-size:14.5px;border-left:3px solid transparent}
aside a.nv:hover{background:rgba(255,255,255,.08);color:#fff}
aside a.nv.on{background:rgba(255,255,255,.14);color:#fff;border-left-color:var(--g400)}
aside a.nv .bdg{margin-left:auto;background:var(--g500);color:#06301f;border-radius:99px;font-size:11px;padding:1px 7px}
main.body{padding:0 0 60px;min-width:0}
.top{background:#fff;border-bottom:1px solid var(--div);padding:16px 30px;display:flex;align-items:center;gap:16px;position:sticky;top:0;z-index:20}
.top .who{margin-left:auto;display:flex;align-items:center;gap:12px;font-size:14px;color:var(--n700)}
.pad{padding:28px 30px;max-width:1280px}
.card{background:#fff;border:1px solid var(--div);border-radius:var(--r);padding:22px}
.card.p0{padding:0;overflow:hidden}
.grid{display:grid;gap:18px}
.g2{grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.kpi{background:#fff;border:1px solid var(--div);border-radius:var(--r);padding:18px 20px}
.kpi b{display:block;font-family:var(--fh);font-weight:400;font-size:32px;color:var(--p800);line-height:1.1}
.kpi span{font-size:13px;color:var(--n600);text-transform:uppercase;letter-spacing:.06em}
.kpi em{font-style:normal;font-size:12.5px;color:var(--g700)}
.kpi em.dn{color:#b4453a}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;cursor:pointer;text-decoration:none;font-family:var(--fb);font-weight:600;font-size:14px;padding:9px 16px;border-radius:10px;border:1px solid transparent;background:var(--n200);color:var(--text);transition:background .13s}
.btn:hover{background:var(--n300)}
.btn.pri{background:var(--p600);color:#fff}.btn.pri:hover{background:var(--p700)}
.btn.grn{background:var(--p600);color:#fff}.btn.grn:hover{background:var(--p700)}
.btn.amb{background:var(--g600);color:#fff}.btn.amb:hover{background:var(--g500)}
.btn.out{background:#fff;border-color:var(--n400)}.btn.out:hover{background:var(--p100);border-color:var(--p300)}
.btn.dgr{background:#fdecea;color:#a03227}.btn.dgr:hover{background:#f8d7d3}
.btn.sm{padding:6px 11px;font-size:13px;border-radius:8px}
.btn[disabled]{opacity:.45;pointer-events:none}
label{display:block;font-size:13px;font-weight:600;color:var(--n700);margin-bottom:5px}
input[type=text],input[type=email],input[type=password],input[type=number],input[type=url],select,textarea{width:100%;font-family:var(--fb);font-size:14.5px;padding:10px 13px;border:1px solid var(--n400);border-radius:10px;background:#fff;color:var(--text)}
textarea{min-height:120px;resize:vertical}
textarea.code{font-family:ui-monospace,"SFMono-Regular",Menlo,monospace;font-size:13px;line-height:1.5;min-height:420px;white-space:pre;overflow-wrap:normal;overflow-x:auto}
.fld{margin-bottom:16px}
.fld .hint{font-size:12.5px;color:var(--n600);margin-top:4px;font-weight:400}
.row2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
table.tbl{width:100%;border-collapse:collapse;font-size:14px;background:#fff}
table.tbl th{text-align:left;padding:11px 16px;background:var(--n100);border-bottom:1px solid var(--div);font-weight:600;font-size:12.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--n700)}
table.tbl td{padding:12px 16px;border-bottom:1px solid var(--div);vertical-align:middle}
table.tbl tr:hover td{background:var(--n100)}
.pill{display:inline-block;font-size:12px;font-weight:600;padding:3px 10px;border-radius:99px;background:var(--n200);color:var(--n700)}
.pill.ok{background:var(--g200);color:var(--g800)}
.pill.tri{background:var(--p200);color:var(--p800)}
.pill.warn{background:#fdf0d5;color:#8a5a00}
.pill.bad{background:#fdecea;color:#a03227}
.msg{border-radius:10px;padding:12px 16px;margin-bottom:18px;font-size:14px}
.msg.ok{background:var(--g100);border:1px solid var(--g300);color:var(--g900)}
.msg.err{background:#fdecea;border:1px solid #f2b8b1;color:#8c2b21}
.msg.inf{background:var(--p100);border:1px solid var(--p300);color:var(--p900)}
.bar{height:8px;border-radius:99px;background:var(--n300);overflow:hidden}
.bar i{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--p500),var(--g500));border-radius:99px;transition:width .35s cubic-bezier(.4,0,.2,1)}
.bar.lg{height:14px}
.inst{border:1px solid var(--div);border-radius:12px;padding:14px 16px;margin-bottom:10px;background:#fff;display:grid;grid-template-columns:auto minmax(190px,1fr) minmax(0,auto);gap:14px;align-items:center}
.inst>div{min-width:0}
.inst>.ds{max-width:46%;justify-self:end;text-align:right;overflow-wrap:anywhere}
.inst.fail>.ds{color:#a8382c}
.inst .st{width:26px;height:26px;border-radius:50%;background:var(--n200);display:grid;place-items:center;font-size:13px;color:var(--n600);flex:0 0 auto}
.inst.run .st{background:var(--p200);color:var(--p800)}
.inst.done .st{background:var(--g500);color:#fff}
.inst.fail .st{background:#e8574a;color:#fff}
.inst .nm{font-weight:600}
.inst .ds{font-size:12.5px;color:var(--n600)}
.inst .bar{margin-top:7px}
.sp{display:inline-block;width:13px;height:13px;border:2px solid var(--p300);border-top-color:var(--p700);border-radius:50%;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.chart{display:flex;align-items:flex-end;gap:5px;height:150px}
.chart div{flex:1;background:linear-gradient(180deg,var(--p400),var(--p600));border-radius:5px 5px 0 0;min-height:3px;position:relative}
.chart div:hover{background:linear-gradient(180deg,var(--g400),var(--g600))}
.chart div span{position:absolute;bottom:-20px;left:0;right:0;text-align:center;font-size:10px;color:var(--n600)}
.hbar{display:grid;grid-template-columns:170px 1fr 62px;gap:12px;align-items:center;margin-bottom:9px;font-size:13.5px}
.hbar .t{height:20px;border-radius:5px;background:linear-gradient(90deg,var(--p500),var(--p700))}
.hbar .t.g{background:linear-gradient(90deg,var(--g500),var(--g700))}
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--div);margin-bottom:22px;flex-wrap:wrap}
.tabs a{padding:10px 16px;font-size:14px;font-weight:600;color:var(--n700);text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px}
.tabs a:hover{color:var(--p700)}
.tabs a.on{color:var(--p800);border-bottom-color:var(--p600)}
.login{min-height:100vh;display:grid;place-items:center;background:linear-gradient(135deg,#0e212a,#1a5c2e 60%,#227a3c)}
.login .box{background:#fff;border-radius:20px;padding:36px;width:400px;max-width:92vw;box-shadow:var(--lg)}
.emp{text-align:center;padding:54px 20px;color:var(--n600)}
.emp b{display:block;font-family:var(--fh);font-weight:400;font-size:20px;color:var(--n700);margin-bottom:6px}
code{font-family:ui-monospace,Menlo,monospace;font-size:12.5px;background:var(--n200);padding:2px 6px;border-radius:5px}
.split{display:grid;grid-template-columns:1fr 380px;gap:20px;align-items:start}
@media(max-width:1100px){.shell{grid-template-columns:1fr}aside{position:static;height:auto}.split{grid-template-columns:1fr}}

/* green-build additions */
aside a.nv.on{border-left-color:#6bc189}
aside a.nv .bdg{background:#6bc189;color:#0e212a}
.kpi b{color:var(--p800)}
.bar i{background:linear-gradient(90deg,var(--p500),var(--p700))}
.chart div{background:linear-gradient(180deg,var(--p400),var(--p600))}
.chart div:hover{background:linear-gradient(180deg,var(--g400),var(--g600))}
.hbar .t{background:linear-gradient(90deg,var(--p500),var(--p700))}
.hbar .t.g{background:linear-gradient(90deg,#4e6b72,#17303a)}
.pill.ok{background:var(--p200);color:var(--p800)}
.pill.tri{background:#d7e0e2;color:#17303a}
.pill.warn{background:var(--g200);color:var(--g800)}
.sp{border-color:var(--p300);border-top-color:var(--p700)}
.msg.ok{background:var(--p100);border-color:var(--p300);color:var(--p900)}
.msg.inf{background:#eef2f3;border-color:#b0c1c5;color:#0e212a}
th{background:var(--n100)}
.tabs a.on{color:var(--p800);border-bottom-color:var(--p600)}
@media(max-width:760px){.pad{padding:18px 14px}.top{padding:12px 14px}.split{grid-template-columns:1fr}
.row2{grid-template-columns:1fr}table.tbl{font-size:13px}table.tbl th,table.tbl td{padding:9px 10px}}

/* --- Shared blocks used across the module screens ------------------------- */
/* .msg has ok/err/inf; warn and bad are the names the module screens use. */
.msg.warn{background:#fdf0d5;border:1px solid #f0d9a4;color:#7a4f00}
.msg.bad{background:#fdecea;border:1px solid #f2b8b1;color:#8c2b21}
.msg code{background:rgba(0,0,0,.06);padding:1px 5px;border-radius:4px;font-size:12.5px}
/* A status message clears itself three seconds after the page settles — see
   clearMessages() in admin.js, which owns which messages go and which stay.
   The geometry is animated as well as the opacity so the content below it moves
   up smoothly rather than jumping when the node is removed. */
.msg{transition:opacity .38s ease,transform .38s ease,margin-bottom .38s ease,max-height .38s ease;max-height:40vh}
.msg-going{opacity:0;transform:translateY(-6px);margin-bottom:0;max-height:0;padding-top:0;padding-bottom:0;border-width:0;overflow:hidden}
@media (prefers-reduced-motion:reduce){.msg{transition:none}.msg-going{display:none}}

/* Four-up figure row. Same shape as .kpi, laid out for itself. */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:22px}
.stat{background:#fff;border:1px solid var(--div);border-radius:var(--r);padding:17px 19px}
.stat span{display:block;font-size:12px;color:var(--n600);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px}
.stat strong{display:block;font-family:var(--fh);font-weight:400;font-size:31px;line-height:1.05;color:var(--p800)}
.stat em{font-style:normal;font-size:12.5px;color:var(--n600)}

.two{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:18px}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}
.grid3{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:16px}

/* Label/value pairs — an account summary, a purchase summary. */
.kv{display:grid;gap:1px;background:var(--div);border:1px solid var(--div);border-radius:12px;overflow:hidden}
.kv>div{display:flex;justify-content:space-between;gap:14px;align-items:baseline;background:#fff;padding:11px 14px;font-size:13.5px}
.kv>div span{color:var(--n600)}
.kv>div b{text-align:right;overflow-wrap:anywhere}

/* Radio cards — one choice per row, with the reason under the label. */
.radios{display:grid;gap:10px}
.radio{display:flex;gap:11px;align-items:flex-start;border:1px solid var(--n400);border-radius:12px;padding:13px 15px;cursor:pointer;background:#fff;font-weight:400;margin:0}
.radio:hover{border-color:var(--p400);background:var(--p100)}
.radio.on{border-color:var(--p600);background:var(--p100);box-shadow:0 0 0 1px var(--p600) inset}
.radio input{width:auto;margin-top:2px;flex:0 0 auto}
.radio span{display:block;min-width:0}
.radio strong{display:block;font-size:14px;color:var(--n900)}
.radio em{font-style:normal;display:block;font-size:12.5px;color:var(--n600);line-height:1.5;margin-top:3px}

/* The list of machine-readable files, each a link out. */
.filelist{display:grid;gap:8px;margin-top:12px}
.filelist a{display:flex;gap:12px;align-items:baseline;flex-wrap:wrap;padding:10px 13px;border:1px solid var(--div);border-radius:10px;text-decoration:none;background:#fff}
.filelist a:hover{border-color:var(--p400);background:var(--p100)}
.filelist code{font-size:13px;color:var(--p700);font-weight:600}
.filelist span{font-size:12.5px;color:var(--n600)}

/* --- Module library: a file browser over what is on the server ------------ */
.fbrowse{border:1px solid var(--div);border-radius:12px;overflow:hidden;background:var(--n100)}
.fbhead{display:grid;grid-template-columns:auto 1fr 70px 1fr 80px;gap:14px;align-items:center;padding:9px 16px;
  background:var(--n200);border-bottom:1px solid var(--div);font-size:11.5px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;color:var(--n700)}
.fbhead label{margin:0}
.fbhead input{width:auto}
.fbhead .fbf{text-align:left}
@media(max-width:900px){.fbhead{display:none}}
.fbrow{border:0;border-bottom:1px solid var(--div);border-radius:0;margin:0;background:#fff}
.fbrow:last-child{border-bottom:0}
.fbrow.off{opacity:.72;background:var(--n100)}
.fbrow.off .st{background:var(--n300);color:var(--n700)}
.fbfiles{margin:7px 0 9px}
.fbfiles summary{font-size:12.5px;color:var(--p700);cursor:pointer;font-weight:600;list-style:none}
.fbfiles summary::-webkit-details-marker{display:none}
.fbfiles summary::before{content:"▸ ";font-size:10px}
.fbfiles[open] summary::before{content:"▾ "}
.fbfiles code{display:block;margin:5px 0 0;font-size:11.5px;background:var(--n100);border:1px solid var(--div);
  padding:3px 8px;border-radius:5px;width:fit-content;max-width:100%;overflow-wrap:anywhere}
.fbfiles code.miss{background:#fdecea;border-color:#f2b8b1;color:#8c2b21;text-decoration:line-through}
.fbfiles .hint{display:block;margin-top:7px}

.fbdrop{display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-top:20px;padding:18px;
  border:2px dashed var(--n400);border-radius:14px;background:var(--n100);color:var(--n700)}
.fbdrop:hover{border-color:var(--p400);background:var(--p100)}
.fbdrop>div{min-width:220px;flex:1}
.fbdrop strong{display:block;font-size:14px;color:var(--n900);margin-bottom:2px}
.fbdrop input[type=file]{width:auto;flex:0 1 260px;font-size:13px;padding:7px 9px}

/* --- Demo content: the build report ------------------------------------- */
.demolog{margin-top:18px;padding:16px 18px;border:1px solid var(--div);border-radius:12px;background:var(--n100);font-size:13px}
.demolog p{margin:0 0 8px}
.demolog p.bad{color:#8c2b21}
.demolog ul{margin:0 0 12px;padding-left:20px;display:grid;gap:4px}
.demolog li{color:var(--n800);line-height:1.5}
.demolog a.btn{margin-right:8px}
