:root{
  --desk:#1D4A42; --face:#DEDAD2; --face-2:#EAE7E0;
  --hi:#FFFFFF; --lo:#8E897F; --lo2:#5A564E;
  --ink:#1B1A17; --ink-2:#5E594F; --ink-3:#8E897F;
  --bar:#2F7A5E; --bar-2:#57A986; --acc:#1F6B4F; --red:#A63A2C; --amber:#8A6A1F;
  --m:"IBM Plex Mono",ui-monospace,monospace;
}
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:var(--desk);color:var(--ink);font-family:var(--m);font-size:12.5px;
  line-height:1.6;overflow:hidden;font-variant-numeric:tabular-nums;
  background-image:linear-gradient(rgba(255,255,255,.022) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.022) 1px,transparent 1px);
  background-size:4px 4px}
img{image-rendering:pixelated}
button,input,select{font-family:var(--m);font-size:inherit}
button{cursor:pointer}
code{font-family:var(--m);word-break:break-all}

.out{border:2px solid var(--hi);border-right-color:var(--lo2);border-bottom-color:var(--lo2);
  box-shadow:inset -1px -1px 0 var(--lo),inset 1px 1px 0 var(--face-2)}
.in{border:2px solid var(--lo2);border-right-color:var(--hi);border-bottom-color:var(--hi);
  box-shadow:inset 1px 1px 0 var(--lo)}

/* ---------- desktop ---------- */
#desk{position:absolute;inset:0 0 34px 0;overflow:hidden}
.icons{position:absolute;left:14px;top:12px;z-index:1;display:flex;gap:14px;align-items:flex-start}
.col{display:flex;flex-direction:column;gap:4px}
.ico{width:82px;height:62px;padding:6px 3px;text-align:center;cursor:pointer;
  border:1px dotted transparent;user-select:none;overflow:hidden;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start}
