:root{
  --bg:#0e1014; --bg2:#15181d; --surface:#1a1e24; --surface2:#1f242b;
  --line:#626b76; --line2:#737e8a;
  --ink:#e7e3d8; --ink2:#b9bbb3; --ink3:#9ba3ad;
  --copper:#d2813a; --amber:#f2a94e; --ember:#ffb869; --copper-d:#7a4d23;
  --teal:#3fb6a0; --teal-d:#1d4a44;
  --danger:#e06a5e; --danger-d:#5a2622;
  --r:8px;
  --glow:0 0 14px rgba(242,169,78,.32);
  --focus:#ffd08a;
  --target:44px;
  --compact-target:28px;
  --space-sm:8px;
  --card-inset:14px;
  --dialog-gutter:16px;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{background:var(--bg);color:var(--ink);font-family:"Chakra Petch",sans-serif}
body{
  min-height:100vh;
  background-image:
    radial-gradient(1100px 600px at 82% -12%, rgba(242,169,78,.12), transparent 60%),
    radial-gradient(800px 500px at -10% 105%, rgba(210,129,58,.07), transparent 60%),
    linear-gradient(var(--line) .6px, transparent .6px),
    linear-gradient(90deg, var(--line) .6px, transparent .6px);
  background-size:auto, auto, 38px 38px, 38px 38px;
  background-position:0 0, 0 0, -1px -1px, -1px -1px;
  background-blend-mode:normal, normal, soft-light, soft-light;
}
body::before{
  content:"";position:fixed;inset:0;pointer-events:none;z-index:0;
  background:radial-gradient(circle at 50% 0%, transparent 70%, rgba(0,0,0,.4) 100%);
  mix-blend-mode:multiply;
}
.skip-link{position:fixed;top:8px;left:8px;z-index:1000;padding:10px 14px;border:2px solid var(--focus);
  border-radius:6px;background:var(--bg);color:var(--ink);font-weight:700;transform:translateY(-160%)}
.skip-link:focus{transform:translateY(0)}
#plannerMain:focus{outline:3px solid var(--focus);outline-offset:3px}
:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
.wrap{position:relative;z-index:1}
.mono{font-family:"JetBrains Mono",monospace}
.wrap{max-width:1240px;margin:0 auto;padding:24px 20px 64px}
@media(max-width:560px){
  .wrap{padding:18px 12px 48px}
  .brand h1{font-size:34px;letter-spacing:1.2px}
  button.btn{padding:8px 10px;font-size:11.5px}
}
header.top{display:flex;align-items:center;justify-content:space-between;gap:12px 28px;flex-wrap:wrap;
  border-bottom:1px solid var(--line);padding-bottom:14px;margin-bottom:18px;position:relative}
.brand{flex:1 1 360px;min-width:0}
header.top::after{
  content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;
  background:linear-gradient(90deg,transparent,var(--copper),transparent);opacity:.55;
}
.brand h1{
  font-family:"Big Shoulders Stencil Display","Chakra Petch",sans-serif;
  font-weight:800;font-size:42px;letter-spacing:2px;line-height:.95;
  text-transform:uppercase;display:flex;align-items:center;gap:2px;
}
.brand h1 .spark{
  color:var(--ember);margin:0 4px;
  text-shadow:0 0 16px rgba(255,184,105,.7), 0 0 32px rgba(210,129,58,.35);
  animation:ember 2.6s ease-in-out infinite;
}
@keyframes ember{
  0%,100%{opacity:1;filter:drop-shadow(0 0 6px rgba(255,184,105,.5))}
  50%{opacity:.78;filter:drop-shadow(0 0 2px rgba(255,184,105,.25))}
}
.brand p{color:var(--ink2);font-size:13px;letter-spacing:.3px;max-width:62ch}
/* tagline and the contribute link share one row so the brand block stays two lines tall */
.brand-sub{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 16px;margin-top:6px}
/* shrink-but-never-grow: the tagline keeps its own line-length beside the disclosure on
   wide headers, and still wraps inside the brand column instead of overflowing it. */
.brand .tagline{color:var(--ink2);font-size:13.5px;max-width:none;margin:0;flex:0 1 auto;min-width:0}
/* The report form opens in a dialog rather than expanding here: at full size it pushed
   the whole planner down the page, and the header must stay two lines tall. */
.contrib-open{appearance:none;background:transparent;border:0;padding:0;cursor:pointer;margin:0;
  font-family:"Chakra Petch",sans-serif;font-size:12.5px;color:var(--amber);letter-spacing:.3px;
  display:inline-flex;align-items:center;gap:6px;min-height:24px;text-align:left}
.contrib-open::after{content:"\2197";font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--ink3)}
.contrib-open:hover{color:var(--ember)}
.contrib-open:hover::after{color:var(--ember)}

/* Report form — two submit paths over one set of fields, inside the report dialog. */
.contrib-form{display:flex;flex-direction:column;gap:10px;margin-top:12px}
.contrib-field{display:flex;flex-direction:column;gap:4px;min-width:0}
.contrib-field label{color:var(--ink2);font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}
.contrib-optional{color:var(--ink3);font-weight:400;text-transform:none;letter-spacing:.2px}
.contrib-form textarea{font-family:"JetBrains Mono",monospace;font-size:12.5px;
  background:var(--surface2);color:var(--ink);border:1px solid var(--line2);border-radius:5px;
  padding:7px 9px;width:100%;line-height:1.45;resize:vertical;min-height:96px;
  transition:border-color .15s, box-shadow .15s}
