@font-face{
  font-family:"Poppins"; font-style:normal; font-weight:400; font-display:swap;
  src:url("/fonts/poppins-400.woff2") format("woff2");
}
@font-face{
  font-family:"Poppins"; font-style:normal; font-weight:500; font-display:swap;
  src:url("/fonts/poppins-500.woff2") format("woff2");
}
@font-face{
  font-family:"Poppins"; font-style:normal; font-weight:600; font-display:swap;
  src:url("/fonts/poppins-600.woff2") format("woff2");
}

/* Holdout
   Text-only. No panels, no cards, no rules, no filled buttons. Structure comes
   from whitespace, alignment and case — the way a terminal session reads.
   The single exception is the checkerboard behind imagery, because that is
   content (it is what transparency looks like), not chrome. */

:root{
  --bg:#070707;
  --text:#e9e9e9;
  --muted:#9a9a9a;
  --faint:#5a5a5a;
  --dim:#333333;
  --accent:#ffffff;
  --accent-ink:#ffffff;
  --accent-deep:#000000;
  --accent-soft:rgba(255,255,255,.05);
  --crit:#ffffff;
  --chk-a:#101010; --chk-b:#181818;
  --mono:ui-monospace,"Cascadia Code","JetBrains Mono","SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  --sans:"Poppins",system-ui,"Segoe UI",sans-serif;
  --font:var(--sans);
  /* kept so any stray rule resolves to something sane */
  --surface:transparent; --surface-2:transparent; --surface-3:#1a1a1a;
  --border:transparent; --border-soft:transparent;
  --good:var(--text); --warn:var(--text);
}
@media (prefers-color-scheme: light){
  :root{
    --bg:#f7f7f7; --text:#111; --muted:#5c5c5c; --faint:#8c8c8c; --dim:#d0d0d0;
    --accent:#111; --accent-ink:#111; --accent-deep:#fff; --accent-soft:rgba(0,0,0,.04);
    --crit:#000; --chk-a:#ececec; --chk-b:#dedede; --surface-3:#e6e6e6;
  }
}

*{box-sizing:border-box}
/* .login/.app set display:grid, which outranks the UA's [hidden]{display:none};
   without this both views render at once. */
[hidden]{display:none !important}
body{
  margin:0;background:var(--bg);color:var(--text);
  font-family:var(--font);font-size:13px;line-height:1.6;
  -webkit-font-smoothing:antialiased;font-variant-ligatures:none;
}
h1,h2{margin:0;font-weight:400;font-size:13px;text-transform:uppercase;letter-spacing:.18em;
  color:var(--faint)}
button{font-family:inherit;font-size:inherit;cursor:pointer;background:none;border:0;
  padding:0;color:inherit}
input,select,table{font-family:inherit;font-size:inherit}
a{color:var(--text)}
table{border-collapse:collapse}

/* ---------- the one piece of chrome: alpha checkerboard ---------- */
.mark,.checker,.gallery .cell,.stage{
  background-image:
    linear-gradient(45deg,var(--chk-b) 25%,transparent 25%),
    linear-gradient(-45deg,var(--chk-b) 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,var(--chk-b) 75%),
    linear-gradient(-45deg,transparent 75%,var(--chk-b) 75%);
  background-color:var(--chk-a);
}
.mark{width:11px;height:11px;flex:none;display:inline-block;
  background-size:6px 6px;background-position:0 0,0 3px,3px -3px,-3px 0}
.mark.big{width:34px;height:34px;background-size:10px 10px;
  background-position:0 0,0 5px,5px -5px,-5px 0}

/* ---------- text buttons: [ LABEL ] ---------- */
button.ghost,button.primary{
  text-transform:uppercase;letter-spacing:.12em;font-size:11px;color:var(--muted);
  transition:color .1s;
}
button.ghost::before,button.primary::before{content:"[ ";color:var(--dim)}
button.ghost::after,button.primary::after{content:" ]";color:var(--dim)}
button.primary{color:var(--text)}
button.ghost:hover,button.primary:hover:not(:disabled){color:var(--text)}
button.ghost:hover::before,button.ghost:hover::after,
button.primary:hover::before,button.primary:hover::after{color:var(--text)}
button.ghost:disabled,button.primary:disabled{color:var(--dim);cursor:not-allowed}
button.ghost:disabled::before,button.ghost:disabled::after,
button.primary:disabled::before,button.primary:disabled::after{color:var(--dim)}
button.ghost.small{font-size:10px}
button.primary.block{display:block;width:100%;text-align:left;margin-top:4px}
button.link{color:var(--text);text-decoration:underline;text-underline-offset:2px;
  text-transform:none;letter-spacing:0;font-size:inherit}
button.link::before,button.link::after{content:none}

/* ---------- header ---------- */
.bar{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:14px 20px 10px;flex-wrap:wrap;
}
.brand{display:flex;align-items:center;gap:8px;font-size:12px;
  letter-spacing:.22em;text-transform:uppercase;color:var(--text)}
.word b{font-weight:400;color:var(--faint)}
.acct{display:flex;align-items:center;gap:16px;font-size:11px;color:var(--faint);flex-wrap:wrap}
.meters{display:flex;align-items:center;gap:16px}
.acct .stat{display:inline-flex;align-items:baseline;gap:4px}
.acct .num{color:var(--muted)}
.acct .unit{color:var(--faint)}
.acct .user{color:var(--muted)}
.divider{display:none}