.ico:hover{border-color:rgba(255,255,255,.34)}
.ico.sel{background:rgba(47,122,94,.5);border-color:rgba(255,255,255,.6)}
.ico:focus-visible{outline:1px solid #fff;outline-offset:1px}
.ico .g{width:32px;height:32px;margin:0 0 3px;display:grid;place-items:center;flex:none;
  background:var(--face);border:2px solid var(--hi);border-right-color:var(--lo2);border-bottom-color:var(--lo2)}
.ico .g svg{width:19px;height:19px;fill:var(--acc)}
.ico span{color:#EAF3EE;font-size:10.5px;letter-spacing:.3px;line-height:1.25;
  text-shadow:1px 1px 0 rgba(0,0,0,.6)}

/* ---------- windows ---------- */
.win{position:absolute;background:var(--face);min-width:260px;
  max-width:calc(100vw - 16px);max-height:calc(100vh - 46px);display:flex;flex-direction:column;
  box-shadow:3px 3px 0 rgba(0,0,0,.32)}
.tb{background:linear-gradient(90deg,var(--bar),var(--bar-2));color:#F2F7F4;
  padding:4px 5px 4px 8px;display:flex;align-items:center;gap:8px;cursor:move;user-select:none;
  flex:none;touch-action:none}
.win.blur .tb{background:linear-gradient(90deg,#7E8A85,#9AA6A0)}
.tb b{font-size:12px;font-weight:600;letter-spacing:.4px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tb .x{width:17px;height:16px;background:var(--face);border:1px solid var(--hi);
  border-right-color:var(--lo2);border-bottom-color:var(--lo2);color:var(--ink);
  font-size:10px;line-height:1;display:grid;place-items:center;padding:0;font-weight:700}
.tb .x:active{border-color:var(--lo2);border-right-color:var(--hi);border-bottom-color:var(--hi)}
.mb{display:flex;gap:13px;padding:3px 9px;border-bottom:1px solid var(--lo);font-size:11.5px;color:var(--ink-2);flex:none}
.body{padding:12px;overflow:auto;flex:1}
.body::-webkit-scrollbar{width:14px;height:14px}
.body::-webkit-scrollbar-track{background:#CFCABE}
.body::-webkit-scrollbar-thumb{background:var(--face);border:2px solid var(--hi);
  border-right-color:var(--lo2);border-bottom-color:var(--lo2)}

/* ---------- content ---------- */
h1{font-size:17px;margin:0 0 6px;font-weight:600;letter-spacing:-.01em}
h1 em{font-style:normal;color:var(--acc)}
h2{font-size:11px;letter-spacing:1.6px;text-transform:uppercase;color:var(--ink-3);margin:15px 0 6px;font-weight:600}
h2:first-child{margin-top:0}
p{margin:0 0 10px;color:var(--ink-2);max-width:64ch}
.field{background:#FFF;padding:8px 10px}
.r{display:flex;justify-content:space-between;gap:10px;padding:2px 0}
.r b{font-weight:600}
.r+.r{border-top:1px dotted #DDD8CD}
.z{color:var(--ink-3)}
table{width:100%;border-collapse:collapse;font-size:11.5px;background:#fff}
th{background:var(--face);text-align:left;padding:5px 7px;font-weight:600;font-size:10.5px;
  letter-spacing:.8px;border-bottom:1px solid var(--lo);position:sticky;top:0}
td{padding:5px 7px;border-bottom:1px solid #E8E4DA}
td.n,th.n{text-align:right}
.b3{background:var(--face);border:2px solid var(--hi);border-right-color:var(--lo2);
  border-bottom-color:var(--lo2);padding:5px 14px;font-size:11.5px;color:var(--ink)}
.b3:active{border-color:var(--lo2);border-right-color:var(--hi);border-bottom-color:var(--hi)}
.b3.go{background:var(--acc);color:#F2F7F4;border-color:#4F9C7C;border-right-color:#154A36;border-bottom-color:#154A36}
.b3.sm{padding:2px 8px;font-size:10.5px}
.b3:disabled{opacity:.45;cursor:default}
.btns{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
.mach{background:#fff;display:grid;place-items:center;padding:8px;align-self:start}
.mach img{width:100%;max-width:180px;display:block}
.gal{display:grid;grid-template-columns:repeat(auto-fill,minmax(74px,1fr));gap:5px;padding:6px;background:#fff}
.gal img{width:100%;background:#fff;border:1px solid var(--lo)}
.bars{display:grid;gap:3px}
.bar{display:grid;grid-template-columns:34px 42px 1fr 74px;gap:8px;align-items:center;font-size:11.5px}
.bar .t{background:#fff;padding:1px 4px}
.bar .g{height:11px;background:#fff;border:1px solid var(--lo);position:relative}
.bar .g i{position:absolute;inset:0 auto 0 0;background:var(--acc)}
.bar .c{text-align:right;color:var(--ink-2)}
.empty{background:#fff;padding:22px 14px;text-align:center;color:var(--ink-3);font-size:11.5px}
.note{border-left:2px solid var(--lo);padding-left:10px;margin:10px 0;color:var(--ink-3);font-size:11.5px}

.toc{background:#fff;padding:8px 10px;margin-bottom:14px;
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px 14px}
@media(max-width:560px){.toc{grid-template-columns:1fr}}
.toc a{display:block;padding:2px 0;font-size:11px;color:var(--ink-2);text-decoration:none;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.toc a:hover{color:var(--acc);text-decoration:underline}
.body h2[id]{scroll-margin-top:8px}

/* ---------- forms ---------- */
.form{background:#fff;padding:10px}
.fr{display:flex;align-items:center;gap:9px;padding:4px 0}
.fr label{width:96px;flex:none;color:var(--ink-2)}
.fr input,.fr select{flex:1;min-width:0;padding:4px 7px;background:#fff;color:var(--ink);
  border:2px solid var(--lo2);border-right-color:var(--hi);border-bottom-color:var(--hi)}
.fr input:focus,.fr select:focus{outline:1px solid var(--acc);outline-offset:-3px}
.cost{background:#fff;padding:8px 10px;margin-top:8px;display:flex;justify-content:space-between;gap:10px}
.cost b{color:var(--red)}
.spec{background:#fff;padding:8px 10px;margin-top:8px;font-size:11px;color:var(--ink-2)}
.spec code{color:var(--acc)}

/* ---------- whitelist task gate ---------- */
.wlgrid{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
@media(max-width:560px){.wlgrid{grid-template-columns:1fr}}
.wlhd{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
.wlhd h2{margin:0}
.badge{font-size:9.5px;letter-spacing:1.3px;padding:2px 8px;background:#fff;color:var(--ink-2);
  border:2px solid var(--lo2);border-right-color:var(--hi);border-bottom-color:var(--hi)}
.badge.on{background:var(--acc);color:#F2F7F4;border-color:#4F9C7C;
  border-right-color:#154A36;border-bottom-color:#154A36}
.task{display:flex;align-items:center;gap:8px;background:#fff;padding:6px 8px;margin-bottom:4px}
.task .ck{width:15px;height:15px;flex:none;display:grid;place-items:center;background:#fff;
  border:2px solid var(--lo2);border-right-color:var(--hi);border-bottom-color:var(--hi);
  font-size:10px;font-weight:700;color:var(--acc);line-height:1;cursor:pointer}
.task.done .ck::after{content:"\2713"}
.task .lb{flex:1;font-size:11px;line-height:1.35}
.task.done .lb{color:var(--ink-3)}
.gate{position:relative}
.gate.lock>*{opacity:.42}
.gate.lock::after{content:"";position:absolute;inset:0;cursor:not-allowed}
.hint{background:#fff;padding:7px 9px;margin-top:8px;font-size:11px;color:var(--ink-3);
  display:flex;gap:7px;align-items:flex-start}
.hint svg{width:13px;height:13px;fill:var(--amber);flex:none;margin-top:2px}

/* ---------- dialog ---------- */
.dlgback{position:fixed;inset:0;z-index:1500;background:rgba(12,30,26,.42);
  display:grid;place-items:center;padding:16px}
.dlg{background:var(--face);width:min(430px,100%);box-shadow:4px 4px 0 rgba(0,0,0,.34)}
.dlgb{display:flex;gap:12px;padding:16px 14px 8px}
.dlgi{width:32px;height:32px;flex:none;display:grid;place-items:center}
.dlgi svg{width:28px;height:28px}
.dlgi.info svg{fill:var(--acc)} .dlgi.warn svg{fill:var(--amber)} .dlgi.ok svg{fill:var(--acc)}
.dlgt{font-size:12px;color:var(--ink-2);line-height:1.65}
.dlgt b{color:var(--ink)}
.dlgt code{display:block;background:#fff;padding:6px 8px;margin-top:7px;font-size:10.5px;color:var(--acc)}
.dlgn{display:flex;justify-content:flex-end;gap:6px;padding:8px 14px 14px}

/* ---------- taskbar ---------- */
#tb{position:absolute;left:0;right:0;bottom:0;height:34px;background:var(--face);
  border-top:2px solid var(--hi);display:flex;align-items:center;gap:5px;padding:3px 5px;z-index:900}
#start{font-weight:700;font-size:11.5px;padding:4px 11px;display:flex;align-items:center;gap:6px}
#start .led{width:8px;height:8px;border-radius:50%;background:var(--acc);box-shadow:0 0 6px var(--acc)}
#tasks{flex:1;display:flex;gap:4px;overflow:hidden}
#tasks button{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:11px;padding:4px 10px;text-align:left}
#tasks button.act{border-color:var(--lo2);border-right-color:var(--hi);border-bottom-color:var(--hi);font-weight:600}
#cw{font-size:11px;padding:4px 12px;font-weight:600}

/* ---------- start menu ---------- */
#menu{position:absolute;left:5px;bottom:36px;width:216px;background:var(--face);z-index:950;display:none}
#menu.open{display:block}
#menu .hd{background:linear-gradient(180deg,var(--bar),#215C46);color:#F2F7F4;
  padding:9px 11px;font-weight:700;letter-spacing:2.4px;font-size:12px}
#menu .scroll{max-height:min(58vh,430px);overflow:auto}
#menu a{display:flex;align-items:center;gap:9px;padding:6px 11px;font-size:11.5px;color:var(--ink);text-decoration:none}
#menu a:hover{background:var(--acc);color:#F2F7F4}
#menu a svg{width:15px;height:15px;fill:currentColor;flex:none}
#menu hr{border:0;border-top:1px solid var(--lo);margin:3px 8px}

@media(prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important}}
@media(max-width:760px){
  body{overflow:hidden}

  /* Width alone decides this. A phone and a narrow desktop window want the same
     thing, and the layout below keeps the OS intact either way: icons become a
     launcher grid, and a window is still a window with wallpaper around it. */
  #desk{position:fixed;inset:0 0 46px 0;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:10px}
  .icons{position:static;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px}
  .col{display:contents}
  .ico{width:auto;height:auto;padding:13px 3px 11px;background:rgba(255,255,255,.055);
    border:1px solid rgba(255,255,255,.09)}
  .ico:active{background:rgba(47,122,94,.55)}
  .ico .g{width:38px;height:38px;margin:0 0 6px}
  .ico .g svg{width:22px;height:22px}
  .ico span{font-size:11px}

  /* one window visible at a time, switched from the taskbar, never destroyed */
  .win{position:fixed!important;left:7px!important;right:7px!important;top:7px!important;
    bottom:53px!important;width:auto!important;height:auto!important;max-width:none;max-height:none;
    margin:0;z-index:800!important;box-shadow:3px 3px 0 rgba(0,0,0,.42)}
  .win.blur{display:none}
  .tb{padding:8px 8px 8px 11px;cursor:move}
  .tb b{font-size:13px}
  .tb .x{width:27px;height:25px;font-size:12px}
  .mb{padding:5px 10px;font-size:12px;gap:15px}
  .body{padding:12px 12px 22px;max-height:none!important}

  #tb{position:fixed;height:46px;padding:5px 6px;
    padding-bottom:calc(5px + env(safe-area-inset-bottom))}
  #tasks{gap:5px;overflow-x:auto;scrollbar-width:none}
  #tasks::-webkit-scrollbar{display:none}
  #tasks button{max-width:132px;padding:7px 11px;font-size:11.5px}
  #start,#cw{padding:8px 12px;font-size:12px}
  #start span:not(.led){display:none}
  #menu{left:5px;right:5px;width:auto;bottom:48px}
  #menu .scroll{max-height:54vh}
  #menu a{padding:9px 12px;font-size:12.5px}

  .dlg{width:100%}
  .dlgn .b3{padding:8px 15px}
  .wlgrid{grid-template-columns:1fr}
  h1{font-size:19px}
  .fr input,.fr select{padding:7px 8px;font-size:12.5px}
  .b3{padding:7px 15px}
  .task{padding:8px 9px}
  table{font-size:11px}
}

/* ================= boot · POST SELF TEST (module: boot) =================
   Replaces the old #boot block entirely. Namespace: #pboot / .pb-*.
   Pure CSS boxes and transforms — no images, no canvas, nothing on the
   critical path, so a 380px phone runs the identical timeline.          */

#pboot{position:fixed;inset:0;z-index:5000;background:#101F1B;cursor:pointer;overflow:hidden;
  display:grid;place-items:center;
  background-image:repeating-linear-gradient(0deg,rgba(255,255,255,.02) 0 1px,transparent 1px 3px)}
#pboot.pb-gone{opacity:0;pointer-events:none;transition:opacity .14s linear}

/* the chassis. .in is reused, but its bevel colours are re-toned for a dark box */
.pb-mach{position:relative;width:min(520px,92vw);height:min(300px,52vh);background:#16302A}
#pboot .pb-mach.in{border-color:#0A1512;border-right-color:#2E5A4C;border-bottom-color:#2E5A4C;
  box-shadow:inset 1px 1px 0 #061210}

/* the paper window. The sheet is bottom-anchored and grows upward as it prints,
   and it can never reach a viewport edge — the chassis margin is always visible. */
.pb-win{position:absolute;left:12px;right:12px;top:12px;bottom:40px;overflow:hidden}
.pb-logo{position:absolute;left:50%;top:46%;transform:translate(-50%,-50%);
  width:clamp(58px,15vw,92px);height:auto;image-rendering:pixelated;opacity:0;
  border:2px solid rgba(234,243,238,.14);box-shadow:0 8px 26px rgba(0,0,0,.5);z-index:0}
.pb-paper{z-index:1;position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;
  background:#EDE9DF;color:var(--ink);padding:9px 11px 8px;
  box-shadow:0 -2px 0 rgba(0,0,0,.28);will-change:transform;
  font-size:clamp(9.5px,2.6vw,11.5px);line-height:1.78}

/* one row = one head pass. min-height is pinned in em so a late IBM Plex Mono
   swap cannot reflow the sheet mid-print — there is no font gate. */
.pb-ln{display:flex;align-items:baseline;gap:8px;white-space:nowrap;min-height:1.78em;
  clip-path:inset(0 100% 0 0)}
.pb-ln.pb-hd{justify-content:center;font-weight:700;letter-spacing:2px;
  border-bottom:1px solid #C9C3B5;padding-bottom:3px;margin-bottom:3px}
.pb-k{flex:none}
.pb-v{flex:none;font-weight:600}
/* zero-height flex leader, never literal dots — this is why no row can wrap at 380px */
.pb-f{flex:1 1 auto;min-width:10px;align-self:flex-end;height:0;
  border-top:1px dotted #B9B3A6;margin-bottom:.36em}
/* fixed-width status gutter: every row shares one hard right edge */
.pb-s{flex:none;width:9ch;text-align:right;color:var(--acc)}
.pb-s.pb-wait{color:var(--ink-3)}
.pb-s.pb-dark{color:var(--ink-2)}
.pb-stamp{align-self:flex-end;margin-top:5px}

/* the nozzle check: the six reward tickers ARE the alignment pattern */
.pb-nz{display:inline-flex;gap:3px;align-self:center}
.pb-nz i{display:flex;flex-direction:column;align-items:center;gap:2px;font-style:normal}
.pb-nz i b{display:block;width:13px;height:9px;
  background:repeating-linear-gradient(90deg,var(--ink) 0 1px,transparent 1px 3px)}
.pb-nz i em{font-style:normal;font-size:7.5px;letter-spacing:.4px;line-height:1;color:var(--ink-2)}

/* carriage rail + head. The sweep animates `left` on a 2-element rail — one
   property, no layout thrash, and it is the sequence's only signature motion. */
.pb-rail{position:absolute;left:12px;right:12px;bottom:22px;height:12px;background:#0C1A17;
  box-shadow:inset 0 1px 0 rgba(0,0,0,.65),inset 0 -1px 0 rgba(255,255,255,.06)}
.pb-head{position:absolute;top:-3px;left:4%;width:30px;height:17px;transform:translateX(-50%);
  background:linear-gradient(180deg,var(--bar-2),var(--bar));box-shadow:0 2px 0 rgba(0,0,0,.45)}
.pb-head:after{content:"";position:absolute;left:5px;right:5px;top:3px;height:2px;background:#0C1A17}
.pb-led{position:absolute;right:14px;bottom:7px;width:7px;height:7px;background:#123028}
.pb-led.pb-on{background:var(--bar-2);box-shadow:0 0 7px var(--bar-2)}

.pb-skip{position:fixed;right:12px;bottom:12px;background:none;border:0;padding:7px 9px;
  color:#6E8F84;font-family:var(--m);font-size:10.5px;letter-spacing:2px}
.pb-skip:hover{color:#9ED0BC}

/* phone. Captions are desktop-only — six unlabelled hairline bars still read
   as a nozzle check, and 7.5px type on a phone does not. */
@media(max-width:480px){
  .pb-nz i em{display:none}
  .pb-nz i b{width:9px}
}
@media(max-width:420px){
  .pb-mach{height:min(320px,58vh)}
  .pb-head{width:22px}
  .pb-s{width:8ch}
  .pb-paper{padding:8px 9px 7px}
}