.contrib-form textarea:hover{border-color:#454c57}
.contrib-form textarea:focus{border-color:var(--copper);
  box-shadow:0 0 0 2px rgba(210,129,58,.22), inset 0 0 0 1px rgba(242,169,78,.08)}
/* Honeypot: reachable by a script that fills every input, and by nothing else. Kept out
   of the layout without display:none, which some bots read as a field to skip. */
.contrib-trap{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.contrib-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:2px}
.contrib-actions .btn{flex:0 1 auto}
.contrib-actions .btn:disabled{opacity:.5;cursor:not-allowed;border-color:var(--line);color:var(--ink3);
  background:var(--surface);filter:none;box-shadow:none;transform:none}
.contrib-help{color:var(--ink3);font-size:11.5px;line-height:1.5}
.contrib-status{font-size:12px;font-weight:600;min-height:1em;color:var(--ink2)}
.contrib-status.is-bad{color:#ff9b90}
.contrib-status.is-good{color:var(--teal)}
.contrib-status a{color:var(--amber);text-decoration:underline;text-underline-offset:2px}

/* Input rail — the three dialogs that hold solver input read as one object,
   each segment reporting whether it has data. Settings sits outside it. */
.tools{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:8px 10px;position:relative;
  flex:0 0 auto;max-width:100%}
/* save status sits beside the rail, not on its own row — it is ambient, not a control */
.tools .saveind{order:0}
.rail{order:1;display:flex;align-items:stretch;border:1px solid var(--line2);border-radius:6px;
  background:var(--surface);overflow:hidden;max-width:100%}
.rail-seg{appearance:none;background:transparent;border:0;cursor:pointer;color:var(--ink);
  font-family:"Chakra Petch",sans-serif;text-align:left;padding:7px 14px 8px;min-height:var(--target);
  display:flex;flex-direction:column;gap:3px;justify-content:center;transition:background .15s,color .15s}
.rail-seg+.rail-seg{border-left:1px solid var(--line2)}
.rail-seg:hover{background:rgba(210,129,58,.08)}
.rail-seg:focus-visible{outline:3px solid var(--focus);outline-offset:-3px}
.rail-lbl{font-size:11.5px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;
  display:flex;align-items:center;gap:7px;white-space:nowrap}
.rail-dot{width:6px;height:6px;border-radius:50%;flex:0 0 auto;border:1px solid var(--line2);
  background:transparent;transition:background .2s,border-color .2s,box-shadow .2s}
.rail-seg.filled .rail-dot{background:var(--copper);border-color:var(--copper);box-shadow:0 0 8px rgba(242,169,78,.6)}
.rail-state{font-family:"JetBrains Mono",monospace;font-size:10px;letter-spacing:.3px;color:var(--ink3);
  white-space:nowrap;padding-left:13px;font-variant-numeric:tabular-nums}
.rail-seg.filled .rail-state{color:var(--ink2)}
.rail-warn{color:var(--amber);font-weight:500}
.rail-seg.needs{background:rgba(242,169,78,.07)}
.rail-seg.needs .rail-dot{border-color:var(--amber);box-shadow:0 0 0 3px rgba(242,169,78,.14)}
.tools button.btn.rail-aside{order:2;align-self:stretch}
button.btn{font-family:"Chakra Petch",sans-serif;font-weight:600;font-size:12px;letter-spacing:.6px;
  background:var(--surface);color:var(--ink);border:1px solid var(--line2);border-radius:6px;
  min-height:var(--target);padding:8px 13px;cursor:pointer;transition:.15s;display:inline-flex;align-items:center;gap:6px;
  text-transform:uppercase}
button.btn:hover{border-color:var(--copper);color:var(--amber);background:rgba(210,129,58,.06)}
button.btn:active{transform:scale(.97)}
button.btn.primary{
  background:linear-gradient(180deg,var(--ember),var(--copper) 60%,#a45a1f);
  border-color:var(--copper);color:#15110a;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18), 0 5px 14px rgba(210,129,58,.22), 0 0 0 1px rgba(242,169,78,.15);
}
button.btn.primary:hover{filter:brightness(1.08);color:#15110a;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), 0 7px 18px rgba(210,129,58,.32), 0 0 0 1px rgba(242,169,78,.28);}
button.btn.ghost{background:transparent}
/* Reserved for real pending actions, and only those: the stale-bar Resimulate button, and the
   Refresh button on the new-build notice. Nothing ambient may borrow it. */
@keyframes attentionPulse{0%,100%{box-shadow:0 0 0 0 rgba(242,169,78,.65)}50%{box-shadow:0 0 0 9px rgba(242,169,78,0)}}
.grid{display:grid;grid-template-columns:minmax(320px,380px) minmax(0,1fr);gap:18px;align-items:start}
@media(max-width:880px){.grid{grid-template-columns:minmax(0,1fr)}}
.grid > *{min-width:0}
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  transition:border-color .18s, box-shadow .18s;position:relative}
.card:hover{border-color:#343a44}
.card>.head{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:13px 16px;border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,var(--bg2),var(--surface));position:relative;
  border-top-left-radius:var(--r);border-top-right-radius:var(--r)}
.card>.head::after{
  content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;
  background:linear-gradient(90deg,transparent,var(--copper-d) 30%,var(--copper) 50%,var(--copper-d) 70%,transparent);
  opacity:.45;
}
.card>.head h2{font-size:13px;font-weight:700;letter-spacing:1.1px;text-transform:uppercase;color:var(--ink);
  display:flex;align-items:center;gap:8px}
.card>.head h2::before{
  content:"";width:6px;height:6px;border-radius:50%;background:var(--copper);
  box-shadow:0 0 8px rgba(242,169,78,.6);
}
.card>.head .sub{font-size:11.5px;color:var(--ink3);letter-spacing:.3px}
.card>.body,.card-body{padding:var(--card-inset)}
/* "results out of date" bar — shown when crafter-line inputs or the project selection change
   before a resolve */
.stale-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  margin:14px 14px 0;padding:9px 12px;border-radius:6px;
  background:rgba(210,129,58,.10);border:1px solid var(--copper-d)}
.stale-bar[hidden]{display:none}
.stale-msg{font-size:12px;font-weight:600;color:var(--amber);letter-spacing:.2px}
.stale-bar .btn{white-space:nowrap;animation:attentionPulse 1.15s ease-out infinite}
/* Dim the children rather than #results itself: the project on/off panel lives inside #results and
   is the control that made the plan stale, so it has to stay readable while everything it invalidated
   fades. Opacity on the container would take the panel down with it — a child cannot out-opaque its
   parent — which is why this is a child selector and not a shorter rule on #results. */
#results.stale>*{opacity:.42;filter:saturate(.55);transition:opacity .15s,filter .15s}
#results.stale>.proj-adjust{opacity:1;filter:none}

/* "new build shipped" notice — appears hours into a session, so it is pinned rather than
   placed in the flow where a scrolled-down reader would never see it. On a page this dark
   and this dense a quiet bar in the corner is a bar nobody reads, so it slides in, throws a
   few expanding rings to catch peripheral vision, then settles and leaves the pulse on
   Refresh alone. It sits under the modal layer (z-index 50), so an open dialog still wins. */
.update-bar{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);z-index:40;
  display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  width:min(560px,calc(100vw - 24px));padding:12px 15px;border-radius:var(--r);
  background:linear-gradient(180deg,var(--surface2),var(--surface));
  border:1px solid var(--amber);box-shadow:0 12px 30px rgba(0,0,0,.55),var(--glow);
  animation:updateArrive .3s ease-out, updateFlash 1.4s ease-out .3s 5}
.update-bar[hidden]{display:none}
.update-msg{flex:1;min-width:200px;font-size:12.5px;line-height:1.5;color:var(--ink);letter-spacing:.2px}
.update-msg b{color:var(--amber)}
.update-actions{display:flex;gap:8px;flex-wrap:wrap}
.update-actions .btn{white-space:nowrap}
#updateReload{animation:attentionPulse 1.15s ease-out infinite}
@keyframes updateArrive{from{transform:translate(-50%,150%)}to{transform:translate(-50%,0)}}
@keyframes updateFlash{
  0%,100%{box-shadow:0 12px 30px rgba(0,0,0,.55),0 0 0 0 rgba(242,169,78,.55)}
  50%{box-shadow:0 12px 30px rgba(0,0,0,.55),0 0 0 15px rgba(242,169,78,0)}
}
@media(max-width:560px){.update-actions{width:100%}.update-actions .btn{flex:1;justify-content:center}}
/* Motion is the attention-getter here, so without it the bar keeps the loudest static
   treatment available instead of quietly losing the thing that made it noticeable. */
@media(prefers-reduced-motion:reduce){
  .update-bar{animation:none;box-shadow:0 12px 30px rgba(0,0,0,.55),0 0 0 4px rgba(242,169,78,.28),var(--glow)}
  #updateReload{animation:none}
}

#results{min-width:0}
#results table{min-width:520px}
.stack{display:flex;flex-direction:column;gap:16px}

/* lines */
.globals{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px;margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid var(--line);align-items:end}
.globals .fl{display:flex;flex-direction:column;gap:3px;justify-content:flex-end;min-width:0}
.globals .fl span{font-size:9.5px;letter-spacing:.45px;text-transform:uppercase;color:var(--ink3);
  display:inline-flex;align-items:center;gap:4px;line-height:1.2;flex-wrap:wrap}
.globals .fl > input{min-height:var(--target)}

/* The card's two actions share the row under the table. The basis is the width of the longer
   label, so the pair breaks to a line each before either button is narrow enough to wrap its
   own text — a two-line button inside a 44px row is the one outcome worth spending a break on. */
.line-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}
.line-actions .btn{flex:1 1 145px;justify-content:center}
.line-actions .btn:disabled{opacity:.45;cursor:not-allowed;border-color:var(--line);color:var(--ink3);
  background:transparent;filter:none;box-shadow:none;transform:none}

/* Crafter lines table. Labels and help buttons live in the header row, so adding a
   line costs one 44px row instead of a card carrying its own copy of every label. */
.ltable{width:100%;border-collapse:collapse}
.ltable th{text-align:left;padding:0 6px 8px 0;vertical-align:bottom;font-weight:600}
.ltable td{padding:3px 6px 3px 0;vertical-align:top}
.ltable th:last-child,.ltable td:last-child{padding-right:0}
.lines-th{font-size:9.5px;letter-spacing:.45px;text-transform:uppercase;color:var(--ink3);
  display:inline-flex;align-items:center;gap:5px;line-height:1.25}