.badge{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.badge::before{content:"· "}
.badge.ok{color:var(--text)}
.badge.bad{color:var(--text)}
.badge.bad::before{content:"! "}
.badge.mock{color:var(--faint)}
.badge.idle{color:var(--faint)}

/* ---------- tabs ---------- */
.tabs{display:flex;align-items:center;gap:22px;padding:2px 20px 12px;flex-wrap:wrap}
.tab{text-transform:uppercase;letter-spacing:.16em;font-size:11px;color:var(--dim)}
.tab:hover{color:var(--muted)}
.tab.is-on{color:var(--text)}
.tab.is-on::before{content:"› "}
.tabs-spacer{flex:1}
.farmpulse{display:inline-flex;align-items:center;gap:6px;font-size:10.5px;color:var(--dim);
  letter-spacing:.05em}
.farmpulse i{display:none}
.farmpulse.busy{color:var(--muted)}
.farmpulse.busy::before{content:"●";animation:blink 1.1s steps(1,end) infinite}
@keyframes blink{0%,49%{opacity:1}50%,100%{opacity:.15}}
@keyframes glowpulse{
  0%,100%{opacity:.55;text-shadow:none}
  50%{opacity:1;text-shadow:0 0 12px rgba(255,255,255,.35)}
}
@keyframes textglow{
  0%,100%{color:#a7aeaa;text-shadow:none}
  50%{color:#eef3f0;text-shadow:0 0 16px rgba(238,243,240,.4)}
}

/* ---------- login ---------- */
/* The form sits low over the backdrop rather than centred, so the clip reads
   as the page and the form as something resting on it. The clamp keeps it on
   screen on short windows instead of running off the bottom. */
/* --vph is the visible viewport height in this document's own units,
   measured in JS: dvh cannot be trusted here because under the wide-screen
   zoom rule it resolves against the UNZOOMED viewport and overshoots. */
.login{display:grid;justify-items:center;align-items:end;
  min-height:100vh;min-height:var(--vph,100dvh);padding:20px;box-sizing:border-box}
/* bottom-anchored: whatever form is showing (sign-in, request, signup), it
   ends above the fold instead of forcing a slight scroll — the logo lives in
   the fixed backdrop, so it keeps the upper half regardless */
.login-inner{margin-bottom:34px}
/* no rubber-band overscroll revealing the void behind the backdrop */
html{overscroll-behavior-y:none}
.login-inner{position:relative;z-index:1;width:100%;max-width:400px}

/* ---------- hero ---------- */
/* Full-bleed backdrop. Fixed to the viewport rather than sized in flow, so it
   covers the page at any height; it lives inside #loginView, so [hidden] stops
   it the moment the app is shown. */
.hero{position:fixed;inset:0;z-index:0;background:#000;overflow:hidden}
.hero-vid{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  display:block;border:0}
/* scrim: the clip has bright passages, and the form has to stay readable
   wherever the animation happens to be */
.hero::after{content:"";position:absolute;inset:0;background:rgba(0,0,0,.5)}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.card{padding:0}
#loginForm{display:flex;flex-direction:column;gap:14px}
label{font-size:10.5px;color:var(--faint);display:flex;flex-direction:column;gap:3px;
  text-transform:uppercase;letter-spacing:.14em}
/* input:not([type]) matters: an <input> with no type attribute IS text,
   but the attribute selector [type=text] does not match it — those fields
   were falling through to the browser's default white. */
input:not([type]),input[type=text],input[type=password],input[type=email],
input[type=number],#prompt,.login input{
  width:100%;background:none;border:0;border-bottom:1px solid var(--dim);
  padding:4px 0;color:var(--text);font-family:var(--mono);font-size:13px;
  transition:border-color .12s;
}
/* Chrome paints autofilled fields its own pale blue; an inset shadow is the
   only override it honours. Global — the login form re-overrides in its own
   colours below. */
input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus{
  -webkit-text-fill-color:var(--text);
  -webkit-box-shadow:0 0 0 1000px var(--bg) inset;
  caret-color:var(--text);
  transition:background-color 999999s;  /* stalls Chrome's repaint */
}
input[type=checkbox]{accent-color:var(--text)}
input::placeholder{color:var(--dim)}
input:focus{outline:none;border-bottom-color:var(--text)}
.err{color:var(--text);font-size:11.5px;margin:0}
.err::before{content:"! "}

/* ---------- layout ---------- */
/* Workspace: compact controls beside a large picking stage. Clicking points
   accurately needs the frame as big as the screen allows. */
.app{max-width:1800px;margin:0 auto;padding:6px 20px 60px}
.worksplit{display:grid;grid-template-columns:300px minmax(0,1fr);gap:36px;align-items:start}
.workctl{min-width:0}
.workstage{min-width:0}
/* Desktop: the page itself never scrolls — the stage stays put and the
   controls column scrolls inside its own track. --chrome is the height of
   everything above the workspace (header + tabs + padding), measured live
   by app.js so nothing here goes stale when the header changes. */
@media(min-width:901px){
  #appView .worksplit{height:var(--wsh, auto);overflow:hidden}
  #appView .workctl{height:100%;overflow-y:auto;overflow-x:hidden;
    padding-right:14px;scrollbar-width:thin;scrollbar-color:var(--dim) transparent}
  #appView .workctl::-webkit-scrollbar{width:6px}
  #appView .workctl::-webkit-scrollbar-thumb{background:var(--dim)}
  #appView .workctl::-webkit-scrollbar-track{background:transparent}
  /* the stage flexes to whatever height is left instead of a fixed 72vh,
     so the image, timeline and hints always fit without scrolling */
  #appView .workstage{height:100%;overflow:hidden;display:flex;flex-direction:column}
  #appView .picker{display:flex;flex-direction:column;flex:1;min-height:0}
  #appView .pickstage{height:auto;flex:1;min-height:180px}
  #appView .pickframe{max-height:var(--stageh, 72vh)}
  #appView .pickstage img{max-height:var(--stageh, 72vh)}
  /* the roomy page-bottom padding belongs to scrolling pages; here it just
     pushed the pinned layout past the fold */
  #appView.app{padding-bottom:8px}
}
@media(max-width:900px){.worksplit{grid-template-columns:1fr;gap:24px}}

/* hover tooltips on setting names — the terminal answer to a manual */
[data-tip]{position:relative;cursor:help}
[data-tip]:hover::after{
  content:attr(data-tip);position:absolute;left:0;top:calc(100% + 8px);
  z-index:40;width:34ch;background:var(--bg);border:1px solid var(--dim);
  padding:10px 12px;font-size:10.5px;line-height:1.7;color:var(--muted);
  text-transform:none;letter-spacing:0;font-weight:400;white-space:normal;
  pointer-events:none}

/* Carlo runs the site at 150% browser zoom and prefers those proportions,
   so wide screens get them by default. Media queries evaluate against the
   REAL viewport, so breakpoints are unaffected; gate high enough that the
   effective width (/1.5) still clears the 900px two-column layout. */
@media(min-width:1600px){body{zoom:1.5}}
/* Jobs gets the full width so the playback stage can be large. */
.jobs{max-width:1500px;margin:0 auto;padding:6px 20px 60px}
.farm{max-width:1240px;margin:0 auto;padding:6px 20px 60px}
.panel{padding:0}
.panel-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  margin-bottom:16px}
.panel-note{font-size:10.5px;color:var(--dim)}

/* ---------- account ---------- */
.acct .user{background:none;border:0;font:inherit;cursor:pointer;padding:0;
  text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--dim)}
.acct .user:hover{color:var(--text)}
.mustset{border:1px solid var(--text);padding:12px 14px;margin:0 0 26px;
  font-size:12px;line-height:1.6;color:var(--muted);max-width:62ch}
.fmsg{font-size:11px;letter-spacing:.06em;color:var(--muted);align-self:center}
.fmsg.bad{color:var(--text)}
.fmsg.bad::before{content:"! ";color:var(--text)}

