/* 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;
  --font:var(--mono);
  /* 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(--mono);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}}

/* ---------- 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:start;
  min-height:100vh;min-height:var(--vph,100dvh);padding:20px;box-sizing:border-box}
.login-inner{margin-top:clamp(24px,calc(var(--vph,100dvh)*.72),calc(var(--vph,100dvh) - 205px))}
/* 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:blink 1.1s steps(1,end) 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;
  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){
  #tabWork,#tabFarm,#tabAdmin,#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}
}