.lines-th-sr{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.ltable .col-n{width:32px}
.ltable .col-x{width:30px}
/* Number inputs carry a 20-character intrinsic width, so speed and turbo bid for the
   same space and the table splits it evenly: speed clips its five-figure values while
   turbo, which never runs past three digits, sits half empty. Releasing that floor and
   asking for the minimum on turbo hands the surplus to speed. Once the input lets go it
   is the heading that holds the column open, so turbo's help button drops under its
   label: one more line across the header row, paid once, against a wider speed field on
   every line below it. */
.ltable .col-turbo{width:48px}
.ltable .col-turbo .lines-th{flex-wrap:wrap;gap:0 5px}
.ltable td input[type=number]{min-width:0;padding-left:6px;padding-right:6px}
/* the line's validation text takes the whole row: a sentence naming a field, its range
   and the value still in force cannot be read a word at a time down a column three
   digits wide. The row divider moves down with it, so the message stays inside the band
   belonging to its line, and an error-free line costs no height. */
.ltable tr.line-row>td{border-bottom:0}
.ltable tr.line-errs>td{padding:0;border-bottom:1px solid var(--line)}
.ltable tbody tr.line-errs:last-child>td{border-bottom:0}
.ltable .tag{font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:700;
  color:var(--amber);letter-spacing:.3px;background:rgba(210,129,58,.08);
  border:1px solid var(--copper-d);border-radius:4px;
  display:flex;align-items:center;justify-content:center;min-height:var(--target)}
.ltable select,.ltable input[type=number]{min-height:var(--target)}
/* projected speed hangs off the entered speed: no column, no width cost, and only
   the rows actually below max turbo grow */
.line-proj{font-size:10px;color:var(--amber);letter-spacing:.2px;margin-top:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* the upgrade level behind the chosen multiplier, hung off the picker for the same
   reason: this column is only as wide as its heading, so "16.38k× (level 14)" cannot
   fit inside the closed select. Muted, because it restates the value above it. */
.line-lvl{font-size:10px;color:var(--ink3);letter-spacing:.2px;margin-top:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ltable .col-x .iconbtn{margin-top:8px}
.ltable tbody tr:hover .tag{background:rgba(210,129,58,.16);border-color:var(--copper)}

/* Below 560px a six-column table stops fitting, so each row folds back into a card.
   Same DOM, same handlers — only the layout changes. */
@media(max-width:560px){
  .ltable,.ltable tbody,.ltable tr,.ltable td{display:block}
  .ltable thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%)}
  .ltable tr{display:grid;
    grid-template-columns:30px minmax(0,1.15fr) minmax(0,1.15fr) minmax(0,.7fr) 28px;
    grid-template-areas:"tag cap spx turbo x";
    /* start, not end: a speed cell carrying a projection is taller, and bottom
       alignment would lift its label out of line with the others */
    gap:7px 8px;align-items:start;padding:8px;margin-bottom:7px;position:relative;
    border:1px solid var(--line);border-radius:7px;
    background:linear-gradient(180deg,var(--bg2),var(--surface2))}
  .ltable tr::before{content:"";position:absolute;left:-1px;top:8px;bottom:8px;width:2px;border-radius:2px;
    background:linear-gradient(180deg,var(--copper-d),var(--copper) 50%,var(--copper-d));opacity:.45}
  /* the errors are the card's own text, not a second card: they sit in the gap under it,
     and an empty row collapses into the card's margin rather than adding to it */
  .ltable tr.line-errs{display:block;padding:0 9px;margin-bottom:7px;
    border:0;border-radius:0;background:none}
  .ltable tr.line-errs::before{content:none}
  /* the card border is the divider here, so the row's own rule has nothing to separate */
  .ltable tr.line-errs>td{border-bottom:0}
  /* the card border already separates rows, so the global cell rule's divider has no job
     here — and once a cell carries a note under its control it lands as a stray underline */
  .ltable td{padding:0;border-bottom:0}
  .ltable .col-n{grid-area:tag;align-self:center}
  .ltable .col-cap{grid-area:cap}
  .ltable .col-spx{grid-area:spx}
  /* the card sizes turbo through the grid track, so drop the table's width hint */
  .ltable .col-turbo{grid-area:turbo;width:auto}
  .ltable .col-x{grid-area:x;align-self:center}
  /* reserve two lines for every label: "max compression" wraps and the others don't,
     so without this the controls start at different heights across one row */
  .ltable td[data-label]::before{content:attr(data-label);display:block;
    font-size:9.5px;letter-spacing:.45px;text-transform:uppercase;color:var(--ink3);
    line-height:1.25;margin-bottom:3px;min-height:2.5em}
}
/* Three fields stop fitting across a phone around here: the longest label needs more
   than a third of the card, so fold to two columns. */
@media(max-width:380px){
  .ltable tr{grid-template-columns:30px minmax(0,1fr) minmax(0,1fr) 28px;
    grid-template-areas:"tag cap spx x" "tag turbo turbo x"}
  .ltable .col-x .iconbtn{margin-top:0}
}
select,input[type=number],input[type=text]{font-family:"JetBrains Mono",monospace;font-size:12.5px;
  background:var(--surface2);color:var(--ink);border:1px solid var(--line2);border-radius:5px;
  padding:7px 9px;width:100%;transition:border-color .15s, box-shadow .15s;
  line-height:1.2;-webkit-appearance:none;appearance:none}
input[aria-invalid="true"],select[aria-invalid="true"]{border-color:var(--danger);box-shadow:0 0 0 1px rgba(224,106,94,.28)}
.field-stack{display:flex;flex-direction:column;gap:3px;min-width:0;max-width:100%}
.field-error{min-width:0;max-width:100%;color:#ff9b90;font-family:"Chakra Petch",sans-serif;font-size:10.5px;
  font-weight:600;line-height:1.35;letter-spacing:.1px;overflow-wrap:anywhere;text-transform:none}
/* hide number-input spinner arrows */
input[type=number]{-moz-appearance:textfield}
input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
select{appearance:none;-webkit-appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink3) 50%),linear-gradient(135deg,var(--ink3) 50%,transparent 50%);
  background-position:calc(100% - 14px) 50%, calc(100% - 9px) 50%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:24px}