/* ---------- admin ---------- */
.invite{display:flex;flex-wrap:wrap;align-items:flex-end;gap:18px 22px;margin-bottom:30px}
.ifield{display:flex;flex-direction:column;gap:5px;min-width:150px}
.ifield .k{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
.ifield input{width:100%}
.ifield.chk{flex-direction:row;align-items:center;gap:8px;min-width:0;
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.ifield.chk input{width:auto}
.newcode{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin:-14px 0 30px;
  padding:12px 14px;border:1px solid var(--text)}
.newcode .k{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.newcode code{font-size:17px;letter-spacing:.2em;color:var(--text)}
.newcode .nchint{font-size:10.5px;color:var(--dim);flex-basis:100%}
.ledger{width:100%;font-size:12px}
.ledger th{text-align:left;font-weight:400;color:var(--dim);font-size:10px;
  letter-spacing:.14em;text-transform:uppercase;padding:0 26px 8px 0;
  white-space:nowrap}
.ledger td{padding:4px 26px 4px 0;vertical-align:baseline;color:var(--muted)}
.ledger th:last-child,.ledger td:last-child{padding-right:0}
.ledger tbody tr:hover td{color:var(--text)}
.ledger tr.off td{color:var(--dim)}
.c-note{color:var(--muted);max-width:200px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.c-act{white-space:nowrap;text-align:right}
.c-act button{margin-left:6px}

/* ---------- frame bar ----------
   One cell per frame in the job, present from the moment it is submitted so
   the length of the work is visible before any of it is done. */
.framebar{display:flex;gap:1px;height:15px;margin:8px 0 2px;cursor:pointer;
  align-items:stretch;user-select:none}
.framebar i{flex:1 1 0;min-width:1px;background:var(--dim);position:relative}
.framebar i[data-s="ok"]{background:var(--text)}
.framebar i[data-s="fail"]{background:var(--dim);
  /* hatched so a failure never reads as merely queued */
  background-image:repeating-linear-gradient(45deg,
    var(--text) 0 1px,transparent 1px 3px)}
.framebar i.now{animation:framepulse .9s steps(2,end) infinite}
@keyframes framepulse{0%,49%{background:var(--text)}50%,100%{background:var(--dim)}}
/* playhead reads over any cell state */
.framebar i.at::after{content:"";position:absolute;inset:-3px -1px;
  border:1px solid var(--text);pointer-events:none}
/* the stage goes black for a frame that does not exist yet */
.stage.blank{background:#000;background-image:none}
.stage{position:relative}
.notyet{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  font-size:10px;letter-spacing:.22em;color:#555;pointer-events:none}

/* ---------- farm ---------- */
.stripbar{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:4px 26px;margin-bottom:34px}
.strip{display:flex;align-items:baseline;gap:8px}
.strip .k{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
.strip .v{font-size:12.5px;color:var(--text);margin-left:auto}
.strip .v.on{color:var(--text)}
.strip .v.off{color:var(--faint)}

.tablewrap{overflow-x:auto}
.dl-table{width:100%;font-size:12px;min-width:640px}
.dl-table thead th{
  text-align:left;font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--dim);font-weight:400;padding:0 14px 10px 0;white-space:nowrap;
}
.dl-table td{padding:3px 14px 3px 0;vertical-align:baseline;color:var(--muted)}
.dl-table tbody tr:hover td{color:var(--text)}
.dl-table tbody tr.mine td{color:var(--text)}
.c-nu{text-align:right;white-space:nowrap;font-size:11.5px}
.c-id{color:var(--dim);font-size:11.5px;white-space:nowrap}
.c-us{white-space:nowrap}
.c-us .you{color:var(--faint);font-size:10px;letter-spacing:.1em;text-transform:uppercase}
.c-us .you::before{content:" ‹"}
.c-us .you::after{content:"›"}
/* free-allowance jobs are people trying things out, not billable work */
.c-us .test{margin-left:6px;color:var(--dim);font-size:10px;letter-spacing:.1em;
  text-transform:uppercase}
.c-pr{white-space:nowrap;width:1%}
.c-nu s{text-decoration:none;color:var(--text)}
.c-nu s::before{content:" !"}
.dl-table .empty{padding:18px 0}

/* ---------- wallet ---------- */
.topups{display:flex;gap:14px;flex-wrap:wrap;margin-bottom:18px}
.topups .topup{font-size:12.5px;letter-spacing:.06em}
.paywith{display:flex;align-items:center;gap:18px;flex-wrap:wrap;font-size:11px;
  color:var(--faint)}
.paywith .k{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
.paywith label{flex-direction:row;align-items:center;gap:6px;text-transform:none;
  letter-spacing:0;font-size:11.5px;color:var(--muted);cursor:pointer}
.paywith label.off{color:var(--dim);cursor:not-allowed}
.paywith input[type=radio]{accent-color:var(--text);margin:0}

.lnpay{margin:26px 0 8px}
.lninv{width:100%;background:var(--bg);border:1px solid var(--dim);color:var(--muted);
  font-family:var(--mono);font-size:10.5px;padding:8px;border-radius:0;resize:vertical;
  word-break:break-all}
.lninv:focus{outline:none;border-color:var(--text);color:var(--text)}
a.lnopen{text-decoration:none;display:inline-block}

/* ---------- high scores ---------- */
.scores-head{display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  margin-bottom:22px;flex-wrap:wrap}
.dl-table.scores td{padding:4px 16px 4px 0}
.c-rk{color:var(--dim);font-size:11.5px;white-space:nowrap;letter-spacing:.06em}
tr.first .c-rk,tr.first .c-us{color:var(--text)}
tr.first .c-nu{color:var(--muted)}
#scoresFoot{margin-top:22px}

/* status as text, not chips */
.pill{font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;white-space:nowrap;
  color:var(--faint)}
.pill.done{color:var(--dim)}
.pill.running{color:var(--text);animation:glowpulse 2.2s ease-in-out infinite}
.pill.running::before{content:"● "}
.pill.error{color:var(--text)}
.pill.error::before{content:"! "}
.pill.queued{color:var(--faint)}
.pill.queued::before{content:"· "}
.pill.uploading{color:var(--muted)}
.pill.uploading::before{content:"↑ "}
.pill.paused{color:var(--muted)}
.pill.paused::before{content:"❚❚ "}
.pill.cancelled{color:var(--dim)}
.pill.cancelled::before{content:"× "}
/* job transport, shown in the results header while a job is open */
.jobctl{display:inline-flex;gap:6px;align-items:center;margin-left:auto}
.jobctl button[hidden]{display:none}

/* block-character progress */
.blocks{letter-spacing:-.5px;color:var(--text);font-size:12px}
.blocks .off{color:var(--dim)}
tr.done .blocks,.job.done .blocks{color:var(--faint)}
.pct{color:var(--faint);font-size:11px;margin-left:8px}

/* ---------- new matte ---------- */
.drop{padding:14px 0 16px;color:var(--faint);cursor:pointer;transition:color .12s}
.drop:hover,.drop.hot{color:var(--text)}
.drop-icon{display:none}
.drop-main{margin:0;font-size:12.5px}
.drop-main::before{content:"+ ";color:var(--dim)}
.drop b{font-weight:400;color:var(--text)}
.drop.hot .drop-main::before{color:var(--text)}
.hint{font-size:10.5px;color:var(--dim);margin:3px 0 0}
.hint.free{color:var(--muted);margin-top:8px}
.hint.free::before{content:"· "}

.filerow{display:flex;align-items:baseline;gap:14px;margin-top:6px;font-size:11.5px;
  color:var(--muted);padding:0}
.filerow .cost{color:var(--text);margin-left:auto}

.field{margin-top:22px;font-size:11px;color:var(--faint);gap:4px}
.field-label{display:flex;align-items:baseline;justify-content:space-between;
  font-size:10.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.14em}
.field-label .mono{color:var(--text);letter-spacing:0}
input[type=range]{width:100%;accent-color:var(--text);height:2px;margin:8px 0 0}
.scale{display:flex;justify-content:space-between;font-size:9.5px;color:var(--dim);
  letter-spacing:.1em;text-transform:uppercase}

.field.checkrow{gap:2px}
.field.checkrow span:first-child{display:flex;align-items:center;gap:8px;
  font-size:11.5px;color:var(--muted);text-transform:none;letter-spacing:0}
.field.checkrow input[type=checkbox]{accent-color:var(--text);margin:0}

.actions{display:flex;gap:20px;margin-top:26px;align-items:baseline}
.actions .primary{margin-left:auto}

/* ---------- matte overlay (composited onto the picking stage) ---------- */
.ovmatte{position:absolute;inset:0;pointer-events:none;opacity:0;
  transition:opacity .12s;
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}
/* stacked, because it now sits in the narrow control column */
.ovctl{display:flex;flex-direction:column;gap:8px;margin-top:22px}
.ovrow{display:flex;align-items:center;justify-content:space-between;gap:12px}
.ovlabel{display:flex;flex-direction:row;align-items:center;gap:10px;
  font-size:10.5px;color:var(--faint)}
.ovlabel .frameno{flex:none;min-width:34px;text-align:right}
.ovlabel input[type=range]{flex:1;margin:0;accent-color:var(--text);height:2px}
.ovlabel.swatch{flex:none;min-width:0}
.ovlabel input[type=color]{width:26px;height:16px;padding:0;border:1px solid var(--dim);
  background:none;cursor:pointer}

.preview{margin-top:26px}
.preview-label{font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--dim);margin-bottom:8px}
.checker{overflow:hidden;min-height:100px;background-size:16px 16px;
  background-position:0 0,0 8px,8px -8px,-8px 0}
.checker img{display:block;max-width:100%;margin:0 auto}

/* ---------- point picker ---------- */
.picker{margin-top:0}
.pickcount{color:var(--faint);letter-spacing:.06em}
.pickstage{
  position:relative;overflow:hidden;display:grid;place-items:center;
  min-height:260px;height:72vh;
  background-size:18px 18px;background-position:0 0,0 9px,9px -9px,-9px 0;
}
/* shrink-wraps the image so the overlay and the click maths share one box */
.pickframe{position:relative;display:inline-block;line-height:0;cursor:crosshair;
  max-width:100%;max-height:72vh;
  /* zoom transform is applied inline; origin must be the box corner so the
     cursor-anchored maths in zApply() holds */
  transform-origin:0 0;will-change:transform}
.pickstage.panning,.pickstage.panning .pickframe{cursor:grabbing}
.pickframe.pixel img{image-rendering:pixelated}
.pickstage img{display:block;max-width:100%;max-height:72vh;object-fit:contain;
  user-select:none;-webkit-user-drag:none}
kbd{font:inherit;border:1px solid var(--line);padding:0 4px;color:var(--dim)}
/* zoom readout, corner of the stage */
.zoomtag{position:absolute;right:8px;bottom:6px;font-size:11px;color:var(--dim);
  letter-spacing:.08em;pointer-events:none;text-shadow:0 0 3px #000,0 0 3px #000}
.pickmarks{position:absolute;inset:0;pointer-events:none;line-height:1}
.pickmarks i{
  position:absolute;transform:translate(-50%,-50%) scale(var(--iz,1));
  font-style:normal;font-size:12px;line-height:1;width:15px;height:15px;
  display:grid;place-items:center;
  /* outlined so a marker stays visible on black or white footage */
  text-shadow:0 0 2px #000,0 0 2px #000,0 0 3px #000;
}
.pickmarks i.pos{color:#fff}
.pickmarks i.neg{color:#fff;opacity:.9}
.pickmarks i.pos::after,.pickmarks i.neg::after{
  content:"";position:absolute;inset:0;border:1px solid #fff;border-radius:50%;
  box-shadow:0 0 0 1px rgba(0,0,0,.7)}
.pickmarks i.neg::after{border-style:dashed}
.opt{color:var(--dim);text-transform:none;letter-spacing:0}

/* ---------- timeline ---------- */
.timeline{
  position:relative;flex:1;min-width:60px;height:22px;cursor:pointer;
  touch-action:none;display:flex;align-items:center;
}
.timeline:focus{outline:none}
.timeline:focus .tl-line{background:var(--muted)}
.tl-line{position:absolute;left:0;right:0;height:1px;background:var(--dim)}
.tl-keys{position:absolute;inset:0;pointer-events:none}
/* a keyframe is a moment, so it is a tick — not a span */
.tl-keys b{position:absolute;top:4px;width:1px;height:14px;margin-left:-.5px;
  background:var(--muted)}
.tl-keys b.pos{background:var(--text)}
.tl-keys b.neg{background:var(--faint)}
.tl-keys b.both{background:var(--text);box-shadow:0 6px 0 -1px var(--faint)}
.tl-keys b.on{background:var(--text);width:2px;margin-left:-1px}
.tl-head{position:absolute;top:1px;width:1px;height:20px;margin-left:-.5px;
  background:var(--text)}
.tl-head::before{content:"";position:absolute;top:-1px;left:-2px;
  border-left:2.5px solid transparent;border-right:2.5px solid transparent;
  border-top:4px solid var(--text)}

/* ---------- player ---------- */
.player{margin-bottom:26px}
/* the point of a separate Jobs page is room to actually see the matte */
.stage{overflow:hidden;background-size:18px 18px;
  background-position:0 0,0 9px,9px -9px,-9px 0;
  display:grid;place-items:center;min-height:300px;height:74vh}
.stage img{display:block;max-width:100%;max-height:74vh;object-fit:contain;
  transform-origin:0 0;will-change:transform}
#playerImg.pixel{image-rendering:pixelated}
.stage.grabbing{cursor:grabbing}
.buffer{margin-top:10px;font-size:11px;color:var(--dim);letter-spacing:-.5px;
  white-space:nowrap;overflow:hidden}
.buffer .on{color:var(--muted)}

.transport{display:flex;align-items:center;gap:16px;margin-top:12px}
.transport .play{flex:none}
.transport .framebar{flex:1;min-width:60px;margin:0;height:18px;
  cursor:ew-resize;touch-action:none}
.frameno{font-size:11px;color:var(--faint);white-space:nowrap;flex:none;
  /* counters must not breathe: Poppins digits are proportional, and a counter
     that changes width makes the flexed timeline beside it rescale */
  font-family:var(--mono);font-variant-numeric:tabular-nums;
  font-variant-numeric:tabular-nums}
select.pick{
  width:100%;background:none;border:0;border-bottom:1px solid var(--dim);
  color:var(--text);font-family:var(--mono);font-size:12.5px;padding:4px 0;
  cursor:pointer;border-radius:0;
}
select.pick:focus{outline:none;border-bottom-color:var(--text)}
select.pick option{background:var(--bg);color:var(--text)}

.fps{background:none;border:0;color:var(--faint);font-family:var(--mono);
  font-size:10.5px;flex:none;cursor:pointer}
.fps:focus{outline:none;color:var(--text)}
.fps option{background:var(--bg);color:var(--text)}

/* ---------- results ---------- */
.results-head{display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  margin-bottom:16px}
#resultsTitle{font-size:13px;letter-spacing:.16em;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.prog{font-size:11px;color:var(--muted);white-space:nowrap}

/* a failure has to say what happened and offer the way out */
.joberr{display:flex;align-items:baseline;gap:12px;margin:-4px 0 14px;
  font-size:11.5px;color:var(--text);flex-wrap:wrap}
.joberr-msg{flex:1;min-width:200px}
.joberr-msg::before{content:"! "}
.joberr.calm{color:var(--muted)}
.joberr.calm .joberr-msg::before{content:"· "}

.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));
  gap:4px;margin-bottom:22px}
.gallery .cell{overflow:hidden;aspect-ratio:1;background-size:12px 12px;
  background-position:0 0,0 6px,6px -6px,-6px 0;opacity:.85;transition:opacity .12s}
.gallery .cell:hover{opacity:1}
.gallery .cell img{width:100%;height:100%;object-fit:contain;display:block}

.joblist{display:flex;flex-direction:column;gap:2px}
.job{display:flex;align-items:center;gap:12px;padding:3px 0;cursor:pointer;
  font-size:12px;color:var(--muted);transition:color .12s}

/* job thumbnail — imagery, so the checkerboard is allowed here */
.jthumb{width:22px;height:22px;flex:none;overflow:hidden;opacity:.8;
  transition:opacity .12s;
  background-image:
    linear-gradient(45deg,var(--chk-b) 25%,transparent 25%),
    linear-gradient(-45deg,var(--chk-b) 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,var(--chk-b) 75%),
    linear-gradient(-45deg,transparent 75%,var(--chk-b) 75%);
  background-color:var(--chk-a);
  background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}
.job:hover .jthumb{opacity:1}
.jthumb img{width:100%;height:100%;object-fit:contain;display:block}
.jthumb.empty-thumb{opacity:.35}
.job:hover{color:var(--text)}
/* the open job is marked with a caret, matching the active-tab treatment */
.job.is-open{color:var(--text)}
.job.is-open .jprompt::before{content:"› "}
.job.is-open .jthumb{opacity:1}
.job .jprompt{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:inherit}
.job .jstat{font-size:11px;color:var(--faint);white-space:nowrap}
.job .blocks{flex:none;font-size:11.5px}

.dl{margin-left:auto;font-size:10.5px;text-decoration:none;color:var(--faint);
  text-transform:uppercase;letter-spacing:.12em}
.dl::before{content:"↓ "}
.dl:hover{color:var(--text)}

.empty{color:var(--dim);font-size:11.5px;padding:16px 0;margin:0}

/* ---------- small screens ---------- */
/* Phones: monitor renders + top up credit. The workspace and farm are
   desktop surfaces — picking matte points needs a big screen and a mouse. */
@media(max-width:700px){
  /* Admin stays reachable on a phone — handing out invite QRs at an event
     IS a mobile job. Workspace and Farm remain desktop-only. */
  #tabWork,#tabFarm,#farmPulse{display:none !important}
  #gpuStopBtn{display:none !important}
  /* balance is the number that matters on the move; frames delivered is not */
  .meters .stat:first-child{display:none}
  /* touch targets */
  .topups{gap:10px}
  .topups .topup{font-size:14px;padding:12px 6px;flex:1 1 40%}
  .transport{gap:10px}
  .transport .ghost,.transport .play{font-size:14px;padding:6px 2px}
  .framebar{height:22px}
  .job{padding:8px 0}
  .jstat{font-size:11px}
  .tablewrap{margin:0 -14px;padding:0 14px}
}
@media(max-width:560px){
  .bar{padding:12px 14px 8px;gap:10px}
  .acct{gap:12px}
  .meters{gap:12px}
  .acct .user{display:none}
  .tabs{padding:2px 14px 12px;gap:18px}
  .app,.farm{padding:6px 14px 50px}
  .login-inner h1{font-size:13px;letter-spacing:.28em}
  .gallery{grid-template-columns:repeat(auto-fill,minmax(84px,1fr))}
  .actions{flex-wrap:wrap;gap:14px}
  .actions .primary{margin-left:0}
}

@media (prefers-reduced-motion: reduce){
  *{animation:none !important;transition:none !important}
}

/* ---------- login fields ---------- */
/* Solid bars rather than underlines: they read as inputs against the hero
   above them, which an underline alone does not. Always dark, so the text
   inside is pinned light in both themes. */
/* the form is over an always-dark clip, so its text does not follow the
   theme tokens the rest of the app uses */
.login label{color:#8f8f8f}
.login .primary{color:#fff}
.login .primary::before,.login .primary::after{color:#666}
.login .err{color:#fff}
.login input[type=text],.login input[type=password],.login input{
  background:#0d0d0d;color:#fff;
  border:1px solid #242424;border-bottom:1px solid #242424;
  padding:10px 11px;
}
.login input::placeholder{color:#4a4a4a}
.login input:focus{outline:none;border-color:#6e6e6e;border-bottom-color:#6e6e6e}
/* Chrome paints its own background on autofilled fields; the inset shadow is
   the only way to keep the bar black. */
.login input:-webkit-autofill,
.login input:-webkit-autofill:hover,
.login input:-webkit-autofill:focus{
  -webkit-text-fill-color:#fff;
  -webkit-box-shadow:0 0 0 1000px #0d0d0d inset;
  caret-color:#fff;
}

/* ---------- request invite ---------- */
.loginrow{display:flex;align-items:center;justify-content:space-between;
  gap:16px;margin-top:6px}
.loginrow .ghost{color:#8f8f8f}
.loginrow .ghost:hover{color:#fff}
#askForm{display:flex;flex-direction:column;gap:14px}
.asksent{color:#cfcfcf;font-size:11.5px;line-height:1.7;margin:0;text-align:center}

/* Admin button in the header carries the same active mark as a tab */
.acct .ghost.is-on{color:var(--text)}
.acct .ghost.is-on::before{content:"[ "}
.acct #tabAdmin{margin-right:4px}

/* ---------- workspace help ---------- */
.help{margin-top:30px}
.help summary{cursor:pointer;list-style:none;font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--dim);user-select:none}
.help summary::-webkit-details-marker{display:none}
.help summary::before{content:"[ + ] "}
.help[open] summary::before{content:"[ − ] "}
.help summary:hover{color:var(--text)}
.help-body{margin-top:12px;font-size:11px;line-height:1.75;color:var(--muted);
  max-width:48ch}
.help-body p{margin:0 0 11px}
.help-body b{font-weight:400;color:var(--text)}
.help-body code{color:var(--text);border:1px solid var(--dim);padding:0 4px}

/* ---------- jobs settings sidebar ---------- */
.results.with-side{display:grid;grid-template-columns:230px minmax(0,1fr);
  gap:40px;align-items:start}
/* Open job on desktop: pinned like the workspace — the frame fills the free
   height, the transport sits under it, and the other jobs become a compact
   bar along the bottom that scrolls on its own. */
@media(min-width:901px){
  /* the roomy bottom padding belongs to the scrolling list; pinned mode
     needs the room */
  #jobsView.jobs:has(.results.with-side){padding-bottom:8px}
  #jobsView .results.with-side{height:var(--wsh, auto);overflow:hidden;
    align-items:stretch}
  #jobsView .with-side .jobside{overflow-y:auto;scrollbar-width:thin;
    scrollbar-color:var(--dim) transparent}
  #jobsView .with-side .jobmain{height:100%;display:flex;flex-direction:column;
    min-width:0;min-height:0}
  #jobsView .with-side .player{flex:1;min-height:0;display:flex;
    flex-direction:column;margin-bottom:12px}
  #jobsView .with-side .stage{flex:1;min-height:120px;display:grid;
    place-items:center}
  #jobsView .with-side .stage img{max-height:var(--pstageh, 74vh)}
  /* grid view fills the same slot and scrolls inside itself */
  #jobsView .with-side .gallery{flex:1;min-height:0;overflow-y:auto;
    margin-bottom:12px;scrollbar-width:thin;scrollbar-color:var(--dim) transparent}
  #jobsView .with-side .joblist{flex:none;max-height:170px;overflow-y:auto;
    margin-top:auto;padding-top:10px;border-top:1px solid var(--dim);
    scrollbar-width:thin;scrollbar-color:var(--dim) transparent}
  #jobsView .with-side .joblist::-webkit-scrollbar,
  #jobsView .with-side .gallery::-webkit-scrollbar{width:6px}
  #jobsView .with-side .joblist::-webkit-scrollbar-thumb,
  #jobsView .with-side .gallery::-webkit-scrollbar-thumb{background:var(--dim)}
}
/* clicking the job's name in the header closes it, so say so with the cursor */
#resultsTitle{cursor:default}
.with-side #resultsTitle{cursor:pointer;text-decoration:underline;
  text-underline-offset:4px;text-decoration-color:var(--dim)}
.with-side #resultsTitle:hover{text-decoration-color:var(--text)}
.jobside h3{margin:0 0 14px;font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--dim);font-weight:400}
.jobside .strip{padding:3px 0}
.jobside .v{max-width:14ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.jobside .ghost.block{display:block;width:100%;margin-top:18px;text-align:center}
.jobside .hint{margin-top:10px;font-size:10.5px;line-height:1.6}
@media(max-width:700px){
  /* phones: content first, settings after — the render is what you came for */
  .results.with-side{display:flex;flex-direction:column}
  .jobside{order:2;margin-top:26px}
}

/* centered live status over the empty stage while a job renders */
.stage-status{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  text-align:center; padding:20px; pointer-events:none;
  font-size:15px; letter-spacing:.06em; color:var(--ink, #d7ddd9);
  text-transform:uppercase; background:rgba(0,0,0,.45); z-index:4;
  /* glow lives on the words, not the backdrop — pulsing the whole overlay
     would make the footage behind it appear to flicker */
  animation:textglow 2.4s ease-in-out infinite;
}
.stage-status::after{content:""; animation:dots 1.5s steps(4,end) infinite}
@keyframes dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}

/* Primary drop target on the empty workspace stage */
.stagedrop{
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:6px; text-align:center; height:var(--stageh, 60vh); min-height:280px;
  border:1px dashed var(--line); background:var(--panel);
  transition:background .12s ease, border-color .12s ease;
}
.stagedrop[hidden]{display:none !important}
.stagedrop.hot{border-color:var(--acc); background:var(--panel2)}
.stagedrop .sd-main{margin:2px 0 0; font-size:19px; letter-spacing:.02em}
.stagedrop .sd-sub{margin:0; color:var(--mut); font-size:14px}
.stagedrop .hint{margin-top:10px}
.drop-icon.big{width:52px; height:52px; opacity:.5}

/* what the last click grabbed — a tinted fill over the detected object */
.ovseg{
  position:absolute; inset:0; pointer-events:none; z-index:3;
  background:var(--acc, #58c08a); opacity:0;
  transition:opacity .12s ease;
  /* a selection marker, not a matte: lighter than the preview overlay so it
     never reads as 'this is the edge quality you are getting' */
  -webkit-mask-size:100% 100%; mask-size:100% 100%;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  /* the detection PNG is grayscale with NO alpha channel, so the mask must be
     read by luminance — by alpha it is opaque everywhere and tints the whole
     frame instead of the object */
  mask-mode:luminance; -webkit-mask-source-type:luminance;
  mix-blend-mode:screen;
}
.segbusy{
  position:absolute; left:8px; bottom:8px; z-index:5;
  font-size:11px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--acc, #58c08a); background:rgba(0,0,0,.55); padding:3px 8px;
}

.segnote{
  position:absolute; right:8px; bottom:8px; z-index:5;
  font-size:10.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--mut, #8a938e); background:rgba(0,0,0,.5); padding:3px 8px;
}

/* public links under the sign-in card: what we sell, on what terms — reachable
   without an account, for customers and for payment-provider review */
.legalrow{
  position:fixed; left:50%; bottom:8px; transform:translateX(-50%);
  z-index:1; margin:0; white-space:nowrap;
  font-size:10px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--faint);
}
.legalrow a{color:var(--faint); text-decoration:none}
.legalrow a:hover{color:var(--acc)}

/* free-form top-up amount, sitting inline with the preset buttons */
.topcustom{display:inline-flex; align-items:center; gap:0; margin-left:6px}
.topcustom .cur{
  border:1px solid var(--line); border-right:0; padding:0 8px;
  height:34px; display:flex; align-items:center; color:var(--mut); font-size:13px;
  background:var(--panel);
}
.topcustom input{
  width:82px; height:34px; background:#000; color:var(--ink);
  border:1px solid var(--line); border-right:0; padding:0 8px;
  font-family:var(--mono); font-size:13px;
}
.topcustom input::-webkit-outer-spin-button,
.topcustom input::-webkit-inner-spin-button{-webkit-appearance:none; margin:0}
.topcustom input[type=number]{-moz-appearance:textfield}
.topcustom button{height:34px}

/* drag-drawn selection box: the committed one, and the live rubber band */
.pkbox, .pkrubber{position:absolute; pointer-events:none; z-index:4}
.pkbox{border:1px solid var(--acc, #58c08a); box-shadow:0 0 0 1px rgba(0,0,0,.55)}
.pkbox::after{
  content:""; position:absolute; inset:0;
  background:var(--acc, #58c08a); opacity:.08;
}
.pkrubber{border:1px dashed var(--acc, #58c08a); background:rgba(88,192,138,.10)}

/* Deploy landed under an open tab — say so instead of failing mysteriously. */
#staleBar {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  z-index: 9999; background: var(--panel, #161616); color: var(--fg, #e8e8e8);
  border: 1px solid var(--line, #333); border-radius: 4px;
  padding: 10px 14px; font-size: 12px; letter-spacing: .02em;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .5);
}
#staleBar button {
  background: none; border: 1px solid currentColor; color: inherit;
  border-radius: 3px; padding: 2px 8px; margin: 0 2px; cursor: pointer;
  font: inherit;
}
#staleBar button:hover { background: rgba(255, 255, 255, .08); }

/* Engine coming online — a rotoscope vignette, informative, never blocking. */
.bpcard {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 9998; pointer-events: none;
  width: min(420px, 86vw); padding: 28px 24px 22px; text-align: center;
  background: color-mix(in srgb, var(--bg, #0a0a0a) 88%, transparent);
  color: var(--fg, #e8e8e8);
  border: 1px solid var(--line, #333); border-radius: 6px;
  box-shadow: 0 12px 48px rgba(0, 0, 0, .65);
  backdrop-filter: blur(3px);
  font-family: inherit;
}
.bpcard svg { width: 200px; height: 118px; display: block; margin: 0 auto 14px; }
/* the subject: fills like the matte overlay does, breathing while we wait */
.bpcard .bp-blob {
  fill: var(--acc, #58c08a); fill-opacity: .28;
  stroke: var(--acc, #58c08a); stroke-width: 1.5;
  animation: bp-breathe 2.4s ease-in-out infinite;
}
/* the selection: classic marching ants around it */
.bpcard .bp-ants {
  fill: none; stroke: var(--fg, #e8e8e8); stroke-opacity: .7;
  stroke-width: 1; stroke-dasharray: 6 5;
  animation: bp-ants .8s linear infinite;
}
/* the scanline sweeping the frame top to bottom */
.bpcard .bp-scan {
  stroke: var(--acc, #58c08a); stroke-width: 1.5; stroke-opacity: .85;
  animation: bp-scan 2.8s linear infinite;
}
.bpcard .bp-title {
  font-size: 13px; letter-spacing: .28em; margin-bottom: 4px;
}
.bpcard .bp-eta {
  font-size: 26px; letter-spacing: .06em; min-height: 32px;
  color: var(--acc, #58c08a);
}
.bpcard .bp-note {
  font-size: 11px; letter-spacing: .05em; opacity: .55; margin-top: 6px;
}
.bpcard.ready { border-color: var(--acc, #58c08a); }
.bpcard.ready .bp-title { color: var(--acc, #58c08a); }
.bpcard.ready .bp-blob { animation: none; fill-opacity: .45; }
.bpcard.ready .bp-ants { animation: none; stroke: var(--acc, #58c08a); stroke-dasharray: none; }
.bpcard.ready .bp-scan { display: none; }
@keyframes bp-breathe { 50% { fill-opacity: .1 } }
@keyframes bp-ants { to { stroke-dashoffset: -11 } }
@keyframes bp-scan {
  0% { transform: translateY(12px); opacity: 0 }
  8% { opacity: .85 }
  92% { opacity: .85 }
  100% { transform: translateY(118px); opacity: 0 }
}

/* The entry gate: the workspace stays behind this until the engine answers. */
#bootGate {
  /* top is set from the nav's real height in bootGateSync() */
  position: fixed; left: 0; right: 0; bottom: 0; top: 0; z-index: 9997;
  background: color-mix(in srgb, var(--bg, #0a0a0a) 96%, transparent);
  backdrop-filter: blur(6px);
  opacity: 1; transition: opacity .6s ease;
}
#bootGate.out { opacity: 0; pointer-events: none; }
/* inside the gate the card needs no chrome of its own — the gate is the room */
#bootGate .bpcard {
  background: none; border: none; box-shadow: none; backdrop-filter: none;
  pointer-events: auto;              /* the escape hatch must be clickable */
}
#bootGate .bp-hatch {
  display: block; margin: 18px auto 0; background: none;
  border: 1px solid var(--line, #333); border-radius: 3px;
  color: var(--fg, #e8e8e8); opacity: .7; cursor: pointer;
  padding: 6px 14px; font: inherit; font-size: 11px; letter-spacing: .08em;
}
#bootGate .bp-hatch:hover { opacity: 1; border-color: var(--acc, #58c08a); }

/* Gate as dropzone: light up while footage hovers over it. */
#bootGate.hot { outline: 1px dashed var(--acc, #58c08a); outline-offset: -10px; }
#bootGate.hot .bpcard .bp-ants { stroke: var(--acc, #58c08a); }

/* Resting state: the vignette holds its breath until the person is back. */
#bootGate.resume { cursor: pointer; }
.bpcard.asleep .bp-ants { animation: none; stroke-opacity: .3; }
.bpcard.asleep .bp-scan { display: none; }
.bpcard.asleep .bp-blob { animation: bp-breathe 6s ease-in-out infinite; fill-opacity: .14; }
.bpcard.asleep .bp-title { opacity: .6; }
.bpcard.asleep .bp-eta { font-size: 15px; letter-spacing: .18em; text-transform: uppercase; }

/* Footage held over the gate: the whole vignette leans in. */
#bootGate.hot .bpcard { transform: translate(-50%, -50%) scale(1.05); transition: transform .15s ease; }
#bootGate.hot .bp-ants { animation-duration: .25s; }
#bootGate.hot .bp-blob { fill-opacity: .5; animation: none; }
#bootGate.hot .bp-title { color: var(--acc, #58c08a); }

/* The extraction card runs its scanline fast — work is visibly happening. */
#extractCard { z-index: 9999; }
#extractCard .bp-scan { animation-duration: 1.1s; }
#extractCard .bp-ants { animation-duration: .4s; }

/* The deliberate way in: a cold GPU starts on a press, not on a page load. */
.bpcard .bp-start {
  display: block; margin: 10px auto 4px; background: none; cursor: pointer;
  border: 1px solid var(--acc, #58c08a); border-radius: 3px;
  color: var(--acc, #58c08a); padding: 10px 22px;
  font: inherit; font-size: 13px; letter-spacing: .18em;
}
.bpcard .bp-start:hover { background: rgba(88, 192, 138, .08); }
#bootGate.start { cursor: default; }

/* iOS zooms the whole page onto any focused control smaller than 16px and
   stays zoomed afterwards — the "request access is zoomed in" report
   (2026-08-26). 16px on touch-sized screens ends that; desktop keeps 13px. */
@media (max-width: 700px) {
  .login input, .login textarea, .login select { font-size: 16px; }
}

/* Admin invite links: rows are tap targets, the QR fills the phone screen. */
.advrow { margin: 0 0 10px; }
.adv-row { cursor: pointer; }
.adv-row td { padding-top: 12px; padding-bottom: 12px; }
.adv-row.used { color: var(--faint); cursor: default; }
#qrOverlay {
  position: fixed; inset: 0; z-index: 9999; background: #ffffff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
#qrOverlay .qr-card { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 24px; }
#qrOverlay img { width: min(78vw, 420px); height: min(78vw, 420px); display: block; }
#qrOverlay .qr-code { font-size: 15px; letter-spacing: .12em; color: #0a0a0a; }
#qrOverlay .qr-note { font-size: 11px; letter-spacing: .05em; color: #8a8a8a; }

/* Recovery affordances on the login card. */
.login .forgot { margin-top: 10px; opacity: .55; }
.login .forgot:hover { opacity: 1; }
.notifyrow { margin-top: 6px; }

/* Per-link credit control beside the invite button. */
.advrow { display: flex; align-items: end; gap: 14px; flex-wrap: wrap; }
.advcredit input { width: 90px; }

/* ============================================================
   THEME 2 — "studio" skin (beta)
   Slapshot-style dark app chrome with due.-style card polish.
   Pure override layer: every selector below restyles existing
   structure; layout mechanics and JS hooks stay untouched.
   ============================================================ */

:root{
  --bg:#0b0b0f;
  --text:#ececf1;
  --muted:#a0a0ab;
  --faint:#6a6a76;
  --dim:#33333c;
  --acc:#46d392;
  --acc-ink:#07271a;
  --acc-soft:rgba(70,211,146,.12);
  --panel:#141419;
  --panel2:#1b1b22;
  --line:rgba(255,255,255,.07);
  --mut:var(--muted);
  --ink:var(--text);
  --chk-a:#101014; --chk-b:#17171d;
  --r-card:14px; --r-ctl:10px;
  --shadow:0 10px 32px rgba(0,0,0,.45);
}
body{
  background:
    radial-gradient(1100px 500px at 75% -200px, rgba(70,211,146,.05), transparent 60%),
    var(--bg);
  font-size:13.5px;
}

/* ---------- chrome: header + tab pills ---------- */
.bar{padding:16px 24px 12px}
.brand{font-size:13px}
.badge{border:1px solid var(--line);border-radius:999px;padding:4px 12px;
  background:var(--panel)}
.badge::before{content:""}
.badge.ok{color:var(--acc);border-color:rgba(70,211,146,.35)}
.badge.bad{color:#ff7a6e}
.tabs{gap:8px;padding:4px 24px 16px}
.tab{padding:7px 16px;border-radius:999px;color:var(--faint);
  letter-spacing:.1em;transition:background .12s,color .12s}
.tab:hover{color:var(--text);background:var(--panel)}
.tab.is-on{color:var(--text);background:var(--panel2);
  box-shadow:inset 0 0 0 1px var(--line)}
.tab.is-on::before{content:none}
.acct #tabAdmin{border:1px solid var(--line);border-radius:999px;padding:5px 13px}
.acct .ghost.is-on{background:var(--panel2)}
.acct .ghost.is-on::before{content:none}

/* ---------- buttons: pills, one green primary ---------- */
button.ghost,button.primary{border-radius:999px;transition:all .13s ease}
button.ghost::before,button.ghost::after,
button.primary::before,button.primary::after{content:none}
button.primary{
  background:var(--acc);color:var(--acc-ink);font-weight:600;
  padding:9px 20px;letter-spacing:.08em;
}
button.primary:hover:not(:disabled){color:var(--acc-ink);
  filter:brightness(1.08);transform:translateY(-1px);
  box-shadow:0 6px 18px rgba(70,211,146,.25)}
button.primary:disabled{background:var(--dim);color:var(--faint)}
button.ghost{
  background:var(--panel);color:var(--muted);padding:8px 16px;
  box-shadow:inset 0 0 0 1px var(--line);
}
button.ghost:hover{background:var(--panel2);color:var(--text)}
button.ghost:disabled{background:transparent;color:var(--dim)}
button.ghost.small{padding:5px 12px;font-size:10px}
button.link{background:none;box-shadow:none;padding:0;border-radius:0}

/* ---------- inputs: filled, rounded, ring focus ---------- */
input:not([type]),input[type=text],input[type=password],input[type=email],
input[type=number],#prompt{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-ctl);
  padding:9px 12px;font-family:var(--font);
}
input:focus,#prompt:focus{outline:none;border-color:rgba(70,211,146,.5);
  box-shadow:0 0 0 3px var(--acc-soft)}
input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus{
  -webkit-box-shadow:0 0 0 1000px var(--panel) inset}
input[type=checkbox],input[type=radio]{accent-color:var(--acc)}
input[type=range]{accent-color:var(--acc)}
select.pick{background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-ctl);padding:8px 12px;font-family:var(--font)}
select.pick:focus{border-color:rgba(70,211,146,.5)}
select.pick option,.fps option{background:var(--panel)}

/* ---------- section headers: sentence case, real hierarchy ---------- */
h1,h2{text-transform:none;letter-spacing:.02em;font-size:17px;font-weight:600;
  color:var(--text)}
.scores-head{margin-bottom:16px;align-items:center}
.panel-note{color:var(--faint)}
.jobside h3,.preview-label,.field-label,label,.ifield .k{color:var(--faint)}

/* ---------- cards where the eye rests ---------- */
.stripbar{gap:14px;margin-bottom:30px}
.stripbar .strip{
  flex-direction:column;align-items:flex-start;gap:6px;
  background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-card);padding:16px 18px;
}
.stripbar .strip .k{color:var(--faint)}
.stripbar .strip .v{margin-left:0;font-size:21px;font-weight:600;color:var(--text)}
.stripbar .strip .v.on{color:var(--acc)}
.mustset,.newcode{background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-card);padding:16px 18px}
.newcode code{color:var(--acc)}
.stagedrop{border-radius:var(--r-card)}
.pickstage,.stage{border-radius:var(--r-card)}
.checker{border-radius:var(--r-ctl)}
.gallery .cell{border-radius:8px}
.jthumb{border-radius:6px}

/* jobs list: rows become soft cards, open row stays lifted */
.joblist{gap:6px}
.job{padding:9px 12px;border-radius:var(--r-ctl);border:1px solid transparent}
.job:hover{background:var(--panel)}
.job.is-open{background:var(--panel2);border-color:var(--line)}
.job.is-open .jprompt::before{content:none}
.jthumb{width:30px;height:30px}

/* tables: airier, hairline rows */
.ledger td,.dl-table td{padding-top:8px;padding-bottom:8px;
  border-bottom:1px solid var(--line)}
.ledger tbody tr:last-child td,.dl-table tbody tr:last-child td{border-bottom:0}
.dl-table thead th,.ledger th{padding-bottom:10px;color:var(--faint)}

/* ---------- status chips ---------- */
.pill{border-radius:999px;padding:3px 10px;background:var(--panel);
  box-shadow:inset 0 0 0 1px var(--line);font-size:10px}
.pill.running{background:var(--acc-soft);color:var(--acc);
  box-shadow:inset 0 0 0 1px rgba(70,211,146,.35)}
.pill.done{color:var(--muted)}
.pill.error{background:rgba(255,122,110,.1);color:#ff7a6e;
  box-shadow:inset 0 0 0 1px rgba(255,122,110,.3)}
.pill.queued,.pill.uploading,.pill.paused{color:var(--muted)}

/* framebar reads green for delivered */
.framebar{height:16px;border-radius:4px;overflow:hidden}
.framebar i[data-s="ok"]{background:var(--acc)}
@keyframes framepulse{0%,49%{background:var(--acc)}50%,100%{background:var(--dim)}}
.tl-keys b.pos{background:var(--acc)}
.tl-head{background:var(--acc)}
.tl-head::before{border-top-color:var(--acc)}
.blocks{color:var(--acc)}

/* ---------- workspace controls column gets a home ---------- */
@media(min-width:901px){
  #appView .workctl{background:var(--panel);border:1px solid var(--line);
    border-radius:var(--r-card);padding:18px 18px 22px}
}
.help-body code{border-radius:5px;border-color:var(--line)}
[data-tip]:hover::after{background:var(--panel2);border:1px solid var(--line);
  border-radius:var(--r-ctl);box-shadow:var(--shadow)}

/* ---------- wallet ---------- */
.topups .topup{background:var(--panel);box-shadow:inset 0 0 0 1px var(--line);
  border-radius:var(--r-ctl);padding:12px 20px}
.topups .topup:hover{background:var(--panel2)}
.lninv{border-radius:var(--r-ctl);border-color:var(--line);background:var(--panel)}

/* ---------- login: keep the cinema, round the furniture ---------- */
.login input[type=text],.login input[type=password],.login input{
  background:rgba(10,10,12,.82);border:1px solid rgba(255,255,255,.1);
  border-radius:var(--r-ctl);backdrop-filter:blur(6px)}
.login input:focus{border-color:rgba(70,211,146,.55);
  box-shadow:0 0 0 3px var(--acc-soft)}
.login .primary{background:var(--acc);color:var(--acc-ink)}
.login .primary:hover{color:var(--acc-ink)}
.login .loginrow .ghost{background:rgba(255,255,255,.06);color:#cfcfcf}
/* quiet text link, not a full-width bar */
.login .forgot{background:none;box-shadow:none;width:auto;
  align-self:center;color:#8f8f8f}
.login .forgot:hover{background:none;color:#fff}

/* boot gate and vignette inherit the theme tokens (already var-driven) */
#bootGate{background:color-mix(in srgb, var(--bg) 90%, transparent)}
.bpcard{border-radius:var(--r-card)}

/* scrollbars everywhere, quiet */
*{scrollbar-width:thin;scrollbar-color:var(--dim) transparent}
*::-webkit-scrollbar{width:8px;height:8px}
*::-webkit-scrollbar-thumb{background:var(--dim);border-radius:99px}
*::-webkit-scrollbar-track{background:transparent}

/* ---------- snackbar ---------- */
#snacks{
  position:fixed;left:50%;bottom:22px;transform:translateX(-50%);
  z-index:10000;display:flex;flex-direction:column;gap:8px;
  width:min(440px,calc(100vw - 32px));pointer-events:none;
}
.snack{
  display:flex;align-items:center;gap:12px;pointer-events:auto;
  background:var(--panel2);border:1px solid var(--line);
  border-radius:var(--r-ctl);padding:11px 12px 11px 16px;
  box-shadow:var(--shadow);font-size:12.5px;color:var(--text);
  animation:snackin .18s ease;
}
@keyframes snackin{from{opacity:0;transform:translateY(8px)}}
.snack.out{opacity:0;transform:translateY(6px);
  transition:opacity .22s ease,transform .22s ease}
.snack.error{border-color:rgba(255,122,110,.35)}
.snack.error::before{content:"";width:3px;align-self:stretch;flex:none;
  border-radius:99px;background:#ff7a6e;margin-left:-6px}
.snack.ok::before{content:"";width:3px;align-self:stretch;flex:none;
  border-radius:99px;background:var(--acc);margin-left:-6px}
.snack-msg{flex:1;line-height:1.5}
.snack-act{background:none;border:0;color:var(--acc);font:inherit;
  font-weight:600;letter-spacing:.04em;cursor:pointer;padding:4px 6px;
  border-radius:6px;flex:none}
.snack-act:hover{background:var(--acc-soft)}
.snack-x{background:none;border:0;color:var(--faint);font-size:15px;
  cursor:pointer;padding:2px 6px;flex:none;line-height:1}
.snack-x:hover{color:var(--text)}