select:hover,input[type=number]:hover,input[type=text]:hover{border-color:#454c57}
select:focus,input:focus{border-color:var(--copper);
  box-shadow:0 0 0 2px rgba(210,129,58,.22), inset 0 0 0 1px rgba(242,169,78,.08)}
.iconbtn{background:transparent;border:1px solid var(--line2);color:var(--ink3);border-radius:5px;
  width:var(--compact-target);height:var(--compact-target);cursor:pointer;font-size:16px;line-height:1;transition:.15s}
.iconbtn:hover{border-color:var(--danger);color:var(--danger);background:rgba(224,106,94,.07)}
.lvl-step{display:inline-flex;align-items:center;gap:5px}
.lvl-step .iconbtn{width:var(--compact-target);height:var(--compact-target);font-size:15px;color:var(--ink2)}
.lvl-step .iconbtn:hover{border-color:var(--teal);color:var(--teal);background:rgba(63,182,160,.08)}
.lvl-step .iconbtn:disabled{opacity:.35;cursor:default;border-color:var(--line);color:var(--ink3);background:transparent}

/* tooltip system */
.tip{display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border-radius:50%;padding:0;
  border:1px solid var(--line2);background:var(--bg2);
  color:var(--ink3);font-family:"JetBrains Mono",monospace;font-size:9px;font-weight:700;font-style:normal;
  cursor:help;position:relative;vertical-align:middle;line-height:1;
  transition:.15s;flex:0 0 auto;user-select:none;letter-spacing:0;text-transform:none}
.tip:hover,.tip:focus-visible{
  border-color:var(--copper);color:var(--amber);
  background:rgba(210,129,58,.15);
  box-shadow:0 0 0 2px rgba(210,129,58,.15);
}
.tip .tip-text{
  position:absolute;bottom:calc(100% + 9px);left:50%;
  transform:translateX(-50%) translateY(3px);
  background:#0b0d10;color:var(--ink);
  border:1px solid var(--copper-d);border-radius:6px;
  padding:9px 12px;
  font-family:"Chakra Petch",sans-serif;font-style:normal;font-weight:400;
  font-size:11.5px;letter-spacing:.15px;line-height:1.5;text-align:left;text-transform:none;
  white-space:normal;
  width:max-content;max-width:230px;
  pointer-events:none;opacity:0;visibility:hidden;display:none;
  transition:opacity .18s, transform .18s, visibility .18s;
  z-index:60;
  box-shadow:0 12px 28px rgba(0,0,0,.6), 0 0 0 1px rgba(242,169,78,.06), 0 0 40px rgba(210,129,58,.18);
}
.tip:hover .tip-text,.tip:focus-visible .tip-text{
  opacity:1;visibility:visible;display:block;transform:translateX(-50%) translateY(0);
}
.tip.tip-right .tip-text{left:-4px;right:auto;transform:translateX(0) translateY(3px)}
.tip.tip-right:hover .tip-text,.tip.tip-right:focus-visible .tip-text{transform:translateX(0) translateY(0)}
/* Tooltips open upward by default, which fails for a tip near the top of a scrolling
   panel: inside .modal-b the bubble is clipped by the scroll container and covers the
   card heading above it. placeTip() measures the room actually available and adds
   .tip-below to flip the bubble under the button. Horizontal variants are untouched. */
.tip.tip-below .tip-text{bottom:auto;top:calc(100% + 9px);transform:translateX(-50%) translateY(-3px)}
.tip.tip-below.tip-right .tip-text{transform:translateX(0) translateY(-3px)}
.tip.tip-below:hover .tip-text,.tip.tip-below:focus-visible .tip-text{transform:translateX(-50%) translateY(0)}
.tip.tip-below.tip-right:hover .tip-text,.tip.tip-below.tip-right:focus-visible .tip-text{transform:translateX(0) translateY(0)}
/* rightmost column header in the lines table: flip its tooltip inward so it can't
   overflow the card edge (previously the last .line-fields column did this) */
@media(min-width:561px){
  .ltable .col-turbo .tip .tip-text{left:auto;right:-4px;transform:translateX(0) translateY(3px)}
  .ltable .col-turbo .tip:hover .tip-text,
  .ltable .col-turbo .tip:focus-visible .tip-text{transform:translateX(0) translateY(0)}
}
/* icon variant: paints the in-game indicator beside the text (left), text wraps to its right */
.tip.tip-ic .tip-text{
  background-image:var(--tip-img);
  background-repeat:no-repeat;
  background-position:left 12px center;
  background-size:54px auto;
  padding-left:78px;
  max-width:250px;
}
/* not enough horizontal room → stack the icon on top, text below */
@media(max-width:560px){
  .tip .tip-text,.tip.tip-right .tip-text{
    position:fixed;left:12px;right:12px;top:12px;bottom:auto;width:auto;max-width:none;
    transform:none
  }
  .tip:hover .tip-text,.tip:focus-visible .tip-text,
  .tip.tip-right:hover .tip-text,.tip.tip-right:focus-visible .tip-text{transform:none}
  .tip.tip-ic .tip-text{
    background-position:top 10px center;
    background-size:auto 46px;
    padding-left:12px;
    padding-top:64px;
    max-width:230px;
  }
}

/* targets */
/* Saved output sets sit above the checkbox list they rewrite. The picker keeps a row of its own:
   it never displays a chosen set, so its prompt is the only label it ever shows and must not be
   clipped in this narrow column. Buttons carry a user-chosen set name, which renderTargetPresetBar
   shortens for the label — the full name stays in the tooltip. */
.tg-presets{display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--line)}
.tg-presets select{flex:1 0 100%;width:100%}
.tg-presets .btn{flex:0 1 auto;max-width:100%;white-space:nowrap}
.tg-presets .btn:disabled{opacity:.45;cursor:not-allowed;border-color:var(--line);color:var(--ink3);
  background:transparent;filter:none;box-shadow:none;transform:none}
.tg{display:flex;flex-direction:column;gap:8px}
.tg-sub{font-size:10px;color:var(--ink3);letter-spacing:.6px;text-transform:uppercase;font-weight:600;
  margin:6px 2px 0;padding-top:8px;border-top:1px solid var(--line)}
.tg-row{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;
  padding:10px 12px;border:1px solid var(--line);border-radius:6px;
  background:linear-gradient(180deg,var(--bg2),var(--surface2));transition:.15s;position:relative;overflow:hidden}
.tg-row.on{border-color:var(--copper);
  background:linear-gradient(180deg,rgba(210,129,58,.08),rgba(210,129,58,.04));
  box-shadow:inset 0 0 0 1px rgba(242,169,78,.08), 0 0 20px rgba(210,129,58,.06)}
.tg-row.on::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:2px;
  background:linear-gradient(180deg,var(--ember),var(--copper));
}
.tg-row label{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13.5px;font-weight:600;letter-spacing:.3px}
.tg-row input[type=checkbox]{appearance:none;width:17px;height:17px;border:1px solid var(--line2);border-radius:4px;
  background:var(--surface2);cursor:pointer;position:relative;flex:0 0 auto;transition:.15s}
.tg-row input[type=checkbox]:checked{background:var(--copper);border-color:var(--copper);
  box-shadow:0 0 8px rgba(242,169,78,.35)}
.tg-row input[type=checkbox]:checked::after{content:"";position:absolute;left:5px;top:1px;width:4px;height:9px;
  border:solid #15110a;border-width:0 2px 2px 0;transform:rotate(45deg)}
.prio{display:flex;align-items:center;gap:8px}
.prio span{font-size:10px;color:var(--ink3);letter-spacing:.6px;text-transform:uppercase;font-weight:600}
.prio input[type=range]{width:84px;accent-color:var(--copper)}
.prio .pv{font-family:"JetBrains Mono",monospace;font-size:12.5px;font-weight:700;color:var(--amber);width:16px;text-align:center;
  text-shadow:0 0 8px rgba(242,169,78,.35)}
/* "100%" needs more room than a single ratio digit. */
.prio .pv.wide{width:34px;text-align:right}
/* The mix-mode switch sits in the card head, where the subtitle used to be. */
.tg-modesw{flex:0 0 auto}
.tg-modesw button{padding-inline:10px}
.tg-modehelp{font-size:10.5px;line-height:1.45;color:var(--ink3);margin-bottom:10px}
/* Measured ceiling under a share slider: a percentage is unreadable without its base. */
.tg-ceiling{grid-column:1/-1;font-family:"JetBrains Mono",monospace;font-size:10.5px;color:var(--ink3);
  margin-top:-2px;letter-spacing:.2px}
/* The output holding the shared floor down — the one worth spending the next line on. */
.metric.binding{border-color:var(--copper)}
.metric .binding-tag{font-size:9.5px;letter-spacing:.5px;text-transform:uppercase;font-weight:700;color:var(--amber)}
.metric .slack-tag{font-size:9.5px;letter-spacing:.4px;text-transform:uppercase;color:var(--ink3)}

/* results */
.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-bottom:14px}
.metric{
  background:linear-gradient(180deg,var(--bg2),var(--surface2));
  border:1px solid var(--line);border-radius:7px;padding:12px 14px;
  position:relative;overflow:hidden;transition:.18s;
}
.metric::before{
  content:"";position:absolute;top:0;left:10px;right:10px;height:1px;
  background:linear-gradient(90deg,transparent,var(--copper),transparent);opacity:.5;
}
.metric:hover{border-color:var(--copper-d);transform:translateY(-1px);
  box-shadow:0 10px 22px rgba(0,0,0,.25), 0 0 26px rgba(210,129,58,.08)}
.metric .l{font-size:10.5px;letter-spacing:.7px;text-transform:uppercase;color:var(--ink3);font-weight:600}
.metric .v{font-family:"JetBrains Mono",monospace;font-size:22px;font-weight:700;color:var(--amber);
  margin-top:4px;text-shadow:0 0 14px rgba(242,169,78,.32)}
.metric .u{font-size:10.5px;color:var(--ink2);margin-top:2px;letter-spacing:.3px}
table{width:100%;border-collapse:collapse;font-size:12.5px}
th,td{text-align:left;padding:7px 9px;border-bottom:1px solid var(--line)}
th{font-size:10.5px;letter-spacing:.5px;text-transform:uppercase;color:var(--ink3);font-weight:600}
td.num,th.num{text-align:right;font-family:"JetBrains Mono",monospace}
tr:last-child td{border-bottom:none}
.pill{display:inline-block;font-size:10.5px;font-weight:600;padding:2px 7px;border-radius:20px;letter-spacing:.3px}
.pill.prod{background:rgba(63,182,160,.14);color:var(--teal);border:1px solid var(--teal-d)}
.pill.craft{background:rgba(210,129,58,.14);color:var(--amber);border:1px solid var(--copper-d)}
.pill.idle{background:rgba(120,128,138,.12);color:var(--ink3);border:1px solid var(--line2)}
.bal-ok{color:var(--teal)} .bal-tight{color:var(--amber)} .bal-bad{color:var(--danger)}
.notice{border-radius:6px;padding:10px 12px;font-size:12.5px;line-height:1.5;margin-bottom:12px}
.notice.warn{background:var(--danger-d);border:1px solid var(--danger);color:#f3c4be}
.notice.info{background:var(--bg2);border:1px solid var(--line2);color:var(--ink2)}
.notice.good{background:var(--teal-d);border:1px solid var(--teal);color:#cdeee6}
.subhead{font-size:11px;letter-spacing:.6px;text-transform:uppercase;color:var(--ink3);margin:16px 0 8px;font-weight:600}

/* recipe data */
.rsec{margin-top:18px}
.rgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}
.rcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r)}
.rcard .rh{padding:9px 12px;border-bottom:1px solid var(--line);background:var(--bg2);
  display:flex;align-items:center;justify-content:space-between;gap:8px}
.rcard .rh .nm{font-size:13.5px;font-weight:600;letter-spacing:.4px}
.rcard .rh .ty{font-size:10px;letter-spacing:.5px;text-transform:uppercase;padding:2px 7px;border-radius:20px}
.rcard .rh .ty.raw{background:rgba(120,128,138,.14);color:var(--ink2);border:1px solid var(--line2)}
.rcard .rh .ty.pr{background:rgba(63,182,160,.13);color:var(--teal);border:1px solid var(--teal-d)}
.rcard .rh .ty.fin{background:rgba(210,129,58,.14);color:var(--amber);border:1px solid var(--copper-d)}
.rcard .rb{padding:8px 10px;max-height:330px;overflow:auto}
.rtab{width:100%;border-collapse:collapse}
.rtab th{font-size:9.5px;padding:4px 5px;color:var(--ink3);text-transform:uppercase;letter-spacing:.4px;position:sticky;top:0;background:var(--surface)}
.rtab td{padding:3px 4px;border:none}
.rtab td.lv{font-family:"JetBrains Mono",monospace;font-size:11.5px;color:var(--ink2);width:40px}
.rtab input{padding:4px 5px;font-size:11.5px;text-align:right}
.rtab input::placeholder{color:var(--ink3);opacity:.5}
.base-time-field>.field-stack{width:122px;max-width:58%;flex:0 0 auto}
.base-time-input{width:100%!important;max-width:100%;text-align:right}
.help{font-size:11.5px;color:var(--ink3);line-height:1.5;margin-bottom:14px}
.calib{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:14px;margin-bottom:16px}
.calib-h{font-family:'Chakra Petch',sans-serif;font-size:13px;letter-spacing:.5px;text-transform:uppercase;color:var(--amber);margin-bottom:8px}
.calib-row{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
@media(max-width:640px){.calib-row{grid-template-columns:repeat(2,1fr)}}
.calib-out{margin-top:10px;font-size:12px;color:var(--ink2);font-family:'JetBrains Mono',monospace;line-height:1.6}
.calib-warning{color:var(--danger)}
footer{margin-top:36px;border-top:1px solid var(--line);padding-top:16px;color:var(--ink3);font-size:11.5px;line-height:1.6}
footer a,.contrib-help a{color:var(--amber)}
footer a:hover,.contrib-help a:hover{text-decoration:underline}
.footer-links{margin-top:8px}
.saveind{font-size:11px;color:var(--ink3);letter-spacing:.3px}
.saveind b{color:var(--teal);font-weight:600}
.hidden-file{display:none}

/* mode switch */
.modesw{display:inline-flex;border:1px solid var(--line2);border-radius:6px;overflow:hidden;
  background:var(--surface2)}
.modesw button{min-height:var(--target);font-family:"Chakra Petch",sans-serif;font-weight:600;font-size:11px;letter-spacing:.5px;
  background:transparent;color:var(--ink2);border:none;padding:7px 12px;cursor:pointer;transition:.15s;
  white-space:nowrap;text-transform:uppercase}
.modesw button+button{border-left:1px solid var(--line2)}
.modesw button:hover{color:var(--amber);background:rgba(210,129,58,.06)}
.modesw button.on{
  background:linear-gradient(180deg,var(--ember),var(--copper));color:#15110a;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18), inset 0 -1px 0 rgba(0,0,0,.15);
}
.card>.head.results-head{display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch}
.result-head-controls{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--space-sm);width:100%;min-width:0}
.mode-nav{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));width:100%;max-width:100%}
.mode-nav button{min-width:0;justify-content:center}
@media(min-width:561px) and (max-width:900px){
  .mode-nav button{padding-inline:3px;letter-spacing:.2px}
}
/* On narrow screens the 4-button row can't fit — wrap it into a full-width 2×2 grid */
@media(max-width:560px){
  .modesw{display:grid;grid-template-columns:1fr 1fr;width:100%}
  .modesw button{padding:9px 8px;white-space:normal}
  /* container is overflow:hidden with a border, so redo separators per-cell */
  .modesw button+button{border-left:none}
  .modesw button:nth-child(even){border-left:1px solid var(--line2)}
  .modesw button:nth-child(n+3){border-top:1px solid var(--line2)}
}

/* modal */
.modal-bg{position:fixed;inset:0;background:rgba(8,9,11,.72);display:flex;align-items:center;justify-content:center;
  padding-top:max(var(--dialog-gutter),env(safe-area-inset-top));
  padding-right:max(var(--dialog-gutter),env(safe-area-inset-right));
  padding-bottom:max(var(--dialog-gutter),env(safe-area-inset-bottom));
  padding-left:max(var(--dialog-gutter),env(safe-area-inset-left));
  z-index:50;overflow:hidden}
.modal-bg[hidden]{display:none}
.dialog-open{overflow:hidden}
.modal{background:var(--surface);border:1px solid var(--line2);border-radius:var(--r);width:100%;max-width:520px;
  box-shadow:0 18px 60px rgba(0,0,0,.55)}
.dialog-shell{display:grid;grid-template-rows:auto minmax(0,1fr) auto;max-height:100%;min-height:0;overflow:hidden}
.modal-h{display:flex;align-items:center;justify-content:space-between;padding:13px 16px;border-bottom:1px solid var(--line);background:var(--bg2);
  position:sticky;top:0;z-index:2}
.modal-h h3{font-size:14px;font-weight:600;letter-spacing:.6px;text-transform:uppercase}
.modal-b{padding:16px;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}
.inputs-modal{max-width:700px}
.inputs-tabs{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));width:100%;margin-bottom:16px;
  border:1px solid var(--line2);border-radius:6px;overflow:hidden;background:var(--surface2)}
.inputs-tabs button{min-width:0;min-height:var(--target);padding:8px 6px;border:0;background:transparent;color:var(--ink2);
  font-family:"Chakra Petch",sans-serif;font-size:10.5px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;cursor:pointer}
.inputs-tabs button+button{border-left:1px solid var(--line2)}
.inputs-tabs button:hover{color:var(--amber);background:rgba(210,129,58,.06)}
.inputs-tabs button[aria-selected="true"]{background:linear-gradient(180deg,var(--ember),var(--copper));color:#15110a;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18),inset 0 -1px 0 rgba(0,0,0,.15)}
.inputs-modal [role="tabpanel"]{min-width:0}
.modal-f [hidden]{display:none}
.settings-section{margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.settings-section-title{margin-bottom:8px;font-size:10.5px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;color:var(--ink3)}
.settings-actions{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.settings-actions .btn{width:100%;justify-content:center}
/* Plan-start anchor — inline in the Project-mode panel (promoted from the old step-by-step modal). */
.plan-anchor{display:flex;align-items:center;flex-wrap:wrap;gap:8px 10px;margin-bottom:12px;padding:8px 12px;border:1px solid var(--line);border-radius:8px;background:var(--bg2)}
.plan-anchor label{font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--ink3);font-weight:600}
/* max-width/min-width: the native datetime control has a fixed intrinsic width (~185px) that pushed
   the page wider than the viewport once the window got narrow enough (200%-zoom reflow territory). */
.plan-anchor input[type=datetime-local]{padding:5px 8px;border:1px solid var(--line);border-radius:6px;background:var(--surface);color:var(--ink);font-size:12px;color-scheme:dark;max-width:100%;min-width:0}
.plan-anchor .btn{padding:4px 12px;font-size:11px}
.plan-anchor .proj-mini{flex:1 1 auto}
/* Line-plan switch (Line switching / Set & forget) reuses the header's .modesw pills. Below 560px
   the controls stack so a narrow screen never has to fit both labels side by side. */
.line-mode{display:flex;align-items:center;flex-wrap:wrap;gap:8px 10px;margin-bottom:12px}
.line-mode-l{font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--ink3);font-weight:600}
.line-mode .modesw button{text-transform:none;letter-spacing:.2px;padding:6px 11px}
@media(max-width:560px){
  .line-mode .modesw{display:grid;grid-template-columns:minmax(0,1fr);width:100%}
  .line-mode .modesw button:nth-child(even){border-left:none}
  .line-mode .modesw button+button{border-top:1px solid var(--line2)}
}
/* Content padding inside a collapsible cat-panel (Adjust projects / Full breakdown). The parent clips
   overflow, so let wide breakdown tables scroll within the panel instead of being cut off. */
.panel-pad{padding:2px 12px 12px;min-width:0}
/* The step-by-step plan is the hero of Project mode; its phase cards carry their own styling. */
.step-main:empty{display:none}
.breakdown-panel{margin-top:4px}
.modal-f{padding:12px 16px max(12px,env(safe-area-inset-bottom));border-top:1px solid var(--line);display:flex;justify-content:flex-end;gap:8px;
  background:var(--bg2);position:sticky;bottom:0;z-index:2;flex-wrap:wrap}
.price-row{display:grid;grid-template-columns:1fr 160px;gap:6px 10px;align-items:center;padding:8px 0;border-bottom:1px solid var(--line)}
.price-row:last-child{border-bottom:none}
.price-row .pnm{font-size:13px;font-weight:600;display:flex;align-items:center;gap:8px}
.price-row>.field-error{grid-column:2;text-align:left}
.price-row .pnm .ty{font-size:9px;letter-spacing:.5px;text-transform:uppercase;padding:2px 6px;border-radius:20px}
.price-row .pnm .ty.raw{background:rgba(120,128,138,.14);color:var(--ink2);border:1px solid var(--line2)}
.price-row .pnm .ty.pr{background:rgba(63,182,160,.13);color:var(--teal);border:1px solid var(--teal-d)}
.price-row .pnm .ty.fin{background:rgba(210,129,58,.14);color:var(--amber);border:1px solid var(--copper-d)}
.price-row .pnm .ty.mined{background:rgba(120,128,138,.14);color:var(--ink2);border:1px solid var(--line2)}
.price-grp{font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--ink3);margin:14px 0 4px;font-weight:600}
.price-grp.first{margin-top:0}

/* collapsible crafting-data panel */
.rsec-toggle{width:100%;display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r);padding:12px 14px;cursor:pointer;color:var(--ink);font-family:"Chakra Petch",sans-serif;text-align:left;transition:.12s}
.rsec-toggle:hover{border-color:var(--copper)}
.rsec-toggle .chev{color:var(--copper);font-size:12px;transition:transform .15s;flex:0 0 auto}
.rsec-toggle[aria-expanded="true"] .chev{transform:rotate(90deg)}
.rsec-toggle .rsec-title{font-size:13px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}
.rsec-toggle .rsec-hint{margin-left:auto;font-size:11px;color:var(--ink3);text-align:right}
@media(max-width:620px){.rsec-toggle .rsec-hint{display:none}}
/* mined-resource setup */
.mined-modal{max-width:1180px}
.mined-intro{margin-bottom:14px}
.mined-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:start}
.mined-card{min-width:0;overflow:hidden;border:1px solid var(--line);border-radius:8px;
  background:linear-gradient(180deg,var(--bg2),var(--surface2));padding:14px}
.mined-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:13px}
.mined-card-head h4{font-size:14px;letter-spacing:.5px;color:var(--ink);margin-bottom:3px}
.mined-card-head p{font-size:10.5px;line-height:1.4;color:var(--ink3)}
.mined-badge{flex:0 0 auto;border:1px solid var(--copper-d);border-radius:20px;padding:3px 8px;
  background:rgba(210,129,58,.12);color:var(--amber);font-size:9.5px;font-weight:600;letter-spacing:.45px;text-transform:uppercase}
.mined-income-stack{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;align-items:start}
.mined-income{display:flex;flex-direction:column;gap:4px;min-width:0}
/* A label carrying a help button is 24px tall and a bare one is 13px, which pushed
   the inputs beside it — and everything below them — out of line by 11px, both
   within a card and across the two cards. Reserve the button's height for every
   label so the fields align whether or not they have help. */
.mined-income>span,.mined-income>label{font-size:10px;letter-spacing:.45px;text-transform:uppercase;
  color:var(--ink3);display:flex;align-items:center;gap:4px;min-height:24px;line-height:1.2}
/* these were the only text inputs in the app left at the browser default height */
.mined-income input{width:100%;min-width:0;min-height:var(--target)}
.mined-breakdown{margin-top:9px;color:var(--ink2);font-family:"JetBrains Mono",monospace;font-size:10.5px;line-height:1.5}
.mined-capacity{margin-top:9px;color:var(--amber);font-family:"JetBrains Mono",monospace;font-size:12px;font-weight:600}
.mined-help{margin:10px 0 0}
.mined-summary{font-size:11.5px;margin:10px 0 0}
.mined-table-title{margin:15px 0 7px;color:var(--ink3);font-size:10px;letter-spacing:.55px;text-transform:uppercase}
.mined-table-wrap{width:100%;max-width:100%;overflow-x:auto;overscroll-behavior-inline:contain;
  scrollbar-color:var(--copper-d) var(--bg2);border:1px solid var(--line);border-radius:6px;background:var(--surface)}
.mined-table-wrap table{min-width:650px}
.mined-table-wrap th,.mined-table-wrap td{white-space:nowrap;padding:6px 8px}
.mined-line-dependent{color:var(--ink2)}
@media(max-width:820px){.mined-grid{grid-template-columns:minmax(0,1fr)}}
@media(max-width:560px){
  .modal-bg{--dialog-gutter:8px}
  .mined-modal .modal-b{padding:10px}
  .mined-card{padding:11px}
  .mined-card-head{flex-wrap:wrap}
  .mined-income-stack{grid-template-columns:minmax(0,1fr)}
  .mined-table-wrap table{min-width:620px}
}
/* projects / shopping-list modal */
.proj{border:1px solid var(--line);border-radius:7px;background:linear-gradient(180deg,var(--bg2),var(--surface2));margin-bottom:10px;overflow:hidden}
.proj-h{display:grid;grid-template-columns:var(--compact-target) 24px 1fr auto;gap:9px;align-items:center;padding:9px 11px}
.proj.open .proj-h{border-bottom:1px solid var(--line)}
.proj-h input[type=checkbox]{appearance:none;width:17px;height:17px;border:1px solid var(--line2);border-radius:4px;background:var(--surface2);cursor:pointer;position:relative;flex:0 0 auto}
.proj-h input[type=checkbox]:checked{background:var(--copper);border-color:var(--copper)}
.proj-h input[type=checkbox]:checked::after{content:"";position:absolute;left:5px;top:1px;width:4px;height:9px;border:solid #15110a;border-width:0 2px 2px 0;transform:rotate(45deg)}
.proj-h .pname{font-size:13.5px;font-weight:600;background:transparent;color:var(--ink);border:1px solid transparent;border-radius:4px;padding:4px 6px;width:100%;font-family:"Chakra Petch",sans-serif}
.proj-h .pname:hover,.proj-h .pname:focus{border-color:var(--line2);background:var(--surface2)}
.pchev{display:inline-flex;align-items:center;justify-content:center;width:var(--compact-target);height:var(--compact-target);
  padding:0;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--copper);font-size:11px;transition:transform .15s;cursor:pointer;user-select:none}
.pchev:hover{border-color:var(--copper)}
.proj.open .pchev{transform:rotate(90deg)}
.proj-tools{display:flex;gap:8px;align-items:center;flex-wrap:wrap;justify-content:flex-end}
.proj-field-errors{display:flex;flex:1 0 100%;max-width:100%;min-width:0;flex-direction:column;gap:3px}
.proj-lvls{display:flex;align-items:center;gap:5px;font-size:10.5px;color:var(--ink3);text-transform:uppercase;letter-spacing:.4px}
.proj-lvls input{width:50px;text-align:center;padding:4px 5px}
.proj-b{padding:9px 11px;display:none}
.proj.open .proj-b{display:block}
.lvl-card{border:1px solid var(--line);border-radius:6px;padding:8px 9px;margin-bottom:7px;background:var(--surface)}
.lvl-h{display:flex;align-items:center;justify-content:space-between;font-size:10px;letter-spacing:.6px;text-transform:uppercase;color:var(--ink3);margin-bottom:6px;font-weight:600}
.lvl-h .lvl-del{min-height:var(--compact-target);padding:2px 5px;border:0;background:transparent;font:inherit;text-transform:inherit;cursor:pointer;color:var(--ink3)}
.lvl-h .lvl-del:hover{color:var(--danger)}
.cost-row{display:grid;grid-template-columns:1fr 130px 26px;gap:6px;align-items:center;margin-bottom:5px}
.cost-row:last-child{margin-bottom:0}
.cost-row select,.cost-row input{padding:5px 7px;font-size:11.5px;height:30px}
.cost-row .cost-qty{align-self:start}
.rtab .field-stack{min-width:82px}
.proj-inline-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:6px 0;border-top:1px solid var(--line);min-width:0;max-width:100%}
.proj-inline-range{display:flex;align-items:center;gap:4px;white-space:nowrap;min-width:0}
.proj-inline-range input{width:46px;max-width:46px}
/* "Mark complete" and "Reopen" are the same button under two labels, and the row is a flex line: let
   it size to its text and checking off the last level drags the stepper sideways, right as the
   reader is still pressing it. Hold the wider label's width for both. */
.proj-inline-row [data-spcomplete]{min-width:11.5em;text-align:center}
.proj-inline-errors{display:flex;flex:1 0 100%;max-width:100%;min-width:0;flex-direction:column;gap:3px}
.proj-mini{font-size:10.5px;color:var(--ink3);letter-spacing:.3px}
.proj-add-lvl{font-size:10.5px;padding:5px 9px}
.seq-toggle{display:flex;gap:8px;align-items:flex-start;margin-bottom:14px;cursor:pointer;font-size:11.5px;color:var(--ink2);line-height:1.45}
.seq-toggle.disabled{opacity:.45;cursor:default}
.seq-toggle.disabled input{cursor:default}
.seq-toggle input,.proj-first .pfirst{appearance:none;width:16px;height:16px;border:1px solid var(--line2);border-radius:4px;background:var(--surface2);cursor:pointer;position:relative;flex:0 0 auto;margin-top:1px}
.seq-toggle input:checked,.proj-first .pfirst:checked{background:var(--copper);border-color:var(--copper)}
.seq-toggle input:checked::after,.proj-first .pfirst:checked::after{content:"";position:absolute;left:5px;top:1px;width:4px;height:9px;border:solid #15110a;border-width:0 2px 2px 0;transform:rotate(45deg)}
.proj-first{display:flex;align-items:center;gap:4px;cursor:pointer;font-size:10px;letter-spacing:.4px;text-transform:uppercase;color:var(--ink3)}
.proj-first .pfirst{width:15px;height:15px;margin-top:0}
.proj-prio{display:flex;align-items:center;gap:4px;font-size:10px;letter-spacing:.4px;text-transform:uppercase;color:var(--ink3)}
.proj-prio input{width:36px;text-align:center;padding:4px 5px}
/* Order is only consulted when projects run one at a time — dimmed (and the input disabled) when
   that toggle is off, so it reads as "not applicable" rather than "typed a number, nothing happened".
   Mirrors the .seq-toggle.disabled treatment on the unlock-gating checkbox. */
.proj-prio.disabled{opacity:.45}
.proj-prio.disabled input{cursor:default}
/* project catalog picker */
.cat-panel{border:1px solid var(--line);border-radius:7px;background:var(--bg2);margin-bottom:14px;overflow:hidden}
.cat-panel>summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 12px;font-size:12.5px;font-weight:600;color:var(--ink);user-select:none}
.cat-panel>summary::-webkit-details-marker{display:none}
.cat-panel>summary::before{content:"▸";color:var(--copper);font-size:11px;transition:transform .15s}
.cat-panel[open]>summary::before{transform:rotate(90deg)}
.cat-sum-lbl{flex:1}
.cat-sum-meta{font-size:10.5px;color:var(--ink3);text-transform:uppercase;letter-spacing:.4px;font-weight:600}
.cat-search{width:100%;margin:0 0 4px;padding:7px 10px;background:var(--surface2);border:1px solid var(--line);border-top:1px solid var(--line);border-radius:0;color:var(--ink);font-size:12.5px}
.cat-search:focus{border-color:var(--copper)}
.cat-list{max-height:230px;overflow-y:auto;padding:4px 10px 10px}
.cat-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line)}
.cat-row:last-child{border-bottom:none}
.cat-row.added{opacity:.55}
.cat-row-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.cat-row-name{font-size:13px;font-weight:600;color:var(--ink)}
.cat-row-meta{font-size:10.5px;color:var(--ink3);letter-spacing:.3px}
.cat-add{flex:0 0 auto;font-size:11px;padding:5px 14px}
/* compact (catalog-sourced) project card */
.cat-card .pname-static{display:flex;flex-direction:column;gap:1px;font-size:13.5px;font-weight:600;color:var(--ink);padding:4px 2px;min-width:0}
.cat-card .cat-card-desc{font-size:10px;font-weight:500;color:var(--ink3);letter-spacing:.3px;text-transform:none}
.proj-lvls.one{color:var(--ink3)}
.cat-lvls{display:flex;flex-direction:column;gap:5px}
.cat-lvl{display:grid;grid-template-columns:46px 1fr;gap:8px;font-size:11.5px;color:var(--ink2);line-height:1.4}
.cat-lvl-n{color:var(--ink3);text-transform:uppercase;letter-spacing:.4px;font-size:10px;padding-top:1px}
.cat-lvl b{color:var(--ink);font-weight:600}
/* progress tracker */
.prog-summary{margin-bottom:14px}
.prog-bar-wrap{height:9px;border-radius:5px;background:var(--surface2);border:1px solid var(--line);overflow:hidden}
.prog-bar{height:100%;background:linear-gradient(90deg,var(--copper),var(--amber));border-radius:5px;transition:width .2s}
.prog-metrics{display:flex;gap:10px;margin-top:10px}
.prog-metric{flex:1;background:var(--bg2);border:1px solid var(--line);border-radius:7px;padding:8px 10px;text-align:center}
.pm-v{font-size:16px;font-weight:700;color:var(--ink);font-family:"JetBrains Mono",monospace}
.pm-l{font-size:10px;color:var(--ink3);text-transform:uppercase;letter-spacing:.4px;margin-top:2px}
.prog-proj{border:1px solid var(--line);border-radius:7px;background:linear-gradient(180deg,var(--bg2),var(--surface2));margin-bottom:10px;padding:10px 12px}
.prog-proj.complete{opacity:.62}
.prog-proj-h{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px}
.prog-proj-name{font-size:13.5px;font-weight:600;color:var(--ink);display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.prog-desc{font-size:10px;font-weight:500;color:var(--ink3)}
.prog-proj-meta{display:flex;align-items:center;gap:9px;flex:0 0 auto;color:var(--ink3);font-size:11px}
.prog-reset{background:none;border:none;color:var(--ink3);font-size:10.5px;cursor:pointer;text-decoration:underline;padding:0}
.prog-reset:hover{color:var(--amber)}
.prog-lvls{display:flex;flex-wrap:wrap;gap:6px}
.prog-lvl{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-family:"JetBrains Mono",monospace;color:var(--ink2);background:var(--surface2);border:1px solid var(--line2);border-radius:6px;padding:5px 9px;cursor:pointer;transition:all .12s}
.prog-lvl:hover{border-color:var(--copper);color:var(--ink)}
.prog-lvl .pl-box{width:13px;height:13px;border:1px solid var(--line2);border-radius:3px;background:var(--bg);position:relative;flex:0 0 auto}
.prog-lvl.next{border-color:var(--copper-d)}
.prog-lvl.next .pl-box{border-color:var(--copper)}
.prog-lvl.done{color:var(--ink);border-color:var(--copper-d);background:rgba(210,129,58,.12)}
.prog-lvl.done .pl-box{background:var(--copper);border-color:var(--copper)}
.prog-lvl.done .pl-box::after{content:"";position:absolute;left:4px;top:1px;width:3px;height:7px;border:solid #15110a;border-width:0 2px 2px 0;transform:rotate(45deg)}
/* step-by-step modal */
.step-phase{border:1px solid var(--line);border-radius:7px;padding:10px 12px;margin-bottom:10px;background:linear-gradient(180deg,var(--bg2),var(--surface2))}
.step-h{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13.5px;margin-bottom:6px}
.step-n{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:var(--copper);color:#15110a;font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:700;flex:0 0 auto}
.step-list{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:6px}
.step-list li{font-size:12.5px;line-height:1.5;color:var(--ink)}
.step-clock{font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;color:var(--amber);white-space:nowrap}
.step-seg{padding-left:16px;margin-top:3px;text-indent:-12px}
.step-seg:first-of-type{margin-top:4px}
.step-then{color:var(--ink3);font-style:italic}

/* ---- async-solve spinner overlay ---- */
.results-wrap{position:relative}
.solve-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:11px;
  background:rgba(14,16,20,.60);backdrop-filter:blur(1.5px);-webkit-backdrop-filter:blur(1.5px);
  border-radius:var(--r);z-index:6}
.solve-overlay[hidden]{display:none}   /* override the class display:flex when hidden */
.solve-overlay-txt{font-family:"Chakra Petch",sans-serif;font-size:13px;font-weight:600;
  color:var(--ink2);letter-spacing:.3px}
.spinner{width:22px;height:22px;border:3px solid var(--line2);border-top-color:var(--amber);
  border-radius:50%;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* Named keyboard-operable ownership for every horizontally wide table. */
.table-scroll{width:100%;max-width:100%;overflow-x:auto;overscroll-behavior-inline:contain;
  scrollbar-color:var(--amber) var(--bg2);border-radius:6px}
.table-scroll:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.table-scroll-hint{position:sticky;left:0;width:max-content;max-width:100%;margin:0 0 5px;padding:3px 7px;
  border:1px solid var(--line2);border-radius:4px;background:var(--bg2);color:var(--ink3);font-size:10.5px;font-weight:600}
.table-scroll-help{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* Project controls need two rows before the rest of the page reaches its phone breakpoint. The
   one-row tools track otherwise collapses catalog and custom project names below roughly 721px. */
@media(max-width:720px){
  .proj-h{
    grid-template-columns:var(--compact-target) 24px minmax(140px,1fr);
    grid-template-areas:"chevron include identity" "tools tools tools";
    align-items:center
  }
  .proj-h>.pchev{grid-area:chevron}
  .proj-h>input[type=checkbox]{grid-area:include}
  .proj-h>.pname,.proj-h>.pname-static{grid-area:identity;min-width:140px}
  .proj-h>.proj-tools{grid-area:tools;width:100%;justify-content:flex-start;padding-top:var(--space-sm);border-top:1px solid var(--line)}
}
/* P1 mobile geometry overrides live after their desktop declarations so the narrow cascade wins. */
@media(max-width:560px){
  .brand h1{font-size:34px;letter-spacing:1.2px}
  .settings-actions{grid-template-columns:minmax(0,1fr)}
  button.btn{padding:8px 10px;font-size:11.5px}
  /* rail goes full width as an even three-up band, labels centred over their state.
     Segments only divide evenly if the labels shrink too — the full names would
     force "Projects + Prices" wider than a third and squeeze the other two. The
     accessible name comes from each button's aria-label, so swapping the visible
     text here costs nothing to screen readers. */
  .tools{width:100%}
  .rail{flex:1 0 100%;order:1}
  .rail-seg{flex:1 1 0;min-width:0;align-items:center;text-align:center;padding:8px 6px}
  .rail-lbl{gap:5px;font-size:10.5px;letter-spacing:.4px;max-width:100%}
  .rail-name{font-size:0}
  .rail-name::after{content:attr(data-short);font-size:10.5px}
  .rail-state{padding-left:0;font-size:0;overflow:hidden;text-overflow:ellipsis;max-width:100%}
  .rail-state::after{content:attr(data-short);font-size:9.5px}
  .rail-seg.needs .rail-state::after{color:var(--amber);font-weight:500}
  .tools .saveind{flex:1 1 auto;order:2;margin:0;text-align:left;align-self:center}
  .tools button.btn.rail-aside{order:3;margin-left:auto;align-self:center}
}
@media(max-width:430px){
  .price-row{grid-template-columns:minmax(0,1fr);gap:var(--space-sm)}
  .price-row>.field-error{grid-column:1;text-align:left}
  .cost-row{grid-template-columns:minmax(0,1fr) minmax(88px,120px) 26px}
}
@media(max-width:360px){
  .tg-row{grid-template-columns:minmax(0,1fr) auto;gap:6px;padding-inline:10px}
  .tg-row:not(.on) .prio{display:none}
  .tg-row .prio{gap:4px}
  .tg-row .prio input[type=range]{width:70px}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{scroll-behavior:auto!important;animation:none!important;transition-duration:.01ms!important;transition-delay:0ms!important}
}
@media (forced-colors:active){
  .skip-link,.btn,.iconbtn,.tip,.pchev,input,select,.card,.proj,.table-scroll{forced-color-adjust:auto}
  .btn,.iconbtn,.tip,.pchev,input,select,.card,.proj,.table-scroll{border-style:solid}
  :focus-visible{outline:3px solid Highlight!important}
  .modesw button[aria-pressed="true"],.inputs-tabs button[aria-selected="true"]{border:2px solid Highlight;color:ButtonText;background:ButtonFace}
  .spinner{border-color:CanvasText;border-top-color:Highlight}
}
@media(max-width:260px){
  .wrap{padding:12px 8px 40px}
  .brand h1{font-size:25px;letter-spacing:.8px}
  .rail{flex-direction:column}
  .rail-seg+.rail-seg{border-left:0;border-top:1px solid var(--line2)}
  .tools button.btn.rail-aside{width:100%;justify-content:center}
  .card>.head{align-items:stretch;flex-direction:column}
  .globals{grid-template-columns:minmax(0,1fr)}
  /* below 260px even the two-up card is too wide: stack every field */
  .ltable tr{grid-template-columns:30px minmax(0,1fr) 28px;
    grid-template-areas:"tag cap x" "tag spx x" "tag turbo x";
    gap:6px;padding-left:5px;padding-right:5px}
  .margin-row{align-items:stretch!important;flex-direction:column}
  .margin-row>div:last-child{justify-content:space-between}
  .modesw{grid-template-columns:minmax(0,1fr)}
  .modesw button:nth-child(even){border-left:0}
  .modesw button:nth-child(n+2){border-top:1px solid var(--line2)}
}

/* ---------- release notes ---------- */
.linkbtn{background:none;border:0;padding:0;font:inherit;color:var(--accent,#f0a020);cursor:pointer;text-decoration:underline}
.changelog{display:flex;flex-direction:column;gap:18px}
.cl-release{border-top:1px solid rgba(255,255,255,.12);padding-top:12px}
.cl-release:first-child{border-top:0;padding-top:0}
.cl-version{display:flex;align-items:baseline;gap:10px;margin:0 0 6px;font-size:1.05rem}
.cl-date{font-weight:400;opacity:.65;font-size:.85rem}
.cl-new{font-size:.72rem;text-transform:uppercase;letter-spacing:.06em;padding:2px 7px;border-radius:999px;background:var(--accent,#f0a020);color:#1a1206}
.cl-group{margin:10px 0 4px;font-size:.8rem;text-transform:uppercase;letter-spacing:.06em;opacity:.75}
.cl-list{margin:0;padding-left:20px}
.cl-list li{margin:3px 0}
